Package com.jetbrains.lang.dart.util

Source Code of com.jetbrains.lang.dart.util.DartUrlResolverImpl

package com.jetbrains.lang.dart.util;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.LibraryProperties;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.util.PairConsumer;
import com.jetbrains.lang.dart.ide.index.DartLibraryIndex;
import com.jetbrains.lang.dart.sdk.DartConfigurable;
import com.jetbrains.lang.dart.sdk.DartSdk;
import com.jetbrains.lang.dart.sdk.listPackageDirs.DartListPackageDirsLibraryProperties;
import com.jetbrains.lang.dart.sdk.listPackageDirs.PubListPackageDirsAction;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.*;

import static com.jetbrains.lang.dart.util.PubspecYamlUtil.*;

class DartUrlResolverImpl extends DartUrlResolver {

  private final @NotNull Project myProject;
  private final @Nullable DartSdk myDartSdk;
  private final @Nullable VirtualFile myPubspecYamlFile;
  private final @NotNull List<VirtualFile> myPackageRoots = new ArrayList<VirtualFile>();
  private final @NotNull Map<String, VirtualFile> myLivePackageNameToDirMap = new THashMap<String, VirtualFile>();
  private final @NotNull Map<String, Set<String>> myPubListPackageDirsMap = new THashMap<String, Set<String>>();

  DartUrlResolverImpl(final @NotNull Project project, final @NotNull VirtualFile contextFile) {
    myProject = project;
    myDartSdk = DartSdk.getGlobalDartSdk();
    myPubspecYamlFile = initPackageRootsAndReturnPubspecYamlFile(contextFile);
    initLivePackageNameToDirMap();
    initPubListPackageDirsMap(contextFile);
  }

  @Nullable
  public VirtualFile getPubspecYamlFile() {
    return myPubspecYamlFile;
  }

  @NotNull
  public VirtualFile[] getPackageRoots() {
    return myPackageRoots.toArray(new VirtualFile[myPackageRoots.size()]);
  }

  public void processLivePackages(final @NotNull PairConsumer<String, VirtualFile> packageNameAndDirConsumer) {
    for (Map.Entry<String, VirtualFile> entry : myLivePackageNameToDirMap.entrySet()) {
      packageNameAndDirConsumer.consume(entry.getKey(), entry.getValue());
    }
  }

  public Collection<String> getLivePackageNames() {
    return myLivePackageNameToDirMap.keySet();
  }

  @Nullable
  public VirtualFile getPackageDirIfLivePackageOrFromPubListPackageDirs(final @NotNull String packageName) {
    final VirtualFile dir = myLivePackageNameToDirMap.get(packageName);
    if (dir != null) return dir;

    final Set<String> dirPaths = myPubListPackageDirsMap.get(packageName);
    if (dirPaths != null) {
      for (String dirPath : dirPaths) {
        final VirtualFile packageDir = LocalFileSystem.getInstance().findFileByPath(dirPath);
        if (packageDir != null) {
          return packageDir;
        }
      }
    }

    return null;
  }

  @Nullable
  public VirtualFile findFileByDartUrl(final @NotNull String url) {
    if (url.startsWith(DART_PREFIX)) {
      return findFileInDartSdkLibFolder(myProject, myDartSdk, url);
    }

    if (url.startsWith(PACKAGE_PREFIX)) {
      final String packageRelPath = url.substring(PACKAGE_PREFIX.length());

      final int slashIndex = packageRelPath.indexOf('/');
      final String packageName = slashIndex > 0 ? packageRelPath.substring(0, slashIndex) : packageRelPath;
      final String relPathToPackageDir = slashIndex > 0 ? packageRelPath.substring(slashIndex + 1) : "";

      final VirtualFile packageDir = StringUtil.isEmpty(packageName) ? null : myLivePackageNameToDirMap.get(packageName);
      if (packageDir != null) {
        return packageDir.findFileByRelativePath(relPathToPackageDir);
      }

      for (final VirtualFile packageRoot : myPackageRoots) {
        final VirtualFile file = packageRoot.findFileByRelativePath(packageRelPath);
        if (file != null) {
          return file;
        }
      }

      final Set<String> packageDirs = myPubListPackageDirsMap.get(packageName);
      if (packageDirs != null) {
        for (String packageDirPath : packageDirs) {
          final VirtualFile file = LocalFileSystem.getInstance().findFileByPath(packageDirPath + "/" + relPathToPackageDir);
          if (file != null) {
            return file;
          }
        }
      }
    }

    if (url.startsWith(FILE_PREFIX)) {
      final String path = StringUtil.trimLeading(url.substring(FILE_PREFIX.length()), '/');
      return LocalFileSystem.getInstance().findFileByPath(SystemInfo.isWindows ? path : ("/" + path));
    }

    if (ApplicationManager.getApplication().isUnitTestMode() && url.startsWith(TEMP_PREFIX)) {
      return TempFileSystem.getInstance().findFileByPath(url.substring((TEMP_PREFIX).length()));
    }

    return null;
  }

  @NotNull
  public String getDartUrlForFile(final @NotNull VirtualFile file) {
    String result = null;

    if (myDartSdk != null) result = getUrlIfFileFromSdkLib(myProject, file, myDartSdk);
    if (result != null) return result;

    result = getUrlIfFileFromLivePackage(file, myLivePackageNameToDirMap);
    if (result != null) return result;

    result = getUrlIfFileFromPackageRoot(file, myPackageRoots);
    if (result != null) return result;

    result = getUrlIfFileFromPubListPackageDirs(myProject, file, myPubListPackageDirsMap);
    if (result != null) return result;

    // see com.google.dart.tools.debug.core.server.ServerBreakpointManager#getAbsoluteUrlForResource()
    return new File(file.getPath()).toURI().toString();
  }

  @Nullable
  private static String getUrlIfFileFromSdkLib(final @NotNull Project project,
                                               final @NotNull VirtualFile file,
                                               final @NotNull DartSdk sdk) {
    final VirtualFile sdkLibFolder = LocalFileSystem.getInstance().findFileByPath(sdk.getHomePath() + "/lib");
    final String relativeToSdkLibFolder = sdkLibFolder == null ? null : VfsUtilCore.getRelativePath(file, sdkLibFolder, '/');
    final String sdkLibName = relativeToSdkLibFolder == null
                              ? null
                              : DartLibraryIndex.getStandardLibraryNameByRelativePath(project, relativeToSdkLibFolder);
    return sdkLibName != null
           ? DART_PREFIX + sdkLibName
           : relativeToSdkLibFolder != null
             ? DART_PREFIX + relativeToSdkLibFolder
             : null;
  }

  @Nullable
  private static String getUrlIfFileFromLivePackage(final @NotNull VirtualFile file,
                                                    final @NotNull Map<String, VirtualFile> livePackageNameToDirMap) {
    for (Map.Entry<String, VirtualFile> entry : livePackageNameToDirMap.entrySet()) {
      final String packageName = entry.getKey();
      final VirtualFile packageDir = entry.getValue();
      final String relPath = VfsUtilCore.getRelativePath(file, packageDir, '/');
      if (relPath != null) {
        return PACKAGE_PREFIX + packageName + "/" + relPath;
      }
    }
    return null;
  }

  @Nullable
  private static String getUrlIfFileFromPackageRoot(final @NotNull VirtualFile file, final @NotNull List<VirtualFile> packageRoots) {
    for (VirtualFile packageRoot : packageRoots) {
      final String relPath = VfsUtilCore.getRelativePath(file, packageRoot, '/');
      if (relPath != null) {
        return PACKAGE_PREFIX + relPath;
      }
    }
    return null;
  }

  @Nullable
  private static String getUrlIfFileFromPubListPackageDirs(final @NotNull Project project,
                                                           final @NotNull VirtualFile file,
                                                           final @NotNull Map<String, Set<String>> pubListPackageDirsMap) {
    final String filePath = file.getPath();

    for (OrderEntry orderEntry : ProjectRootManager.getInstance(project).getFileIndex().getOrderEntriesForFile(file)) {
      if (orderEntry instanceof LibraryOrderEntry &&
          LibraryTablesRegistrar.PROJECT_LEVEL.equals(((LibraryOrderEntry)orderEntry).getLibraryLevel()) &&
          PubListPackageDirsAction.PUB_LIST_PACKAGE_DIRS_LIB_NAME.equals(((LibraryOrderEntry)orderEntry).getLibraryName())) {
        for (Map.Entry<String, Set<String>> mapEntry : pubListPackageDirsMap.entrySet()) {
          for (String dirPath : mapEntry.getValue()) {
            if (filePath.startsWith(dirPath + "/")) {
              final String packageName = mapEntry.getKey();
              return PACKAGE_PREFIX + packageName + filePath.substring(dirPath.length());
            }
          }
        }
        return null;
      }
    }
    return null;
  }

  @Nullable
  private VirtualFile initPackageRootsAndReturnPubspecYamlFile(final @NotNull VirtualFile contextFile) {
    final Module module = ModuleUtilCore.findModuleForFile(contextFile, myProject);
    if (module == null) return null;

    final VirtualFile[] customPackageRoots = DartConfigurable.getCustomPackageRoots(module);
    if (customPackageRoots.length > 0) {
      Collections.addAll(myPackageRoots, customPackageRoots);
      return null;
    }

    final VirtualFile pubspecYamlFile = findPubspecYamlFile(myProject, contextFile);
    final VirtualFile parentFolder = pubspecYamlFile == null ? null : pubspecYamlFile.getParent();
    final VirtualFile packagesFolder = parentFolder == null ? null : parentFolder.findChild(PACKAGES_FOLDER_NAME);
    if (packagesFolder != null && packagesFolder.isDirectory()) {
      myPackageRoots.add(packagesFolder);
    }

    return pubspecYamlFile;
  }

  private void initLivePackageNameToDirMap() {
    if (myPubspecYamlFile == null) return;

    final VirtualFile baseDir = myPubspecYamlFile.getParent();
    final Map<String, Object> yamlInfo = getPubspecYamlInfo(myPubspecYamlFile);
    if (baseDir != null && yamlInfo != null) {
      fillLivePackageNameToDirMap(myProject, myLivePackageNameToDirMap, baseDir, yamlInfo);
    }
  }

  private static void fillLivePackageNameToDirMap(final @NotNull Project project,
                                                  final @NotNull Map<String, VirtualFile> packageNameToDirMap,
                                                  final @NotNull VirtualFile baseDir,
                                                  final @NotNull Map<String, Object> yamlInfo) {
    final Object name = yamlInfo.get(NAME);
    final VirtualFile libFolder = baseDir.findChild(LIB_DIRECTORY_NAME);
    if (name instanceof String && libFolder != null && libFolder.isDirectory()) {
      packageNameToDirMap.put((String)name, libFolder);
    }

    addPathPackagesToMap(project, packageNameToDirMap, yamlInfo.get(DEPENDENCIES), baseDir);
    addPathPackagesToMap(project, packageNameToDirMap, yamlInfo.get(DEV_DEPENDENCIES), baseDir);
  }

  // Path packages: https://www.dartlang.org/tools/pub/dependencies.html#path-packages
  private static void addPathPackagesToMap(final @NotNull Project project,
                                           final @NotNull Map<String, VirtualFile> packageNameToDirMap,
                                           final @Nullable Object yamlDep,
                                           final @NotNull VirtualFile baseDir) {
    // see com.google.dart.tools.core.pub.PubspecModel#processDependencies
    if (!(yamlDep instanceof Map)) return;

    final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
    //noinspection unchecked
    for (Map.Entry<String, Object> packageEntry : ((Map<String, Object>)yamlDep).entrySet()) {
      final String packageName = packageEntry.getKey();

      final Object packageEntryValue = packageEntry.getValue();
      if (packageEntryValue instanceof Map) {
        final Object pathObj = ((Map)packageEntryValue).get(PATH);
        if (pathObj instanceof String) {
          final VirtualFile packageFolder = VfsUtilCore.findRelativeFile(pathObj + "/" + LIB_DIRECTORY_NAME, baseDir);
          if (packageFolder != null && packageFolder.isDirectory() && fileIndex.isInContent(packageFolder)) {
            packageNameToDirMap.put(packageName, packageFolder);
          }
        }
      }
    }
  }

  private void initPubListPackageDirsMap(final @NotNull VirtualFile contextFile) {
    final Module module = ModuleUtilCore.findModuleForFile(contextFile, myProject);

    final List<OrderEntry> orderEntries = module != null
                                          ? Arrays.asList(ModuleRootManager.getInstance(module).getOrderEntries())
                                          : ProjectRootManager.getInstance(myProject).getFileIndex().getOrderEntriesForFile(contextFile);
    for (OrderEntry orderEntry : orderEntries) {
      if (orderEntry instanceof LibraryOrderEntry &&
          LibraryTablesRegistrar.PROJECT_LEVEL.equals(((LibraryOrderEntry)orderEntry).getLibraryLevel()) &&
          PubListPackageDirsAction.PUB_LIST_PACKAGE_DIRS_LIB_NAME.equals(((LibraryOrderEntry)orderEntry).getLibraryName())) {
        final LibraryEx library =
          (LibraryEx)ProjectLibraryTable.getInstance(myProject).getLibraryByName(PubListPackageDirsAction.PUB_LIST_PACKAGE_DIRS_LIB_NAME);
        final LibraryProperties properties = library == null ? null : library.getProperties();

        if (properties instanceof DartListPackageDirsLibraryProperties) {
          myPubListPackageDirsMap.putAll(((DartListPackageDirsLibraryProperties)properties).getPackageNameToDirsMap());
          return;
        }
      }
    }
  }
}
TOP

Related Classes of com.jetbrains.lang.dart.util.DartUrlResolverImpl

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.