Skip to content

Commit

Permalink
better macro completion item rendering & prioritization
Browse files Browse the repository at this point in the history
  • Loading branch information
m0rkeulv committed Aug 26, 2024
1 parent db1f12a commit 6dc3153
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ private static boolean trySortForAssign(PsiElement position, List<HaxeLookupElem
if(reference != null && reference.getParent() instanceof HaxeAssignExpression assignExpression) {
HaxeExpression assignTo = assignExpression.getExpressionList().get(0);
assignToType = HaxeExpressionEvaluator.evaluate(assignTo, null).result;

}
if(reference != null && reference.getParent() instanceof HaxeVarInit init) {
PsiElement parent = init.getParent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.plugins.haxe.ide.hierarchy.HaxeHierarchyUtils;
import com.intellij.plugins.haxe.ide.lookup.HaxeMacroLookupElement;
import com.intellij.plugins.haxe.lang.psi.HaxeComponentName;
import com.intellij.plugins.haxe.lang.psi.HaxeNamedComponent;
import com.intellij.plugins.haxe.model.HaxeModelTarget;
import com.intellij.plugins.haxe.model.HaxeBaseMemberModel;
import com.intellij.plugins.haxe.model.HaxeMethodModel;
import com.intellij.plugins.haxe.model.type.HaxeGenericResolver;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.ProcessingContext;
Expand Down Expand Up @@ -63,14 +64,14 @@ private void reificationAndMacroIds(CompletionResultSet result, PsiElement posit
}

private static void addMacroIdentifiers(CompletionResultSet result, PsiElement position) {
//TODO we need to add enum extractor values in some way.
List<HaxeComponentName> 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());
}
}
}
Expand All @@ -83,7 +84,9 @@ private static void addReificationsAndMacroFunctions(CompletionResultSet result)

public static void addReificationSuggestions(List<LookupElement> result, Set<MacroCompletionData> macroCompletionData) {
for (MacroCompletionData completionData : macroCompletionData) {
result.add(reificationLookupElement(completionData));
LookupElement lookupElement = reificationLookupElement(completionData);
LookupElement withPriorityZero = PrioritizedLookupElement.withPriority(lookupElement, 0);
result.add(withPriorityZero);
}
}
}
Original file line number Diff line number Diff line change
@@ -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<LookupElement> toPrioritized() {
return (PrioritizedLookupElement<LookupElement>)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();
}
}

0 comments on commit 6dc3153

Please sign in to comment.