Package com.google.jstestdriver.idea.config

Source Code of com.google.jstestdriver.idea.config.JstdConfigFileReferenceContributor$MyPsiReference

package com.google.jstestdriver.idea.config;

import com.google.common.collect.Lists;
import com.google.jstestdriver.idea.util.PsiElementFragment;
import com.intellij.openapi.editor.DocumentFragment;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.yaml.psi.YAMLCompoundValue;
import org.jetbrains.yaml.psi.YAMLDocument;
import org.jetbrains.yaml.psi.YAMLKeyValue;
import org.jetbrains.yaml.psi.YAMLSequence;

import java.util.List;

/**
* @author Sergey Simonchik
*/
public class JstdConfigFileReferenceContributor extends PsiReferenceContributor {

  @Override
  public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
    registrar.registerReferenceProvider(JstdConfigFileUtils.CONFIG_FILE_ELEMENT_PATTERN, new PsiReferenceProvider() {
      @NotNull
      @Override
      public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
        final YAMLKeyValue keyValue = ObjectUtils.tryCast(element, YAMLKeyValue.class);
        if (keyValue == null) {
          return PsiReference.EMPTY_ARRAY;
        }
        final YAMLDocument yamlDocument = ObjectUtils.tryCast(keyValue.getParent(), YAMLDocument.class);
        if (yamlDocument == null) {
          return PsiReference.EMPTY_ARRAY;
        }
        final BasePathInfo basePathInfo = new BasePathInfo(yamlDocument);
        if (BasePathInfo.isBasePathKey(keyValue)) {
          PsiReference basePathRef = createBasePathRef(basePathInfo);
          if (basePathRef != null) {
            return new PsiReference[] {basePathRef};
          }
        } else if (JstdConfigFileUtils.isTopLevelKeyWithInnerFileSequence(keyValue)) {
          VirtualFile basePath = basePathInfo.getBasePath();
          if (basePath != null) {
            List<PsiReference> references = Lists.newArrayList();
            addReferencesForKeyValueWithInnerFileSequence(basePathInfo, keyValue, references);
            return references.toArray(new PsiReference[references.size()]);
          }
        }
        return PsiReference.EMPTY_ARRAY;
    }
    });
  }

  @Nullable
  private static PsiReference createBasePathRef(@NotNull BasePathInfo basePathInfo) {
    DocumentFragment documentFragment = basePathInfo.getValueAsDocumentFragment();
    YAMLKeyValue keyValue = basePathInfo.getKeyValue();
    if (documentFragment != null && keyValue != null) {
      PsiElementFragment<YAMLKeyValue> keyValueFragment = PsiElementFragment.create(keyValue, documentFragment);
      if (keyValueFragment != null) {
        return new MyPsiReference(keyValueFragment, basePathInfo, ".");
      }
    }
    return null;
  }

  private static void addReferencesForKeyValueWithInnerFileSequence(@NotNull final BasePathInfo basePathInfo,
                                                                    @NotNull final YAMLKeyValue keyValue,
                                                                    @NotNull final List<PsiReference> references) {
    keyValue.acceptChildren(new PsiElementVisitor() {
      @Override
      public void visitElement(PsiElement element) {
        YAMLCompoundValue compoundValue = ObjectUtils.tryCast(element, YAMLCompoundValue.class);
        if (compoundValue != null) {
          compoundValue.acceptChildren(new PsiElementVisitor() {
            @Override
            public void visitElement(PsiElement element) {
              YAMLSequence yamlSequence = ObjectUtils.tryCast(element, YAMLSequence.class);
              if (yamlSequence != null) {
                PsiReference ref = getReferenceBySequence(basePathInfo, keyValue, yamlSequence);
                if (ref != null) {
                  references.add(ref);
                }
              }
            }
          });
        }
      }
    });
  }

  @Nullable
  private static PsiReference getReferenceBySequence(@NotNull BasePathInfo basePathInfo,
                                                     @NotNull YAMLKeyValue keyValue,
                                                     @NotNull YAMLSequence sequence) {
    PsiElementFragment<YAMLSequence> sequenceFragment = JstdConfigFileUtils.buildSequenceTextFragment(sequence);
    if (sequenceFragment != null) {
      String text = sequenceFragment.getText().trim();
      String relativePath = FileUtil.toSystemIndependentName(text);
      PsiElementFragment<YAMLKeyValue> keyValueFragment = sequenceFragment.getSameTextRangeForParent(keyValue);
      return new MyPsiReference(keyValueFragment, basePathInfo, relativePath);
    }
    return null;
  }

  private static class MyPsiReference implements PsiReference {

    private PsiElementFragment<YAMLKeyValue> myYamlKeyValueFragment;
    private final BasePathInfo myBasePathInfo;
    private final String myRelativePath;

    private MyPsiReference(@NotNull PsiElementFragment<YAMLKeyValue> yamlKeyValueFragment,
                           @NotNull BasePathInfo basePathInfo,
                           @NotNull String relativePath) {
      myYamlKeyValueFragment = yamlKeyValueFragment;
      myBasePathInfo = basePathInfo;
      myRelativePath = relativePath;
    }

    @Override
    public PsiElement getElement() {
      return myYamlKeyValueFragment.getElement();
    }

    @Override
    public TextRange getRangeInElement() {
      return myYamlKeyValueFragment.getTextRangeInElement();
    }

    @Override
    public PsiElement resolve() {
      VirtualFile targetVirtualFile = myBasePathInfo.findFile(myRelativePath);
      if (targetVirtualFile != null && targetVirtualFile.isValid()) {
        Project project = myYamlKeyValueFragment.getElement().getProject();
        PsiManager psiManager = PsiManager.getInstance(project);
        if (targetVirtualFile.isDirectory()) {
          PsiDirectory targetPsiDirectory = psiManager.findDirectory(targetVirtualFile);
          if (targetPsiDirectory != null && targetPsiDirectory.isValid()) {
            return targetPsiDirectory;
          }
        } else {
          final PsiFile targetPsiFile = psiManager.findFile(targetVirtualFile);
          if (targetPsiFile != null && targetPsiFile.isValid()) {
            return targetPsiFile;
          }
        }
      }
      return null;
    }

    @NotNull
    @Override
    public String getCanonicalText() {
      return myYamlKeyValueFragment.getText();
    }

    @Override
    public PsiElement handleElementRename(@NotNull String newElementName) throws IncorrectOperationException {
      TextRange fileNameTextRange = findFileNameTextRagne();
      YAMLKeyValue oldKeyValue = myYamlKeyValueFragment.getElement();
      String newKeyValueText = fileNameTextRange.replace(oldKeyValue.getText(), newElementName);
      YAMLKeyValue newKeyValue = createTempKeyValue(newKeyValueText);
      if (newKeyValue != null) {
        return oldKeyValue.replace(newKeyValue);
      }
      return null;
    }

    @NotNull
    private TextRange findFileNameTextRagne() {
      TextRange lastComponentTextRange = calcLastComponentTextRange(myYamlKeyValueFragment.getText());
      TextRange oldPathRange = myYamlKeyValueFragment.getTextRangeInElement();
      return oldPathRange.cutOut(lastComponentTextRange);
    }

    @NotNull
    private static TextRange calcLastComponentTextRange(@NotNull String path) {
      final int i1 = path.lastIndexOf(JstdConfigFileUtils.UNIX_PATH_SEPARATOR);
      final int i2 = path.lastIndexOf(JstdConfigFileUtils.WINDOWS_PATH_SEPARATOR);
      int resInd = i1;
      if (resInd == -1) {
        resInd = i2;
      } else if (i2 != -1) {
        resInd = Math.max(resInd, i2);
      }
      if (resInd != -1) {
        return new TextRange(resInd + 1, path.length());
      }
      return TextRange.allOf(path);
    }

    @Nullable
    private YAMLKeyValue createTempKeyValue(@NotNull String keyValueText) {
      Project project = myYamlKeyValueFragment.getElement().getProject();
      PsiFile psiFile = PsiFileFactory.getInstance(project).createFileFromText("temp", JstdConfigFileType.INSTANCE, keyValueText);
      return PsiTreeUtil.findChildOfType(psiFile, YAMLKeyValue.class);
    }

    @Override
    public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
      return myYamlKeyValueFragment.getElement();
    }

    @Override
    public boolean isReferenceTo(PsiElement element) {
      return getElement().getManager().areElementsEquivalent(resolve(), element);
    }

    @NotNull
    @Override
    public Object[] getVariants() {
      return ArrayUtil.EMPTY_OBJECT_ARRAY;
    }

    @Override
    public boolean isSoft() {
      return false;
    }
  }
}
TOP

Related Classes of com.google.jstestdriver.idea.config.JstdConfigFileReferenceContributor$MyPsiReference

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.