Package org.jetbrains.plugins.clojure.psi.impl.defs

Source Code of org.jetbrains.plugins.clojure.psi.impl.defs.ClDefImpl

package org.jetbrains.plugins.clojure.psi.impl.defs;

import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.ResolveState;
import com.intellij.psi.StubBasedPsiElement;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.clojure.ClojureIcons;
import org.jetbrains.plugins.clojure.lexer.ClojureTokenTypes;
import org.jetbrains.plugins.clojure.psi.ClojurePsiElement;
import org.jetbrains.plugins.clojure.psi.api.*;
import org.jetbrains.plugins.clojure.psi.api.defs.ClDef;
import org.jetbrains.plugins.clojure.psi.api.symbols.ClSymbol;
import org.jetbrains.plugins.clojure.psi.impl.list.ClListBaseImpl;
import org.jetbrains.plugins.clojure.psi.resolve.ResolveUtil;
import org.jetbrains.plugins.clojure.psi.stubs.api.ClDefStub;
import org.jetbrains.plugins.clojure.psi.stubs.api.ClNsStub;

import javax.swing.*;
import java.util.ArrayList;

/**
* @author ilyas
*/
public class ClDefImpl extends ClListBaseImpl<ClDefStub> implements ClDef, StubBasedPsiElement<ClDefStub> {
  public ClDefImpl(ClDefStub stub, @NotNull IStubElementType nodeType) {
    super(stub, nodeType);
  }

  public ClDefImpl(ASTNode node) {
    super(node);
  }

  @Override
  public String toString() {
    return "ClDef";
  }

  /**
   * @return Name of string symbol defined
   */
  @Nullable
  public ClSymbol getNameSymbol() {
    final ClSymbol first = findChildByClass(ClSymbol.class);
    if (first == null) return null;
    return PsiTreeUtil.getNextSiblingOfType(first, ClSymbol.class);
  }

  public String getDefinedName() {
    ClSymbol sym = getNameSymbol();
    if (sym != null) {
      String name = sym.getText();
      assert name != null;
      return name;
    }
    return "";
  }

  @Override
  @Nullable
  public String getName() {
    ClDefStub stub = getStub();
    if (stub != null) {
      return stub.getName();
    }

    return getDefinedName();
  }

  @Override
  public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) {
    // Do not resolve identifier
    if (lastParent != null && lastParent.getParent() == this && lastParent instanceof ClSymbol) return true;
    //process parameters
    if (lastParent != null && lastParent.getParent() == this) {
      final ClVector paramVector = findChildByClass(ClVector.class);
      if (paramVector != null) {
        for (ClSymbol symbol : paramVector.getAllSymbols()) {
          if (!ResolveUtil.processElement(processor, symbol)) return false;
        }
      }
      // for recursive functions
      if (getNameSymbol() != null && lastParent != getNameSymbol() && !ResolveUtil.processElement(processor, getNameSymbol())) return false;
      else if (lastParent instanceof ClList) { // overloaded function (defn ([x] body))
        ClList list = (ClList) lastParent;
        final PsiElement elem = list.getFirstNonLeafElement();
        if (elem instanceof ClVector && !PsiTreeUtil.isAncestor(elem, place, false)) {
          final ClVector params = (ClVector) elem;
          if (params != null) {
            for (ClSymbol symbol : params.getAllSymbols()) {
              if (!ResolveUtil.processElement(processor, symbol)) return false;
            }
          }
        }
      }

      return true;
    } else {
      return ResolveUtil.processElement(processor, this);
    }
  }

  @Override
  public ItemPresentation getPresentation() {
    return new ItemPresentation() {
      public String getPresentableText() {
        return getPresentationText();
      }

      @Nullable
      public String getLocationString() {
        String name = getContainingFile().getName();
        //todo show namespace
        return "(in " + name + ")";
      }

      @Nullable
      public Icon getIcon(boolean open) {
        return ClDefImpl.this.getIcon(Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS);
      }

      @Nullable
      public TextAttributesKey getTextAttributesKey() {
        return null;
      }
    };
  }

  public String getPresentationText() {
    final StringBuffer buffer = new StringBuffer();
    final String name = getName();
    if (name == null) return "<undefined>";
    buffer.append(name).append(" ");
    buffer.append(getParameterString());

    return buffer.toString();
  }

  public String getDocString() {
    PsiElement element = getSecondNonLeafElement();
    if (element == null) return null;
    element = element.getNextSibling();
    while (element != null && isWrongElement(element)) {
      element = element.getNextSibling();
    }
    // For doc String
    final String s = processString(element);
    if (s != null) return s;

    final ClMetadata meta = getMeta();
    if (meta == null) return null;
    return processMetadata(meta);
  }

  private String processString(PsiElement element) {
    if (element instanceof ClLiteral && element.getFirstChild().getNode().getElementType() == ClojureTokenTypes.STRING_LITERAL) {
      final String rawText = element.getText();
      final String str = StringUtil.trimStart(StringUtil.trimEnd(rawText, "\""), "\"");
      return str.replace("\n  ", "\n").replace("\n","<br/>");
    }
    return null;
  }

  private String processMetadata(@NotNull ClMetadata meta) {
    final StringBuffer buffer = new StringBuffer();
    final ClojurePsiElement args = meta.getValue("arglists");
    if (args != null) {
      if (args instanceof ClQuotedForm) {
        ClQuotedForm form = (ClQuotedForm) args;
        if (form.getQuotedElement() instanceof ClList) {
          ClList list = (ClList) form.getQuotedElement();
          final ArrayList<String> chunks = new ArrayList<String>();
          if (list != null) {
            for (PsiElement element : list.getChildren()) {
              if (element instanceof ClVector) {
                chunks.add(element.getText());
              }
            }
          }
          buffer.append("Arguments:\n");
          for (String chunk : chunks) {
            buffer.append("<b>").append(chunk.trim()).append("</b>").append("\n");
          }
          buffer.append("<br/>");
        }
      }
    }

    final ClojurePsiElement value = meta.getValue("doc");
    if (value != null) {
      buffer.append(processString(value));
    }
    return buffer.toString();
  }


  @Override
  public Icon getIcon(int flags) {
    return ClojureIcons.FUNCTION;
  }

  public PsiElement setName(@NotNull @NonNls String name) throws IncorrectOperationException {
    final ClSymbol sym = getNameSymbol();
    if (sym != null) sym.setName(name);
    return this;
  }

  @Override
  public int getTextOffset() {
    ClDefStub stub = getStub();
    if (stub != null) {
      return stub.getTextOffset();
    }

    final ClSymbol symbol = getNameSymbol();
    if (symbol != null) {
      return symbol.getTextRange().getStartOffset();
    }
    return super.getTextOffset();
  }

  public String getParameterString() {
    final ClVector params = findChildByClass(ClVector.class);
    return params == null ? "" : params.getText();
  }

  public ClMetadata getMeta() {
    for (PsiElement element : getChildren()) {
      if (element instanceof ClMetadata) {
        return (ClMetadata) element;
      }
    }
    return null;
  }

  public String getMethodInfo() {
    final ClSymbol sym = getNameSymbol();
    if (sym == null) return "";
    PsiElement next = sym.getNextSibling();
    while (next instanceof LeafPsiElement) next = next.getNextSibling();
    return next == null ? "" : next.getText();
  }
}
TOP

Related Classes of org.jetbrains.plugins.clojure.psi.impl.defs.ClDefImpl

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.