package org.elixir_lang.psi.scope.call_definition_clause;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.ResolveState;
import com.intellij.psi.util.PsiTreeUtil;
import gnu.trove.THashMap;
import org.elixir_lang.annonator.Parameter;
import org.elixir_lang.psi.call.Call;
import org.elixir_lang.psi.call.Named;
import org.elixir_lang.psi.scope.CallDefinitionClause;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static org.elixir_lang.psi.impl.ElixirPsiImplUtil.ENTRANCE;
public class Variants extends CallDefinitionClause {
/*
* CONSTANTS
*/
private static final Key<Call> ENTRANCE_CALL_DEFINITION_CLAUSE = new Key<Call>("ENTRANCE_CALL_DEFINITION_CLAUSE");
/*
* Static Methods
*/
@Nullable
public static List<LookupElement> lookupElementList(@NotNull PsiElement entrance) {
Variants variants = new Variants();
Parameter parameter = Parameter.putParameterized(new Parameter(entrance));
Call entranceCallDefinitionClause = null;
if (parameter.isCallDefinitionClauseName()) {
entranceCallDefinitionClause = (Call) parameter.parameterized;
}
ResolveState resolveState = ResolveState
.initial()
.put(ENTRANCE, entrance)
.put(ENTRANCE_CALL_DEFINITION_CLAUSE, entranceCallDefinitionClause);
PsiTreeUtil.treeWalkUp(
variants,
entrance,
entrance.getContainingFile(),
resolveState
);
List<LookupElement> lookupElementList = new ArrayList<LookupElement>();
lookupElementList.addAll(variants.getLookupElementCollection());
return lookupElementList;
}
/*
* Fields
*/
@Nullable
private Map<PsiElement, LookupElement> lookupElementByPsiElement = null;
/*
* Protected Instance Methods
*/
/**
* Called on every {@link Call} where {@link org.elixir_lang.structure_view.element.CallDefinitionClause#is} is
* {@code true} when checking tree with {@link #execute(Call, ResolveState)}
*
* @return {@code true} to keep searching up tree; {@code false} to stop searching.
*/
@Override
protected boolean executeOnCallDefinitionClause(Call element, ResolveState state) {
Call entranceCallDefinitionClause = state.get(ENTRANCE_CALL_DEFINITION_CLAUSE);
if (entranceCallDefinitionClause == null || !element.isEquivalentTo(entranceCallDefinitionClause)) {
addToLookupElementByPsiElement(element);
}
return true;
}
/**
* Whether to continue searching after each Module's children have been searched.
*
* @return {@code true} to keep searching up the PSI tree; {@code false} to stop searching.
*/
@Override
protected boolean keepProcessing() {
return false;
}
/*
* Private Instance Methods
*/
private void addToLookupElementByPsiElement(@NotNull Call call) {
if (call instanceof Named) {
Named named = (Named) call;
PsiElement nameIdentifier = named.getNameIdentifier();
if (nameIdentifier != null) {
if (lookupElementByPsiElement == null || !lookupElementByPsiElement.containsKey(nameIdentifier)) {
if (lookupElementByPsiElement == null) {
lookupElementByPsiElement = new THashMap<PsiElement, LookupElement>();
}
String name = nameIdentifier.getText();
lookupElementByPsiElement.put(
nameIdentifier,
LookupElementBuilder.createWithSmartPointer(
name,
nameIdentifier
).withRenderer(
new org.elixir_lang.code_insight.lookup.element_renderer.CallDefinitionClause(name)
)
);
}
}
}
}
@NotNull
private Collection<LookupElement> getLookupElementCollection() {
Collection<LookupElement> lookupElementCollection;
if (lookupElementByPsiElement != null) {
lookupElementCollection = lookupElementByPsiElement.values();
} else {
lookupElementCollection = Collections.emptySet();
}
return lookupElementCollection;
}
}