package org.elixir_lang.code_insight.lookup.element_renderer;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.ui.JBColor;
import org.elixir_lang.ElixirSyntaxHighlighter;
import org.elixir_lang.annonator.Parameter;
import org.elixir_lang.icons.ElixirIcons;
import org.elixir_lang.psi.operation.InMatch;
import org.elixir_lang.psi.operation.Match;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import static org.elixir_lang.reference.Callable.isIgnored;
import static org.elixir_lang.reference.Callable.isParameterWithDefault;
import static org.elixir_lang.reference.Callable.isVariable;
public class Variable extends com.intellij.codeInsight.lookup.LookupElementRenderer<LookupElement> {
/*
* Fields
*/
@NotNull
private final String name;
/*
* Constructors
*/
public Variable(@NotNull String name) {
this.name = name;
}
/*
* Public Instance Methods
*/
@Override
public void renderElement(LookupElement element, LookupElementPresentation presentation) {
presentation.setItemText(name);
presentation.setItemTextBold(true);
PsiElement psiElement = element.getPsiElement();
assert psiElement != null;
presentation.setIcon(icon(psiElement));
presentation.setItemTextForeground(color(psiElement));
/* Add a space between variable name and match.
See https://github.com/KronicDeth/intellij-elixir/issues/506 */
presentation.appendTailText(" ", false);
TextRange psiElementTextRange = psiElement.getTextRange();
PsiElement enclosingMatch = enclosingMatch(psiElement);
TextRange enclosingMatchTextRange = enclosingMatch.getTextRange();
String enclosingMatchText = enclosingMatch.getText();
int enclosingMatchTextRangeStartOffset = enclosingMatchTextRange.getStartOffset();
int itemStartOffset = psiElementTextRange.getStartOffset() - enclosingMatchTextRangeStartOffset;
String prefix = enclosingMatchText.substring(0, itemStartOffset);
presentation.appendTailText(prefix, true);
int itemEndOffset = psiElementTextRange.getEndOffset() - enclosingMatchTextRangeStartOffset;
String item = enclosingMatchText.substring(itemStartOffset, itemEndOffset);
presentation.appendTailText(item, false);
String suffix = enclosingMatchText.substring(
itemEndOffset,
enclosingMatchTextRange.getEndOffset() - enclosingMatchTextRangeStartOffset
);
presentation.appendTailText(suffix, true);
}
/*
* Private Instance Methods
*/
@Contract(pure = true)
@NotNull
private Color color(@NotNull final PsiElement element) {
Color color = JBColor.foreground();
if (isIgnored(element)) {
color = ElixirSyntaxHighlighter.IGNORED_VARIABLE.getDefaultAttributes().getForegroundColor();
} else {
Parameter parameter = new Parameter(element);
Parameter.Type parameterType = Parameter.putParameterized(parameter).type;
if (parameterType != null) {
if (parameterType == Parameter.Type.VARIABLE) {
color = ElixirSyntaxHighlighter.PARAMETER.getDefaultAttributes().getForegroundColor();
}
} else if (isParameterWithDefault(element)) {
color = ElixirSyntaxHighlighter.PARAMETER.getDefaultAttributes().getForegroundColor();
} else if (isVariable(element)) {
color = ElixirSyntaxHighlighter.VARIABLE.getDefaultAttributes().getForegroundColor();
}
}
return color;
}
@Contract(pure = true)
@NotNull
private PsiElement enclosingMatch(@NotNull final PsiElement ancestor) {
PsiElement enclosingMatch = ancestor;
PsiElement parent = ancestor.getParent();
if (parent instanceof InMatch || parent instanceof Match) {
enclosingMatch = parent;
} else {
assert ancestor != null;
}
return enclosingMatch;
}
@Contract(pure = true)
@Nullable
private Icon icon(@NotNull PsiElement element) {
Icon icon = null;
Parameter parameter = new Parameter(element);
Parameter.Type parameterType = Parameter.putParameterized(parameter).type;
if (parameterType != null) {
icon = ElixirIcons.PARAMETER;
} else {
icon = ElixirIcons.VARIABLE;
}
return icon;
}
}