Package org.intellij.erlang

Source Code of org.intellij.erlang.ErlangParameterInfoHandler

/*
* Copyright 2012-2014 Sergey Ignatov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.intellij.erlang;

import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.lang.parameterInfo.*;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.PsiReference;
import com.intellij.psi.ResolveResult;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import org.intellij.erlang.bif.ErlangBifDescriptor;
import org.intellij.erlang.bif.ErlangBifTable;
import org.intellij.erlang.psi.*;
import org.intellij.erlang.psi.impl.ErlangPsiImplUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class ErlangParameterInfoHandler implements ParameterInfoHandler<ErlangArgumentList, Object> {
  @Override
  public boolean couldShowInLookup() {
    return true;
  }

  @Override
  public Object[] getParametersForLookup(LookupElement item, ParameterInfoContext context) {
    return ArrayUtil.EMPTY_OBJECT_ARRAY;
  }

  @Override
  public Object[] getParametersForDocumentation(Object p, ParameterInfoContext context) {
    return null;
  }

  @Override
  public ErlangArgumentList findElementForParameterInfo(@NotNull CreateParameterInfoContext context) {
    return getErlangArgumentList(context);
  }

  @Override
  public ErlangArgumentList findElementForUpdatingParameterInfo(@NotNull UpdateParameterInfoContext context) {
    return getErlangArgumentList(context);
  }

  @Nullable
  private static ErlangArgumentList getErlangArgumentList(ParameterInfoContext context) {
    PsiElement at = context.getFile().findElementAt(context.getOffset());
    return PsiTreeUtil.getParentOfType(at, ErlangArgumentList.class);
  }

  @Override
  public void showParameterInfo(@NotNull ErlangArgumentList args, @NotNull CreateParameterInfoContext context) {
    ErlangFunctionCallExpression erlFunctionCall = PsiTreeUtil.getParentOfType(args, ErlangFunctionCallExpression.class);
    if (erlFunctionCall != null) {
      PsiReference reference = erlFunctionCall.getReference();
      PsiElement resolve = reference != null ? reference.resolve() : null;
      List<ErlangFunctionClause> clauses = new ArrayList<ErlangFunctionClause>();
      if (resolve instanceof ErlangFunction) {
        List<ErlangFunctionClause> clauseList = ((ErlangFunction) resolve).getFunctionClauseList();
        clauses.addAll(clauseList);
      }
      else if (reference instanceof PsiPolyVariantReference) {
        ResolveResult[] resolveResults = ((PsiPolyVariantReference) reference).multiResolve(true);
        for (ResolveResult result : resolveResults) {
          PsiElement element = result.getElement();
          if (element instanceof ErlangFunction) {
            clauses.addAll(((ErlangFunction) element).getFunctionClauseList());
          }
        }
      }
      if (clauses.size() > 0) {
        Collections.sort(clauses, new Comparator<ErlangFunctionClause>() {
          @Override
          public int compare(ErlangFunctionClause lhs, ErlangFunctionClause rhs) {
            int lhsSize = lhs.getArgumentDefinitionList().getArgumentDefinitionList().size();
            int rhsSize = rhs.getArgumentDefinitionList().getArgumentDefinitionList().size();
            return Integer.signum(lhsSize - rhsSize);
          }
        });
        context.setItemsToShow(ArrayUtil.toObjectArray(clauses));
        context.showHint(args, args.getTextRange().getStartOffset(), this);
      }
      else {
        ErlangGlobalFunctionCallExpression erlGlobalFunctionCall = PsiTreeUtil.getParentOfType(erlFunctionCall, ErlangGlobalFunctionCallExpression.class);
        if (erlGlobalFunctionCall != null) {
          ErlangModuleRef moduleRef = erlGlobalFunctionCall.getModuleRef();
          if (moduleRef != null) {
            String moduleName = moduleRef.getText();
            String functionName = erlFunctionCall.getName();
            List<ErlangBifDescriptor> moduleInfo = functionName.equals(ErlangBifTable.MODULE_INFO) ? ErlangBifTable.getBifs("", functionName) : Collections.<ErlangBifDescriptor>emptyList();
            context.setItemsToShow(ArrayUtil.toObjectArray(ContainerUtil.concat(ErlangBifTable.getBifs(moduleName, functionName), moduleInfo)));
            context.showHint(args, args.getTextRange().getStartOffset(), this);
          }
        }
        else {
          String name = erlFunctionCall.getName();
          context.setItemsToShow(ArrayUtil.toObjectArray(ContainerUtil.concat(ErlangBifTable.getBifs("erlang", name), ErlangBifTable.getBifs("", name))));
          context.showHint(args, args.getTextRange().getStartOffset(), this);
        }
      }
    }
  }

  @Override
  public void updateParameterInfo(@NotNull ErlangArgumentList place, @NotNull UpdateParameterInfoContext context) {
    context.setCurrentParameter(ParameterInfoUtils.getCurrentParameterIndex(place.getNode(), context.getOffset(), ErlangTypes.ERL_COMMA));
  }

  @Override
  public String getParameterCloseChars() {
    return ",){}";
  }

  @Override
  public boolean tracksParameterIndex() {
    return true;
  }

  @Override
  public void updateUI(@Nullable Object p, @NotNull ParameterInfoUIContext context) {
    if (p == null) {
      context.setUIComponentEnabled(false);
      return;
    }
    int index = context.getCurrentParameterIndex();

    StringBuilder builder = new StringBuilder();

    boolean disabled = false;
    int start = 0;
    int end = 0;
    if (p instanceof ErlangFunctionClause) {
      final Ref<ErlangFunTypeArguments> argsRef = Ref.create();

      PsiElement parent = ((ErlangFunctionClause) p).getParent();
      ErlangSpecification specification = parent instanceof ErlangFunction
        ? ErlangPsiImplUtil.getSpecification((ErlangFunction) parent) : null;
      if (specification != null) {
        specification.accept(new ErlangRecursiveVisitor() {
          @Override
          public void visitFunTypeArguments(@NotNull ErlangFunTypeArguments o) {
            argsRef.setIfNull(o);
          }
        });
      }

      List<ErlangArgumentDefinition> args = ((ErlangFunctionClause) p).getArgumentDefinitionList().getArgumentDefinitionList();

      @Nullable ErlangFunTypeArguments arguments = argsRef.get();
      List<ErlangTopType> topTypeList = arguments == null ? ContainerUtil.<ErlangTopType>emptyList() : arguments.getTopTypeList();
      boolean typesAvailable = topTypeList.size() == args.size();

      for (int i = 0; i < args.size(); i++) {
        if (i != 0) builder.append(", ");
        if (index == i) start = builder.length();
        builder.append(args.get(i).getExpression().getText().replaceAll(" ", "").trim());
        if (typesAvailable) {
          ErlangTopType topType = topTypeList.get(i);
          ErlangType type = topType.getType();
          final ErlangQVar var = type.getQVar();
          if (var != null) {
            if (specification != null) {
              final Ref<ErlangType> itemTypeRef = Ref.create();
              specification.accept(new ErlangRecursiveVisitor() {
                @Override
                public void visitTypeGuard(@NotNull ErlangTypeGuard o) {
                  ErlangTopType item = ContainerUtil.getFirstItem(o.getTopTypeList());
                  ErlangQVar qVar = item == null ? null : item.getQVar();
                  PsiReference reference = qVar == null ? null : qVar.getReference();
                  PsiElement resolve = reference == null ? null : reference.resolve();
                  if (var.equals(resolve)) {
                    itemTypeRef.setIfNull(item.getType());
                  }
                }
              });
              if (!itemTypeRef.isNull()) {
                builder.append(" :: ");
                builder.append(itemTypeRef.get().getText());
              }
            }
          }
          else {
            builder.append(" :: ");
            builder.append(type.getText());
          }
        }
        if (index == i) end = builder.length();
      }

      ErlangClauseGuard clauseGuard = ((ErlangFunctionClause) p).getClauseGuard();

      String text = clauseGuard != null ? " " + clauseGuard.getText() : "";
      builder.append(text);

      disabled = index >= args.size();
    }
    else if (p instanceof ErlangBifDescriptor) {
      String bifParams = ((ErlangBifDescriptor) p).getParams();
      builder.append(bifParams);
      for (int i = 0; i < index && start != -1; ++i) {
        start = bifParams.indexOf(',', start + 1);
      }
      if (start == -1) {
        disabled = true;
      }
      else {
        end = bifParams.indexOf(',', start + 1);
        end = end == -1 ? bifParams.length() : end;
      }
    }

    if (builder.length() == 0) {
      builder.append("<no parameters>");
    }

    context.setupUIComponentPresentation(builder.toString(), start, end, disabled, false, true,
      context.getDefaultParameterColor());
  }
}
TOP

Related Classes of org.intellij.erlang.ErlangParameterInfoHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.