package com.siberika.idea.pascal.editor; 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.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.SmartList; import com.siberika.idea.pascal.lang.psi.PasCallExpr; import com.siberika.idea.pascal.lang.psi.PasFormalParameter; import com.siberika.idea.pascal.lang.psi.PasFormalParameterSection; import com.siberika.idea.pascal.lang.psi.PasNamedIdent; import com.siberika.idea.pascal.lang.psi.PasTypes; import com.siberika.idea.pascal.lang.psi.impl.PasField; import com.siberika.idea.pascal.lang.psi.impl.PascalRoutineImpl; import com.siberika.idea.pascal.lang.references.PasReferenceUtil; import com.siberika.idea.pascal.util.PsiUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * Author: George Bakhtadze * Date: 25/03/2015 */ public class PascalParameterInfoHandler implements ParameterInfoHandler<PasCallExpr, PasFormalParameterSection> { @Override public boolean couldShowInLookup() { return true; } @Nullable @Override public Object[] getParametersForLookup(LookupElement item, ParameterInfoContext context) { return null; } @Nullable @Override public Object[] getParametersForDocumentation(PasFormalParameterSection p, ParameterInfoContext context) { return null; } @Nullable @Override public PasCallExpr findElementForParameterInfo(@NotNull CreateParameterInfoContext context) { PasCallExpr res = getCallExpr(context.getFile().findElementAt(context.getOffset())); context.setItemsToShow(getParameters(res)); return res; } @Nullable @Override public PasCallExpr findElementForUpdatingParameterInfo(@NotNull UpdateParameterInfoContext context) { PasCallExpr res = getCallExpr(context.getFile().findElementAt(context.getOffset())); if (res != null) { int index = ParameterInfoUtils.getCurrentParameterIndex(res.getArgumentList().getNode(), context.getOffset(), PasTypes.COMMA); context.setCurrentParameter(index); } return res; } private Object[] getParameters(PasCallExpr callExpr) { Map<String, PasFormalParameterSection> res = new TreeMap<String, PasFormalParameterSection>(); for (PasField field : PasReferenceUtil.resolveRoutines(callExpr)) { if (field.getElement() instanceof PascalRoutineImpl) { PasFormalParameterSection parameters = ((PascalRoutineImpl) field.getElement()).getFormalParameterSection(); if (parameters != null) { res.put(PsiUtil.getFieldName(field.getElement()), parameters); } } } return res.values().toArray(); } @Override public void showParameterInfo(@NotNull PasCallExpr element, @NotNull CreateParameterInfoContext context) { context.showHint(element, element.getTextRange().getStartOffset(), this); } private PasCallExpr getCallExpr(PsiElement element) { PasCallExpr call = PsiTreeUtil.getParentOfType(element, PasCallExpr.class); if ((null == call) && (element != null)) { PsiElement prev = PsiTreeUtil.prevLeaf(element, true); if ((prev != null) && (prev.getText().equals("("))) { call = PsiTreeUtil.getParentOfType(prev, PasCallExpr.class); } } return call; } @Override public void updateParameterInfo(@NotNull PasCallExpr element, @NotNull UpdateParameterInfoContext context) { } @Nullable @Override public String getParameterCloseChars() { return ")"; } @Override public boolean tracksParameterIndex() { return false; } @Override public void updateUI(PasFormalParameterSection p, @NotNull ParameterInfoUIContext context) { List<PsiElement> idents = getIdentList(p); PsiElement hlParam = null; boolean isDisabled = false; if (context.getCurrentParameterIndex() < idents.size()) { hlParam = (context.getCurrentParameterIndex() >= 0) ? idents.get(context.getCurrentParameterIndex()) : null; } else { isDisabled = true; } int hlStart = -1; int hlEnd = -1; if (hlParam != null) { hlStart = hlParam.getTextRange().getStartOffset() - p.getTextOffset() - 1; hlEnd = hlParam.getTextRange().getEndOffset() - p.getTextOffset() - 1; } context.setupUIComponentPresentation(getHintText(p), hlStart, hlEnd, isDisabled, false, false, context.getDefaultParameterColor() ); } @NotNull private List<PsiElement> getIdentList(PasFormalParameterSection p) { SmartList<PsiElement> res = new SmartList<PsiElement>(); for (PasFormalParameter paramSec : p.getFormalParameterList()) { for (PasNamedIdent pasNamedIdent : paramSec.getNamedIdentList()) { res.add(pasNamedIdent); } } return res; } private String getHintText(PasFormalParameterSection p) { String s = p.getText(); return s.length() > 2 ? s.substring(1, s.length() - 1) : "()"; } }