package com.jetbrains.lang.dart.psi;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.ManagingFS;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet;
import com.intellij.util.ProcessingContext;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.lang.dart.util.PubspecYamlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.yaml.psi.YAMLDocument;
import org.jetbrains.yaml.psi.YAMLKeyValue;
import org.jetbrains.yaml.psi.YAMLMapping;
import java.util.Collection;
public class PubspecYamlReferenceContributor extends PsiReferenceContributor {
@Override
public void registerReferenceProviders(@NotNull final PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(PlatformPatterns.psiElement(YAMLKeyValue.class), new PubspecYamlReferenceProvider());
}
public static boolean isPathPackageDefinition(@NotNull final YAMLKeyValue element) {
if (!PubspecYamlUtil.PUBSPEC_YAML.equals(element.getContainingFile().getName())) return false;
if (!PubspecYamlUtil.PATH.equals(element.getKeyText())) return false;
final PsiElement parent1 = element.getParent();
final PsiElement parent2 = parent1 instanceof YAMLMapping ? parent1.getParent() : null;
final String packageName = parent2 instanceof YAMLKeyValue ? ((YAMLKeyValue)parent2).getKeyText() : null;
if (packageName == null) return false;
final PsiElement parent3 = parent2.getParent();
final PsiElement parent4 = parent3 instanceof YAMLMapping ? parent3.getParent() : null;
return parent4 instanceof YAMLKeyValue &&
parent4.getParent() instanceof YAMLMapping &&
parent4.getParent().getParent() instanceof YAMLDocument &&
(PubspecYamlUtil.DEPENDENCIES.equals(((YAMLKeyValue)parent4).getKeyText()) ||
PubspecYamlUtil.DEV_DEPENDENCIES.equals(((YAMLKeyValue)parent4).getKeyText()) ||
PubspecYamlUtil.DEPENDENCY_OVERRIDES.equals(((YAMLKeyValue)parent4).getKeyText()));
}
private static class PubspecYamlReferenceProvider extends PsiReferenceProvider {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull final PsiElement element, @NotNull final ProcessingContext context) {
if (!(element instanceof YAMLKeyValue) || !isPathPackageDefinition((YAMLKeyValue)element)) {
return PsiReference.EMPTY_ARRAY;
}
final PsiElement value = ((YAMLKeyValue)element).getValue();
if (value == null) {
return PsiReference.EMPTY_ARRAY;
}
final String text = StringUtil.trimTrailing(FileUtil.toSystemIndependentName(value.getText()));
final boolean quoted = StringUtil.isQuotedString(text);
final int startInElement = value.getStartOffsetInParent() + (quoted ? 1 : 0);
final FileReferenceSet fileReferenceSet = new FileReferenceSet(StringUtil.unquoteString(text), element, startInElement,
this, SystemInfo.isFileSystemCaseSensitive, false) {
@NotNull
@Override
public Collection<PsiFileSystemItem> computeDefaultContexts() {
if (isAbsolutePathReference()) {
final VirtualFile[] roots = ManagingFS.getInstance().getLocalRoots();
final Collection<PsiFileSystemItem> result = new SmartList<>();
for (VirtualFile root : roots) {
ContainerUtil.addIfNotNull(result, element.getManager().findDirectory(root));
}
return result;
}
return super.computeDefaultContexts();
}
@Override
public boolean isAbsolutePathReference() {
final String path = getPathString();
return SystemInfo.isWindows
? path.length() >= 3 && Character.isLetter(path.charAt(0)) && ':' == path.charAt(1) && '/' == path.charAt(2)
: path.startsWith("/");
}
@Override
protected Condition<PsiFileSystemItem> getReferenceCompletionFilter() {
return DIRECTORY_FILTER;
}
};
return fileReferenceSet.getAllReferences();
}
}
}