package com.github.masahirosuzuka.PhoneGapIntelliJPlugin;
import com.github.masahirosuzuka.PhoneGapIntelliJPlugin.externalToolsDetector.PhoneGapExecutableChecker;
import com.github.masahirosuzuka.PhoneGapIntelliJPlugin.settings.PhoneGapSettings;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.VirtualFileListener;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
import static com.github.masahirosuzuka.PhoneGapIntelliJPlugin.PhoneGapUtil.FOLDER_PLATFORMS;
import static com.github.masahirosuzuka.PhoneGapIntelliJPlugin.PhoneGapUtil.FOLDER_WWW;
import static com.github.masahirosuzuka.PhoneGapIntelliJPlugin.PhoneGapUtil.IONIC_CONFIG;
import static com.intellij.openapi.roots.ModuleRootModificationUtil.updateExcludedFolders;
public class PhoneGapStartupActivity implements StartupActivity {
@Override
public void runActivity(@NotNull Project project) {
StartupManager.getInstance(project).runWhenProjectIsInitialized(() -> {
if (PhoneGapUtil.isPhoneGapProject(project)) {
if (PhoneGapSettings.getInstance().isExcludePlatformFolder()) {
excludeWorkingDirectories(project);
}
PhoneGapExecutableChecker.check(project);
}
});
VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileListener() {
@Override
public void fileCreated(@NotNull VirtualFileEvent event) {
if (!isProcess(event)) {
return;
}
updateModuleExcludeByFSEvent(project, event, ContainerUtil.newHashSet(), ContainerUtil.newHashSet(getExcludedFolderNames(event)));
}
@Override
public void beforeFileDeletion(@NotNull VirtualFileEvent event) {
if (!isProcess(event)) {
return;
}
updateModuleExcludeByFSEvent(project, event, getExcludedFolderNames(event), ContainerUtil.newHashSet());
}
private boolean isProcess(@NotNull VirtualFileEvent event) {
return shouldExcludeDirectory(event) &&
PhoneGapUtil.isPhoneGapProject(project) &&
PhoneGapSettings.getInstance().isExcludePlatformFolder();
}
}, project);
}
private static boolean shouldExcludeDirectory(@NotNull VirtualFileEvent event) {
String name = event.getFileName();
VirtualFile file = event.getFile();
return shouldExcludeDirectory(name, file);
}
private static boolean shouldExcludeDirectory(@NotNull String name, @NotNull VirtualFile file) {
if (!file.isDirectory()) return false;
if (name.equals(FOLDER_PLATFORMS)) return true;
if (!name.equals(FOLDER_WWW)) return false;
VirtualFile candidateParent = file.getParent();
if (candidateParent == null || !candidateParent.isValid()) return false;
return candidateParent.findChild(IONIC_CONFIG) != null;
}
private static Set<String> getExcludedFolderNames(@NotNull VirtualFileEvent event) {
return ContainerUtil.newHashSet(event.getFile().getUrl());
}
private static void updateModuleExcludeByFSEvent(@NotNull Project project,
@NotNull VirtualFileEvent event,
@NotNull Set<String> oldToUpdateFolders,
@NotNull Set<String> newToUpdateFolders) {
VirtualFile eventFile = event.getFile();
Module module = ModuleUtilCore.findModuleForFile(eventFile, project);
if (module == null) {
return;
}
VirtualFile directory = event.getParent();
VirtualFile contentRoot = getContentRoot(module, directory);
if (contentRoot == null) {
return;
}
updateExcludedFolders(module, contentRoot, oldToUpdateFolders, newToUpdateFolders);
}
private static void excludeWorkingDirectories(@NotNull Project project) {
final Collection<VirtualFile> platformsDirectories = FilenameIndex.getVirtualFilesByName(project,
FOLDER_PLATFORMS,
GlobalSearchScope.projectScope(project));
for (VirtualFile directory : platformsDirectories) {
excludeFolder(project, directory);
}
final Collection<VirtualFile> wwwDirectories = FilenameIndex.getVirtualFilesByName(project,
FOLDER_WWW,
GlobalSearchScope.projectScope(project));
for (VirtualFile directory : wwwDirectories) {
if (shouldExcludeDirectory(directory.getName(), directory)) {
excludeFolder(project, directory);
}
}
}
public static void excludeFolder(@NotNull Project project, @NotNull VirtualFile directoryToExclude) {
Module module = ModuleUtilCore.findModuleForFile(directoryToExclude, project);
if (module == null) {
return;
}
VirtualFile contentRoot = getContentRoot(module, directoryToExclude);
if (contentRoot == null) return;
Collection<String> oldExcludedFolders = getOldExcludedFolders(module, directoryToExclude);
if (oldExcludedFolders.size() == 1 && oldExcludedFolders.contains(directoryToExclude.getUrl())) return;
updateExcludedFolders(module, contentRoot, oldExcludedFolders, ContainerUtil.newHashSet(directoryToExclude.getUrl()));
}
private static Collection<String> getOldExcludedFolders(@NotNull Module module, @NotNull final VirtualFile root) {
return ContainerUtil.filter(ModuleRootManager.getInstance(module).getExcludeRootUrls(), url -> url.startsWith(root.getUrl()));
}
private static VirtualFile getContentRoot(@NotNull Module module, @Nullable VirtualFile root) {
return root == null ? null : ProjectRootManager.getInstance(module.getProject()).getFileIndex().getContentRootForFile(root);
}
}