package com.siberika.idea.pascal.util; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.search.FileTypeIndex; import com.intellij.psi.search.FilenameIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.SmartList; import com.intellij.util.containers.ArrayListSet; import com.intellij.util.indexing.FileBasedIndex; import com.siberika.idea.pascal.PascalFileType; import com.siberika.idea.pascal.jps.util.FileUtil; import com.siberika.idea.pascal.module.PascalModuleType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; /** * Author: George Bakhtadze * Date: 26/11/2013 */ public class ModuleUtil { private static final List<String> INCLUDE_EXTENSIONS = Arrays.asList(null, "pas", "pp", "Pas", "Pp", "PAS", "PP"); public static Collection<VirtualFile> getAllModuleFilesByExt(@Nullable Module module, @NotNull String extension) { if (module != null) { return FilenameIndex.getAllFilesByExt(module.getProject(), extension, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)); } else { return Collections.emptyList(); } } /* 1. Search for the original file name, 2. Search for the filename all lowercased. 3. Search for the filename all uppercased. Unit names that are longer than 8 characters will first be looked for with their full length. If the unit is not found with this name, the name will be truncated to 8 characters. */ public static Collection<VirtualFile> getAllCompiledModuleFilesByName(@NotNull final Module module, @NotNull final String name, final FileType fileType) { return ApplicationManager.getApplication().runReadAction(new Computable<Collection<VirtualFile>>() { @Override public Collection<VirtualFile> compute() { Collection<VirtualFile> res = new SmartList<VirtualFile>(); Set<String> nameVariants = new ArrayListSet<String>(); String nameExt = name + "." + fileType.getDefaultExtension(); nameVariants.add(nameExt); nameVariants.add(nameExt.toUpperCase()); nameVariants.add(nameExt.toLowerCase()); if (name.length() > 8) { nameVariants.add(name.substring(0, 8) + "." + fileType.getDefaultExtension()); } for (String unitName : nameVariants) { res.addAll(FileBasedIndex.getInstance().getContainingFiles(FilenameIndex.NAME, unitName, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module))); } return res; } }); } /** * Returns module for the specified library file * @param project - project which the file belongs to * @param file - library file to check * @return module for the file or null if not found */ public static Module getModuleForLibraryFile(Project project, VirtualFile file) { for (Module module : ModuleManager.getInstance(project).getModules()) { if (ModuleUtilCore.moduleContainsFile(module, file, true)) { return module; } } return null; } public static Collection<VirtualFile> getCompiledByNameNoCase(final Module module, String unitName, final FileType fileType) { final String fullName = unitName + "." + fileType.getDefaultExtension(); return ApplicationManager.getApplication().runReadAction(new Computable<Collection<VirtualFile>>() { @Override public Collection<VirtualFile> compute() { Collection<VirtualFile> res = new SmartList<VirtualFile>(); for (VirtualFile file : FileBasedIndex.getInstance().getContainingFiles(FileTypeIndex.NAME, fileType, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module))) { if (fullName.equalsIgnoreCase(file.getName())) { res.add(file); } } return res; } }); } /** * Locates file specified in include directive and its full file name trying the following: * 1. if name specifies an absolute path return it * 2. search in the directory where the current source file is located * 3. search in all paths in search path * if name doesn't include file extension and file doesn't exists ".pas" and ".pp" are tried sequentially * @param project - used to retrieve list of search paths project * @param referencing - file which references to the include * @param name - name found in include directive * @return file name or null if not found */ public static VirtualFile getIncludedFile(Project project, VirtualFile referencing, String name) { File file = new File(name); if (file.isAbsolute()) { return tryExtensions(file); } if (referencing != null) { // if referencing virtual file is known if (referencing.getParent() != null) { String path = referencing.getParent().getPath(); VirtualFile res = tryExtensions(new File(path, name)); if (res != null) { return res; } } else { //System.out.println(String.format("*** Parent of file %s is null", referencing.getName())); } Module module = com.intellij.openapi.module.ModuleUtil.findModuleForFile(referencing, project); return module != null ? trySearchPath(name, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false)) : null; } else { // often lexer can't determine which virtual file is referencing the include return trySearchPath(name, GlobalSearchScope.projectScope(project)); } } private static VirtualFile trySearchPath(String name, GlobalSearchScope filter) { Collection<VirtualFile> virtualFiles = FileBasedIndex.getInstance().getContainingFiles(FileTypeIndex.NAME, PascalFileType.INSTANCE, filter); for (VirtualFile virtualFile : virtualFiles) { String ext = FileUtil.getExtension(name); if (ext != null) { if (name.equalsIgnoreCase(virtualFile.getName())) { return virtualFile; } } else if (name.equalsIgnoreCase(virtualFile.getNameWithoutExtension())) { if (INCLUDE_EXTENSIONS.contains(virtualFile.getExtension())) { return virtualFile; } } } return null; } private static VirtualFile tryExtensions(File file) { if (!file.isFile() && (FileUtil.getExtension(file.getName()) == null)) { String filename = file.getPath(); file = new File(filename + "." + INCLUDE_EXTENSIONS.get(1)); if (!file.isFile()) { file = new File(filename + "." + INCLUDE_EXTENSIONS.get(2)); } } return FileUtil.getVirtualFile(file.getPath()); } public static boolean hasPascalModules(Project project) { Module[] modules = ModuleManager.getInstance(project).getModules(); for (Module module : modules) { if (PascalModuleType.isPascalModule(module)) { return true; } } return false; } }