/*
* Copyright 2012-2014 Sergey Ignatov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.intellij.erlang.utils;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleFileIndex;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
import org.intellij.erlang.ErlangFileType;
import org.intellij.erlang.index.ErlangModuleIndex;
import org.intellij.erlang.psi.ErlangFile;
import org.intellij.erlang.psi.ErlangModule;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
public final class ErlangModulesUtil {
private ErlangModulesUtil() {
}
@NotNull
public static GlobalSearchScope getModuleWithDependenciesScope(@NotNull Module module, boolean includeTests) {
return GlobalSearchScope
.moduleWithDependenciesAndLibrariesScope(module, includeTests)
.intersectWith(GlobalSearchScope.moduleWithDependenciesScope(module));
}
@Nullable
public static ErlangModule getErlangModule(@NotNull final Project project,
@NotNull final String moduleName,
@NotNull final GlobalSearchScope scope) {
return ApplicationManager.getApplication().runReadAction((Computable<ErlangModule>) () -> doGetErlangModule(project, moduleName, scope));
}
@Nullable
public static ErlangFile getErlangModuleFile(@NotNull final Project project,
@NotNull final String moduleName,
@NotNull final GlobalSearchScope scope) {
return ApplicationManager.getApplication().runReadAction((Computable<ErlangFile>) () -> {
ErlangModule module = doGetErlangModule(project, moduleName, scope);
PsiFile containingFile = module != null ? module.getContainingFile() : null;
return containingFile instanceof ErlangFile ? (ErlangFile) containingFile : null;
});
}
@Nullable
private static ErlangModule doGetErlangModule(@NotNull Project project,
@NotNull String moduleName,
@NotNull GlobalSearchScope scope) {
List<ErlangModule> modules = ErlangModuleIndex.getModulesByName(project, moduleName, scope);
return ContainerUtil.getFirstItem(modules);
}
@NotNull
public static Collection<ErlangFile> getErlangModules(@NotNull Project project) {
HashSet<ErlangFile> erlangModules = new HashSet<>();
for (Module module : ModuleManager.getInstance(project).getModules()) {
addErlangFiles(module, false, erlangModules, ErlangFileType.MODULE);
}
return erlangModules;
}
@NotNull
public static Collection<ErlangFile> getErlangModules(@NotNull Module module, boolean onlyTestModules) {
return addErlangFiles(module, onlyTestModules, new HashSet<>(), ErlangFileType.MODULE);
}
@NotNull
public static Collection<VirtualFile> getErlangHeaderFiles(@NotNull Module module, boolean onlyTestModules) {
return addFiles(module, onlyTestModules, ContainerUtil.<VirtualFile>newHashSet(), ErlangFileType.HEADER);
}
@NotNull
public static Collection<VirtualFile> getErlangModuleFiles(@NotNull Module module, boolean onlyTestModules) {
return addFiles(module, onlyTestModules, ContainerUtil.<VirtualFile>newHashSet(), ErlangFileType.MODULE);
}
@NotNull
private static Collection<ErlangFile> addErlangFiles(@NotNull Module module,
boolean onlyTestModules,
@NotNull Collection<ErlangFile> erlangModules,
@NotNull ErlangFileType type) {
Processor<VirtualFile> filesCollector = getErlangModulesCollector(PsiManager.getInstance(module.getProject()), erlangModules, type);
collectFiles(module, onlyTestModules, filesCollector);
return erlangModules;
}
@NotNull
private static Collection<VirtualFile> addFiles(@NotNull Module module,
boolean onlyTest,
@NotNull final Collection<VirtualFile> files,
@NotNull final ErlangFileType type) {
Processor<VirtualFile> modulesCollector = virtualFile -> {
if (virtualFile.getFileType() == type) {
files.add(virtualFile);
}
return true;
};
collectFiles(module, onlyTest, modulesCollector);
return files;
}
private static void collectFiles(@NotNull Module module,
boolean onlyTestModules,
@NotNull Processor<VirtualFile> filesCollector) {
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
ModuleFileIndex moduleFileIndex = rootManager.getFileIndex();
Convertor<VirtualFile, Boolean> sourceDirectoriesFilter = onlyTestModules ? getTestDirectoriesFilter(moduleFileIndex)
: getSourceDirectoriesFilter(moduleFileIndex);
for (VirtualFile sourceRoot : rootManager.getSourceRoots(onlyTestModules)) {
VfsUtilCore.processFilesRecursively(sourceRoot, filesCollector, sourceDirectoriesFilter);
}
}
@NotNull
private static Convertor<VirtualFile, Boolean> getSourceDirectoriesFilter(@NotNull final ModuleFileIndex moduleFileIndex) {
return moduleFileIndex::isInSourceContent;
}
@NotNull
private static Convertor<VirtualFile, Boolean> getTestDirectoriesFilter(@NotNull final ModuleFileIndex moduleFileIndex) {
return moduleFileIndex::isInTestSourceContent;
}
@Nullable
private static Processor<VirtualFile> getErlangModulesCollector(@NotNull final PsiManager psiManager,
@NotNull final Collection<ErlangFile> erlangFiles,
@NotNull final ErlangFileType type) {
return virtualFile -> {
if (virtualFile.getFileType() == type) {
PsiFile psiFile = psiManager.findFile(virtualFile);
if (psiFile instanceof ErlangFile) {
erlangFiles.add((ErlangFile) psiFile);
}
}
return true;
};
}
}