diff --git a/src/main/java/com/intellij/plugins/haxe/ide/completion/HaxeCompletionPriorityUtil.java b/src/main/java/com/intellij/plugins/haxe/ide/completion/HaxeCompletionPriorityUtil.java index 9a9106942..9c08d362c 100644 --- a/src/main/java/com/intellij/plugins/haxe/ide/completion/HaxeCompletionPriorityUtil.java +++ b/src/main/java/com/intellij/plugins/haxe/ide/completion/HaxeCompletionPriorityUtil.java @@ -59,7 +59,6 @@ private static boolean trySortForAssign(PsiElement position, List members = HaxeHierarchyUtils.findMembersByWalkingTree(position); for (HaxeComponentName name : members) { - if (name.getParent() instanceof HaxeModelTarget modelTarget) { - LookupElementBuilder builder = HaxeLookupElementFactory.create(modelTarget.getModel(), "$" + name.getText(), false); - if (builder!= null) result.addElement(builder); - }else if (name.getParent() instanceof HaxeNamedComponent namedComponent){ - LookupElementBuilder builder = HaxeLookupElementFactory.create(namedComponent, "$" + name.getText()); - result.addElement(builder); + // ignoring type definitions and method/function definitions + HaxeBaseMemberModel model = HaxeBaseMemberModel.fromPsi(name); + if (model != null && !(model instanceof HaxeMethodModel)) { + HaxeMacroLookupElement lookupElement = HaxeMacroLookupElement.create(name, new HaxeGenericResolver()); + result.addElement(lookupElement.toPrioritized()); } } } @@ -83,7 +84,9 @@ private static void addReificationsAndMacroFunctions(CompletionResultSet result) public static void addReificationSuggestions(List result, Set macroCompletionData) { for (MacroCompletionData completionData : macroCompletionData) { - result.add(reificationLookupElement(completionData)); + LookupElement lookupElement = reificationLookupElement(completionData); + LookupElement withPriorityZero = PrioritizedLookupElement.withPriority(lookupElement, 0); + result.add(withPriorityZero); } } } diff --git a/src/main/java/com/intellij/plugins/haxe/ide/lookup/HaxeMacroLookupElement.java b/src/main/java/com/intellij/plugins/haxe/ide/lookup/HaxeMacroLookupElement.java new file mode 100644 index 000000000..5baea04a4 --- /dev/null +++ b/src/main/java/com/intellij/plugins/haxe/ide/lookup/HaxeMacroLookupElement.java @@ -0,0 +1,184 @@ +package com.intellij.plugins.haxe.ide.lookup; + +import com.intellij.codeInsight.completion.InsertionContext; +import com.intellij.codeInsight.completion.JavaCompletionUtil; +import com.intellij.codeInsight.completion.PrioritizedLookupElement; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementPresentation; +import com.intellij.navigation.ItemPresentation; +import com.intellij.plugins.haxe.lang.psi.*; +import com.intellij.plugins.haxe.model.*; +import com.intellij.plugins.haxe.model.type.*; +import icons.HaxeIcons; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +public class HaxeMacroLookupElement extends LookupElement implements HaxeLookupElement { + @Getter private final HaxeCompletionPriorityData priority = new HaxeCompletionPriorityData(); + private final HaxeComponentName myComponentName; + + private final HaxeGenericResolver resolver; + @Getter private final boolean isFunctionType; + @Getter private HaxeBaseMemberModel model; + + private String presentableText; + private String tailText; + private String typeText; + private boolean strikeout = false; + private boolean bold = false; + private Icon icon = null; + + @NotNull + public static HaxeMacroLookupElement create(@NotNull HaxeComponentName componentName, HaxeGenericResolver resolver) { + HaxeBaseMemberModel model = HaxeBaseMemberModel.fromPsi(componentName); + if (model instanceof HaxeMethodModel) { + return new HaxeMacroLookupElement(componentName, resolver, model, true); + } + return new HaxeMacroLookupElement(componentName, resolver, model); + } + + + public HaxeMacroLookupElement(HaxeComponentName name, HaxeGenericResolver resolver, HaxeBaseMemberModel model) { + this(name, resolver, model, false); + } + public HaxeMacroLookupElement(HaxeComponentName name, HaxeGenericResolver resolver, HaxeBaseMemberModel model, boolean functionType) { + this.myComponentName = name; + this.resolver = resolver; + this.model = model; + this.isFunctionType = functionType; + calculatePresentation(); + } + + @NotNull + @Override + public String getLookupString() { + return "$" +myComponentName.getIdentifier().getText(); + } + + @Override + public void renderElement(LookupElementPresentation presentation) { + presentation.setItemText(presentableText); + presentation.setStrikeout(strikeout); + presentation.setItemTextBold(bold); + presentation.setIcon(icon); + presentation.setTypeText(typeText); + + if (tailText != null) presentation.setTailText(tailText, true); + + } + + public void calculatePresentation() { + presentableText = getLookupString(); + + if (!isFunctionType) { + final ItemPresentation myComponentNamePresentation = myComponentName.getPresentation(); + if (myComponentNamePresentation == null) return; + icon = myComponentNamePresentation.getIcon(true); + } else { + // TODO functionType references should perhaps have its own icon? + icon = HaxeIcons.Field; + } + if (model != null) { + determineStriketrough(); + evaluateTypeTextAndPriorityBoost(); + } + } + + private void evaluateTypeTextAndPriorityBoost() { + ResultHolder typeHolder = model.getResultType(resolver); + + if (isFunctionType && model instanceof HaxeMethodModel methodModel) { + SpecificFunctionReference functionType = methodModel.getFunctionType(resolver); + typeText = functionType.toPresentationString(); + return; + } + if (typeHolder != null && !typeHolder.isUnknown()) { + typeText = typeHolder.toPresentationString(); + + SpecificTypeReference type = typeHolder.tryUnwrapNullType().getType(); + if(type.isExpr() || type.isExprOf()) { + priority.assignable = 2; + } + else { + String qualifiedName = tryFindQualifiedName(type); + if(qualifiedName.startsWith("haxe.macro")) { + priority.assignable = 2; + } + } + + } + } + + private static @NotNull String tryFindQualifiedName(SpecificTypeReference type) { + if (type instanceof SpecificEnumValueReference valueReference) { + HaxeClass enumParentClass = valueReference.getEnumClass().getHaxeClass(); + if (enumParentClass != null) { + return enumParentClass.getQualifiedName(); + } + } + if (type instanceof SpecificHaxeClassReference classReference) { + HaxeClass haxeClass = classReference.getHaxeClass(); + if(haxeClass != null) { + return haxeClass.getQualifiedName(); + } + } + return ""; + } + + + private void determineStriketrough() { + if (model instanceof HaxeMemberModel && ((HaxeMemberModel)model).getModifiers().hasModifier(HaxePsiModifier.DEPRECATED)) { + strikeout = true; + } + } + + @Override + public void handleInsert(@NotNull InsertionContext context) { + HaxeBaseMemberModel memberModel = HaxeBaseMemberModel.fromPsi(myComponentName); + boolean hasParams = false; + boolean isMethod = false; + if (memberModel != null) { + if (memberModel instanceof HaxeMethodModel methodModel) { + hasParams = !methodModel.getParametersWithContext(null).isEmpty(); + isMethod = true; + } + } + + if (isMethod && !isFunctionType) { + final LookupElement[] allItems = context.getElements(); + final boolean overloadsMatter = allItems.length == 1 && getUserData(JavaCompletionUtil.FORCE_SHOW_SIGNATURE_ATTR) == null; + JavaCompletionUtil.insertParentheses(context, this, overloadsMatter, hasParams); + } + } + + @Override + public PrioritizedLookupElement toPrioritized() { + return (PrioritizedLookupElement)PrioritizedLookupElement.withPriority(this, priority.calculate()); + } + + + + @NotNull + @Override + public Object getObject() { + return myComponentName; + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof HaxeMacroLookupElement lookupElement) { + return myComponentName.equals(lookupElement.myComponentName) && lookupElement.isFunctionType == isFunctionType; + }else { + return false; + } + } + + @Override + public int hashCode() { + return myComponentName.hashCode(); + } +}