/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.parameterinfo;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.lang.parameterInfo.CreateParameterInfoContext;
import com.intellij.lang.parameterInfo.ParameterInfoContext;
import com.intellij.lang.parameterInfo.ParameterInfoHandler;
import com.intellij.lang.parameterInfo.ParameterInfoUIContext;
import com.intellij.lang.parameterInfo.ParameterInfoUtils;
import com.intellij.lang.parameterInfo.UpdateParameterInfoContext;
import com.intellij.psi.PsiAnnotationMethod;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.expressions.IAnnotationExpression;
import gw.lang.reflect.IType;
import gw.lang.reflect.TypeSystem;
import gw.lang.reflect.module.IModule;
import gw.plugin.ij.lang.psi.impl.GosuBaseElementImpl;
import gw.plugin.ij.lang.psi.impl.resolvers.PsiTypeResolver;
import gw.plugin.ij.util.ExceptionUtil;
import gw.plugin.ij.util.GosuBundle;
import gw.plugin.ij.util.GosuModuleUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.google.common.base.Objects.firstNonNull;
public class GosuAnnotationParameterInfoHandler implements ParameterInfoHandler<PsiElement, PsiMethod> {
@Override
public boolean couldShowInLookup() {
return true;
}
@Override
public Object[] getParametersForLookup(LookupElement item, ParameterInfoContext context) {
return new Object[0];
}
@Override
public Object[] getParametersForDocumentation(PsiMethod p, ParameterInfoContext context) {
return new Object[0];
}
@Override
public PsiElement findElementForParameterInfo(@NotNull CreateParameterInfoContext context) {
final IModule module = firstNonNull(GosuModuleUtil.findModuleForPsiElement(context.getFile()),
GosuModuleUtil.getGlobalModule(context.getFile().getProject()));
TypeSystem.pushModule(module);
try {
final PsiElement owner = ParameterInfoUtil.findParamOwnerAtOffset(context.getOffset(), context.getFile());
if (owner != null) {
final IParsedElement pe = ((GosuBaseElementImpl) owner).getParsedElement();
if (pe instanceof IAnnotationExpression) {
processAnnotation(((IAnnotationExpression) pe).getType(), context);
} else {
return null;
}
}
return owner;
} finally {
TypeSystem.popModule(module);
}
}
private void processAnnotation(IType type, @NotNull CreateParameterInfoContext context) {
final PsiElement klass = PsiTypeResolver.resolveType(ParameterInfoUtil.getActualType(type), context.getFile());
if (klass instanceof PsiClass) {
context.setItemsToShow(((PsiClass) klass).getMethods());
}
}
@Override
public void showParameterInfo(@NotNull PsiElement element, @NotNull CreateParameterInfoContext context) {
String error = ParameterInfoUtil.verify(context);
if (error != null) {
ExceptionUtil.showNonFatalError(GosuBundle.message("parameter.info.problem"), error);
} else {
context.showHint(element, element.getTextRange().getStartOffset(), this);
}
}
@Override
public PsiElement findElementForUpdatingParameterInfo(@NotNull UpdateParameterInfoContext context) {
return ParameterInfoUtil.findParamOwnerAtOffset(context.getOffset(), context.getFile());
}
@Override
public void updateParameterInfo(@NotNull PsiElement o, @NotNull UpdateParameterInfoContext context) {
if (context.getParameterOwner() != o) {
context.removeHint();
return;
}
int index = ParameterInfoUtil.getCurrentParameterIndex(o, context.getOffset());
Object[] objectsToView = context.getObjectsToView();
if (index >= 0 && index < objectsToView.length) {
context.setHighlightedParameter(objectsToView[index]);
}
}
@Override
public String getParameterCloseChars() {
return ParameterInfoUtils.DEFAULT_PARAMETER_CLOSE_CHARS;
}
@Override
public boolean tracksParameterIndex() {
return true;
}
@Override
public void updateUI(@NotNull PsiMethod method, ParameterInfoUIContext context) {
if (method instanceof PsiAnnotationMethod) {
// Java annotation
updateAnnotationUI(method, context);
} else {
// Gosu annotation
GosuParameterInfoHandler.updateMethodUI(context, method, null);
}
}
private void updateAnnotationUI(@NotNull PsiMethod method, @Nullable ParameterInfoUIContext context) {
IModule module = GosuModuleUtil.findModuleForPsiElement(method);
TypeSystem.pushModule(module);
try {
StringBuilder sb = new StringBuilder();
// if (settings.SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO) {
// sb.append(method.getReturnType().getPresentableText());
// sb.append(" ");
// sb.append(method.getName());
// sb.append("(");
// }
PsiType returnType = method.getReturnType();
if (returnType != null) {
sb.append(returnType.getPresentableText());
}
sb.append(" ");
int highlightStartOffset = sb.length();
sb.append(method.getName());
int highlightEndOffset = sb.length();
sb.append("()");
// if (settings.SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO) {
// buffer.append(")");
// }
if (context != null) {
context.setupUIComponentPresentation(
sb.toString(),
highlightStartOffset,
highlightEndOffset,
!context.isUIComponentEnabled(),
method.isDeprecated(),
false,
context.getDefaultParameterColor());
}
} finally {
TypeSystem.popModule(module);
}
}
}