Package de.halirutan.mathematica.documentation

Source Code of de.halirutan.mathematica.documentation.MathematicaDocumentationProvider

/*
* Copyright (c) 2013 Patrick Scheibe
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package de.halirutan.mathematica.documentation;

import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupEx;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.lang.documentation.AbstractDocumentationProvider;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiWhiteSpace;
import de.halirutan.mathematica.parsing.psi.api.OperatorNameProvider;
import de.halirutan.mathematica.parsing.psi.api.Symbol;
import de.halirutan.mathematica.parsing.psi.impl.SymbolImpl;
import de.halirutan.mathematica.parsing.psi.util.MathematicaPsiElementFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.InputStream;
import java.util.Scanner;
import java.util.regex.Pattern;

/**
* @author patrick (4/4/13)
*/
public class MathematicaDocumentationProvider extends AbstractDocumentationProvider {

  private static final Pattern SLOT_PATTERN = Pattern.compile("#[0-9]*");
  private static final Pattern ALL_SLOT_PATTERN = Pattern.compile("#+[0-9]*");
  private static final Pattern SLOT_SEQUENCE_PATTERN = Pattern.compile("##[0-9]*");

  /**
   * Generates the documentation (if available) for element. This does two things, first it looks whether the element is
   * a {@link Symbol}. If this is true it tries to load the usage message. If element is not a Symbol, it is possibly an
   * operator. Then it tries to guess the usage message of the operator by converting the class name to a hopefully
   * valid operator name.
   *
   * @param element
   *     Element which was possibly altered by {@link #getCustomDocumentationElement(Editor, PsiFile, PsiElement)} or by
   *     {@link #getDocumentationElementForLookupItem(PsiManager, Object, PsiElement)} if the lookup was active
   * @param originalElement
   *     The original element for which the doc was called (possibly whitespace)
   * @return The html string of the usage message or null if it could not be loaded
   */
  @Nullable
  @Override
  public String generateDoc(PsiElement element, @Nullable PsiElement originalElement) {
    String path = null;

    if (element instanceof Symbol) {
      String context = ((Symbol) element).getMathematicaContext();
      String name = ((Symbol) element).getSymbolName();
      if (ALL_SLOT_PATTERN.matcher(name).matches()) {
        if (SLOT_PATTERN.matcher(name).matches()) name = "Slot";
        else if (SLOT_SEQUENCE_PATTERN.matcher(name).matches()) name = "SlotSequence";
      }
//      path = "usages" + File.separatorChar + context.replace('`', File.separatorChar) + name + ".html";
      path = "usages/" + context.replace('`', '/') + name + ".html";
    }

    if (element instanceof OperatorNameProvider) {
//      path = "usages" + File.separatorChar + "System" + File.separatorChar + ((OperatorNameProviderImpl) element).getOperatorName() + ".html";
      path = "usages/System/" + ((OperatorNameProvider) element).getOperatorName() + ".html";
    }

    InputStream docFile = (path != null) ? MathematicaDocumentationProvider.class.getResourceAsStream(path) : null;
    if (docFile != null) {
      return new Scanner(docFile, "UTF-8").useDelimiter("\\A").next();
    }
    return null;
  }

  /**
   * Calculates the correct element for which the user wants documentation.
   *
   * @param editor
   *     The editor of the file
   * @param file
   *     The file which is edited and where the doc call was made
   * @param contextElement
   *     The element where the caret was when the doc was called
   * @return The element for which the user wants documentation. If an item of the completion list is currently
   * highlighted, then this element. If the cursor is over/beside an identifier, then the symbol element. As last thing
   * it is determined whether the PsiElement is the operator-sign of an operation, then we get the corresponding
   * operation psi implementation element back.
   */
  @Nullable
  @Override
  public PsiElement getCustomDocumentationElement(@NotNull Editor editor, @NotNull PsiFile file, @Nullable PsiElement contextElement) {

    // Check whether there is a completion item which is currently active and give a Symbol element
    // containing the lookup name back.
    final LookupEx activeLookup = LookupManager.getActiveLookup(editor);
    if ((activeLookup != null) && activeLookup.isFocused()) {
      final PsiElement elementAt = file.findElementAt(editor.getCaretModel().getOffset() - 1);
      if (elementAt != null) {
        Symbol lookup = new SymbolImpl(elementAt.getNode());
        final LookupElement currentItem = activeLookup.getCurrentItem();
        final String lookupString = currentItem != null ? currentItem.getLookupString() : "";
        lookup.setName(lookupString);
        return lookup;
      }
    }

    if (contextElement != null) {
      PsiElement parent = contextElement.getParent();

      if ((contextElement instanceof PsiWhiteSpace) || !((parent instanceof Symbol) || (parent instanceof OperatorNameProvider))) {
        PsiElement elm = file.findElementAt(editor.getCaretModel().getOffset() - 1);
        if (elm != null) {
          contextElement = elm;
          parent = elm.getParent();
        }
      }

      if (parent instanceof Symbol) {
        return new SymbolImpl(parent.getNode());
      }

      // Determine if the contextElement is the operator sign of an operation.
      // See the doc to OperatorNameProviderImpl.
      if (parent instanceof OperatorNameProvider) {
        if (((OperatorNameProvider) parent).isOperatorSign(contextElement)) {
          return parent;
        }
      }
    }
    return null;
  }

  /**
   * This makes it possible to have the documentation for each function while scrolling through the completion
   * suggestion list.
   *
   * @param psiManager
   *     access to Psi related things
   * @param object
   *     the current lookup object
   * @param element
   *     the element, the documentation was initially called for. Note that this is typically not a valid built-in
   *     function, because you start typing Plo then the completion box pops up and when you call documentation on one
   *     of the selected lookup entries, the elements name is still Plo, while you want to check the documentation for
   *     the lookup element.
   * @return The Symbol which was created from the string of the lookup element or null if it wasn't possible.
   */
  @Nullable
  @Override
  public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) {
    if (element != null) {
      final LookupEx activeLookup = LookupManager.getActiveLookup(FileEditorManager.getInstance(element.getProject()).getSelectedTextEditor());
      if (activeLookup != null) {
        if (activeLookup.isFocused()) {
          MathematicaPsiElementFactory elementFactory = new MathematicaPsiElementFactory(psiManager.getProject());
          try {
            return elementFactory.createSymbol(object.toString());
          } catch (Exception e) {
            return null;
          }
        }
      }
    }
    return null;
  }
}
TOP

Related Classes of de.halirutan.mathematica.documentation.MathematicaDocumentationProvider

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.