mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
project model: support excluding file from content roots by pattern (IDEA-127753)
Currently only file/directory names, not relative paths, are matched.
This commit is contained in:
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* 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 com.intellij.openapi.roots.impl;
|
||||
|
||||
import com.intellij.ide.projectView.actions.MarkRootActionBase;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class DirectoryIndexForExcludePatternsTest extends DirectoryIndexTestCase {
|
||||
private VirtualFile myContentRoot;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
final File root = createTempDirectory();
|
||||
myContentRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(root);
|
||||
ModuleRootModificationUtil.addContentRoot(myModule, myContentRoot.getPath());
|
||||
}
|
||||
|
||||
public void testExcludeFileByExtension() {
|
||||
addExcludePattern("*.txt");
|
||||
VirtualFile dir = createChildDirectory(myContentRoot, "dir");
|
||||
VirtualFile txt1 = createChildData(myContentRoot, "a.txt");
|
||||
VirtualFile txt2 = createChildData(dir, "a.txt");
|
||||
VirtualFile java1 = createChildData(myContentRoot, "A.java");
|
||||
VirtualFile java2 = createChildData(dir, "A.java");
|
||||
assertExcluded(txt1, myModule);
|
||||
assertExcluded(txt2, myModule);
|
||||
assertNotExcluded(java1);
|
||||
assertNotExcluded(java2);
|
||||
assertIteratedContent(myModule, Arrays.asList(java1, java2), Arrays.asList(txt1, txt2));
|
||||
}
|
||||
|
||||
public void testExcludeDirectoryByName() {
|
||||
addExcludePattern("exc");
|
||||
VirtualFile dir = createChildDirectory(myContentRoot, "dir");
|
||||
VirtualFile exc = createChildDirectory(myContentRoot, "exc");
|
||||
VirtualFile dirUnderExc = createChildDirectory(exc, "dir2");
|
||||
VirtualFile excUnderDir = createChildDirectory(dir, "exc");
|
||||
VirtualFile underExc = createChildData(exc, "a.txt");
|
||||
VirtualFile underDir = createChildData(dir, "a.txt");
|
||||
VirtualFile underExcUnderDir = createChildData(excUnderDir, "a.txt");
|
||||
VirtualFile underDirUnderExc = createChildData(dirUnderExc, "a.txt");
|
||||
assertExcluded(exc, myModule);
|
||||
assertExcluded(underExc, myModule);
|
||||
assertExcluded(dirUnderExc, myModule);
|
||||
assertExcluded(underDirUnderExc, myModule);
|
||||
assertExcluded(underExcUnderDir, myModule);
|
||||
assertNotExcluded(dir);
|
||||
assertNotExcluded(underDir);
|
||||
assertIteratedContent(myModule, Arrays.asList(underDir), Arrays.asList(underExc, underDirUnderExc, underExcUnderDir));
|
||||
}
|
||||
|
||||
private void addExcludePattern(@NotNull String pattern) {
|
||||
ModuleRootModificationUtil.updateModel(myModule,
|
||||
model -> MarkRootActionBase.findContentEntry(model, myContentRoot).addExcludePattern(pattern));
|
||||
}
|
||||
}
|
||||
@@ -18,13 +18,20 @@ package com.intellij.roots;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.roots.*;
|
||||
import com.intellij.openapi.roots.impl.ContentEntryImpl;
|
||||
import com.intellij.openapi.roots.impl.ModuleRootManagerComponent;
|
||||
import com.intellij.openapi.roots.impl.ModuleRootManagerImpl;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.testFramework.IdeaTestCase;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.intellij.testFramework.assertions.Assertions.assertThat;
|
||||
|
||||
public class ManagingContentRootsTest extends IdeaTestCase {
|
||||
private VirtualFile dir;
|
||||
|
||||
@@ -90,6 +97,36 @@ public class ManagingContentRootsTest extends IdeaTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
public void testAddExcludePattern() {
|
||||
PsiTestUtil.addContentRoot(myModule, dir);
|
||||
ModuleRootModificationUtil.updateModel(myModule, model -> findContentEntry(dir.getUrl(), model).addExcludePattern("*.txt"));
|
||||
assertEquals("*.txt", assertOneElement(findContentEntry(dir.getUrl()).getExcludePatterns()));
|
||||
ModuleRootModificationUtil.updateModel(myModule, model -> findContentEntry(dir.getUrl(), model).removeExcludePattern("*.txt"));
|
||||
assertEmpty(findContentEntry(dir.getUrl()).getExcludePatterns());
|
||||
}
|
||||
|
||||
public void testExcludePatternSerialization() {
|
||||
PsiTestUtil.addContentRoot(myModule, dir);
|
||||
ModuleRootModificationUtil.updateModel(myModule, model -> findContentEntry(dir.getUrl(), model).addExcludePattern("exc"));
|
||||
Element entry = new Element(ContentEntryImpl.ELEMENT_NAME);
|
||||
((ContentEntryImpl)findContentEntry(dir.getUrl())).writeExternal(entry);
|
||||
String elementText = "<content url=\"" + dir.getUrl() + "\">\n" +
|
||||
" <excludePattern pattern=\"exc\" />\n" +
|
||||
"</content>";
|
||||
assertThat(entry).isEqualTo(elementText);
|
||||
}
|
||||
|
||||
public void testExcludePatternDeserialization() throws IOException, JDOMException {
|
||||
ModuleRootManagerImpl.ModuleRootManagerState state = new ModuleRootManagerImpl.ModuleRootManagerState();
|
||||
state.readExternal(JDOMUtil.load("<component name=\"NewModuleRootManager\">" +
|
||||
" <content url=\"" + dir.getUrl() + "\">\n" +
|
||||
" <excludePattern pattern=\"exc\" />\n" +
|
||||
" </content>" +
|
||||
"</component>\n"));
|
||||
((ModuleRootManagerComponent)getRootManager()).loadState(state);
|
||||
assertEquals("exc", assertOneElement(findContentEntry(dir.getUrl()).getExcludePatterns()));
|
||||
}
|
||||
|
||||
private ContentEntry findContentEntry(String url) {
|
||||
return findContentEntry(url, getRootManager());
|
||||
}
|
||||
@@ -102,7 +139,7 @@ public class ManagingContentRootsTest extends IdeaTestCase {
|
||||
}
|
||||
|
||||
private void addContentRoot(final String path) {
|
||||
ApplicationManager.getApplication().runWriteAction(() -> ModuleRootModificationUtil.addContentRoot(getModule(), path));
|
||||
ModuleRootModificationUtil.addContentRoot(getModule(), path);
|
||||
}
|
||||
|
||||
private ModuleRootManager getRootManager() {
|
||||
|
||||
+1
-1
@@ -134,7 +134,7 @@ private class DefaultWebServerRootsProvider : WebServerRootsProvider() {
|
||||
val directoryIndex = DirectoryIndex.getInstance(project)
|
||||
val info = directoryIndex.getInfoForFile(file)
|
||||
// we serve excluded files
|
||||
if (!info.isExcluded && !info.isInProject) {
|
||||
if (!info.isExcluded(file) && !info.isInProject(file)) {
|
||||
// javadoc jars is "not under project", but actually is, so, let's check library or SDK
|
||||
if (file.fileSystem == JarFileSystem.getInstance()) getInfoForDocJar(file, project) else null
|
||||
}
|
||||
|
||||
+2
-2
@@ -226,7 +226,7 @@ public class ProjectViewDirectoryHelper {
|
||||
DirectoryInfo info = myIndex.getInfoForFile(parent);
|
||||
if (!module.equals(info.getModule())) return true;
|
||||
//show inner content root separately only if it won't be shown under outer content root
|
||||
return info.isExcluded() && !shouldShowExcludedFiles(settings);
|
||||
return info.isExcluded(parent) && !shouldShowExcludedFiles(settings);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ public class ProjectViewDirectoryHelper {
|
||||
|
||||
private boolean shouldBeShown(VirtualFile dir, ViewSettings settings) {
|
||||
DirectoryInfo directoryInfo = myIndex.getInfoForFile(dir);
|
||||
return directoryInfo.isInProject() || shouldShowExcludedFiles(settings) && directoryInfo.isExcluded();
|
||||
return directoryInfo.isInProject(dir) || shouldShowExcludedFiles(settings) && directoryInfo.isExcluded(dir);
|
||||
}
|
||||
|
||||
private static boolean shouldShowExcludedFiles(ViewSettings settings) {
|
||||
|
||||
@@ -132,7 +132,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
|
||||
@Override
|
||||
public DirectoryInfo getInfoForDirectory(@NotNull VirtualFile dir) {
|
||||
DirectoryInfo info = getInfoForFile(dir);
|
||||
return info.isInProject() ? info : null;
|
||||
return info.isInProject(dir) ? info : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -193,4 +193,15 @@ public interface ContentEntry extends Synthetic {
|
||||
boolean removeExcludeFolder(@NotNull String url);
|
||||
|
||||
void clearExcludeFolders();
|
||||
|
||||
/**
|
||||
* Returns patterns for names of files which should be excluded from this content root. If name of a file under this content root matches
|
||||
* any of the patterns it'll be excluded from the module, if name of a directory matches any of the patterns the directory and all of its
|
||||
* contents will be excluded. '?' and '*' wildcards are supported.
|
||||
*/
|
||||
@NotNull
|
||||
List<String> getExcludePatterns();
|
||||
|
||||
void addExcludePattern(@NotNull String pattern);
|
||||
void removeExcludePattern(@NotNull String pattern);
|
||||
}
|
||||
|
||||
+39
-1
@@ -55,6 +55,7 @@ public class ContentEntryImpl extends RootModelComponentBase implements ContentE
|
||||
private final Set<SourceFolder> mySourceFolders = new LinkedHashSet<>();
|
||||
private final Set<ExcludeFolder> myExcludeFolders = new TreeSet<>(ContentFolderComparator.INSTANCE);
|
||||
@NonNls public static final String URL_ATTRIBUTE = JpsModuleRootModelSerializer.URL_ATTRIBUTE;
|
||||
private List<String> myExcludePatterns;
|
||||
|
||||
ContentEntryImpl(@NotNull VirtualFile file, @NotNull RootModelImpl m) {
|
||||
this(file.getUrl(), m);
|
||||
@@ -69,6 +70,9 @@ public class ContentEntryImpl extends RootModelComponentBase implements ContentE
|
||||
this(getUrlFrom(e), m);
|
||||
initSourceFolders(e);
|
||||
initExcludeFolders(e);
|
||||
for (Element element : e.getChildren(JpsModuleRootModelSerializer.EXCLUDE_PATTERN_TAG)) {
|
||||
addExcludePattern(element.getAttributeValue(JpsModuleRootModelSerializer.EXCLUDE_PATTERN_ATTRIBUTE));
|
||||
}
|
||||
}
|
||||
|
||||
private static String getUrlFrom(@NotNull Element e) throws InvalidDataException {
|
||||
@@ -312,6 +316,30 @@ public class ContentEntryImpl extends RootModelComponentBase implements ContentE
|
||||
myExcludeFolders.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getExcludePatterns() {
|
||||
return myExcludePatterns != null ? myExcludePatterns : Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addExcludePattern(@NotNull String pattern) {
|
||||
if (myExcludePatterns == null) {
|
||||
myExcludePatterns = new SmartList<>();
|
||||
}
|
||||
myExcludePatterns.add(pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeExcludePattern(@NotNull String pattern) {
|
||||
if (myExcludePatterns != null) {
|
||||
myExcludePatterns.remove(pattern);
|
||||
if (myExcludePatterns.isEmpty()) {
|
||||
myExcludePatterns = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ExcludeFolder addExcludeFolder(ExcludeFolder f) {
|
||||
Disposer.register(this, (Disposable)f);
|
||||
myExcludeFolders.add(f);
|
||||
@@ -355,6 +383,10 @@ public class ContentEntryImpl extends RootModelComponentBase implements ContentE
|
||||
}
|
||||
}
|
||||
|
||||
for (String pattern : getExcludePatterns()) {
|
||||
cloned.addExcludePattern(pattern);
|
||||
}
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
@@ -375,6 +407,10 @@ public class ContentEntryImpl extends RootModelComponentBase implements ContentE
|
||||
element.addContent(subElement);
|
||||
}
|
||||
}
|
||||
|
||||
for (String pattern : getExcludePatterns()) {
|
||||
element.addContent(new Element(JpsModuleRootModelSerializer.EXCLUDE_PATTERN_TAG).setAttribute(JpsModuleRootModelSerializer.EXCLUDE_PATTERN_ATTRIBUTE, pattern));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ContentFolderComparator implements Comparator<ContentFolder> {
|
||||
@@ -392,6 +428,8 @@ public class ContentEntryImpl extends RootModelComponentBase implements ContentE
|
||||
if (i != 0) return i;
|
||||
i = ArrayUtil.lexicographicCompare(getSourceFolders(), other.getSourceFolders());
|
||||
if (i != 0) return i;
|
||||
return ArrayUtil.lexicographicCompare(getExcludeFolders(), other.getExcludeFolders());
|
||||
i = ArrayUtil.lexicographicCompare(getExcludeFolders(), other.getExcludeFolders());
|
||||
if (i != 0) return i;
|
||||
return ContainerUtil.compareLexicographically(getExcludePatterns(), other.getExcludePatterns());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,25 +17,39 @@
|
||||
package com.intellij.openapi.roots.impl;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.ContentEntry;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class DirectoryInfo {
|
||||
/**
|
||||
* @return {@code true} if located under project content or library roots and not excluded or ignored
|
||||
* @return {@code true} if the whole directory is located under project content or library roots and not excluded or ignored
|
||||
* @deprecated use {@link #isInProject(VirtualFile)} instead, this method doesn't take {@link ContentEntry#getExcludePatterns()} into account
|
||||
*/
|
||||
public abstract boolean isInProject();
|
||||
|
||||
/**
|
||||
* @return {@code true} if {@code file} is located under project content or library roots and not excluded or ignored
|
||||
*/
|
||||
public abstract boolean isInProject(@NotNull VirtualFile file);
|
||||
|
||||
/**
|
||||
* @return {@code true} if located under ignored directory
|
||||
*/
|
||||
public abstract boolean isIgnored();
|
||||
|
||||
/**
|
||||
* @return {@code true} if located project content, output or library root but excluded from the project
|
||||
* @return {@code true} if the whole directory is located in project content, output or library root but excluded from the project
|
||||
* @deprecated use {@link #isExcluded(VirtualFile)} instead, this method doesn't take {@link ContentEntry#getExcludePatterns()} into account
|
||||
*/
|
||||
public abstract boolean isExcluded();
|
||||
|
||||
/**
|
||||
* @return {@code true} if {@code file} located under this directory is excluded from the project.
|
||||
*/
|
||||
public abstract boolean isExcluded(@NotNull VirtualFile file);
|
||||
|
||||
public abstract boolean isInModuleSource();
|
||||
|
||||
public abstract boolean isInLibrarySource();
|
||||
|
||||
+14
-4
@@ -25,14 +25,14 @@ import org.jetbrains.annotations.Nullable;
|
||||
*/
|
||||
public class DirectoryInfoImpl extends DirectoryInfo {
|
||||
public static final int MAX_ROOT_TYPE_ID = Byte.MAX_VALUE;
|
||||
private final VirtualFile myRoot;//original project root for which this information is calculated
|
||||
protected final VirtualFile myRoot;//original project root for which this information is calculated
|
||||
private final Module module; // module to which content it belongs or null
|
||||
private final VirtualFile libraryClassRoot; // class root in library
|
||||
private final VirtualFile contentRoot;
|
||||
private final VirtualFile sourceRoot;
|
||||
private final boolean myInModuleSource;
|
||||
private final boolean myInLibrarySource;
|
||||
private final boolean myExcluded;
|
||||
protected final boolean myExcluded;
|
||||
private final byte mySourceRootTypeId;
|
||||
|
||||
DirectoryInfoImpl(@NotNull VirtualFile root, Module module, VirtualFile contentRoot, VirtualFile sourceRoot, VirtualFile libraryClassRoot,
|
||||
@@ -72,7 +72,7 @@ public class DirectoryInfoImpl extends DirectoryInfo {
|
||||
", isInModuleSource=" + isInModuleSource() +
|
||||
", rootTypeId=" + getSourceRootTypeId() +
|
||||
", isInLibrarySource=" + isInLibrarySource() +
|
||||
", isExcludedFromModule=" + isExcluded() +
|
||||
", isExcludedFromModule=" + myExcluded +
|
||||
", libraryClassRoot=" + getLibraryClassRoot() +
|
||||
", contentRoot=" + getContentRoot() +
|
||||
", sourceRoot=" + getSourceRoot() +
|
||||
@@ -80,7 +80,12 @@ public class DirectoryInfoImpl extends DirectoryInfo {
|
||||
}
|
||||
|
||||
public boolean isInProject() {
|
||||
return !isExcluded();
|
||||
return !myExcluded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInProject(@NotNull VirtualFile file) {
|
||||
return !isExcluded(file);
|
||||
}
|
||||
|
||||
public boolean isIgnored() {
|
||||
@@ -113,6 +118,11 @@ public class DirectoryInfoImpl extends DirectoryInfo {
|
||||
return myExcluded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExcluded(@NotNull VirtualFile file) {
|
||||
return myExcluded;
|
||||
}
|
||||
|
||||
public Module getModule() {
|
||||
return module;
|
||||
}
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* 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 com.intellij.openapi.roots.impl;
|
||||
|
||||
import com.intellij.openapi.fileTypes.impl.FileTypeAssocTable;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class DirectoryInfoWithExcludePatterns extends DirectoryInfoImpl {
|
||||
private final FileTypeAssocTable<Boolean> myExcludePatterns;
|
||||
|
||||
public DirectoryInfoWithExcludePatterns(@NotNull VirtualFile root, Module module, VirtualFile contentRoot, VirtualFile sourceRoot,
|
||||
VirtualFile libraryClassRoot, boolean inModuleSource, boolean inLibrarySource, boolean isExcluded,
|
||||
int sourceRootTypeId, FileTypeAssocTable<Boolean> excludePatterns) {
|
||||
super(root, module, contentRoot, sourceRoot, libraryClassRoot, inModuleSource, inLibrarySource, isExcluded, sourceRootTypeId);
|
||||
myExcludePatterns = excludePatterns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExcluded(@NotNull VirtualFile file) {
|
||||
if (myExcluded) return true;
|
||||
VirtualFile current = file;
|
||||
while (!myRoot.equals(current)) {
|
||||
if (myExcludePatterns.findAssociatedFileType(current.getNameSequence()) != null) {
|
||||
return true;
|
||||
}
|
||||
current = current.getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -51,12 +51,12 @@ public class ModuleFileIndexImpl extends FileIndexBase implements ModuleFileInde
|
||||
for (VirtualFile[] roots : allRoots) {
|
||||
for (VirtualFile root : roots) {
|
||||
DirectoryInfo info = getInfoForFileOrDirectory(root);
|
||||
if (!info.isInProject()) continue;
|
||||
if (!info.isInProject(root)) continue;
|
||||
|
||||
VirtualFile parent = root.getParent();
|
||||
if (parent != null) {
|
||||
DirectoryInfo parentInfo = myDirectoryIndex.getInfoForFile(parent);
|
||||
if (parentInfo.isInProject() && myModule.equals(parentInfo.getModule())) continue; // inner content - skip it
|
||||
if (parentInfo.isInProject(parent) && myModule.equals(parentInfo.getModule())) continue; // inner content - skip it
|
||||
}
|
||||
result.add(root);
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class ModuleFileIndexImpl extends FileIndexBase implements ModuleFileInde
|
||||
@Override
|
||||
public boolean isInContent(@NotNull VirtualFile fileOrDir) {
|
||||
DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
|
||||
return info.isInProject() && myModule.equals(info.getModule());
|
||||
return info.isInProject(fileOrDir) && myModule.equals(info.getModule());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+11
@@ -17,6 +17,7 @@ package com.intellij.openapi.roots.impl;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -48,6 +49,11 @@ class NonProjectDirectoryInfo extends DirectoryInfo {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInProject(@NotNull VirtualFile file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DirectoryInfo: " + myDebugName;
|
||||
@@ -93,6 +99,11 @@ class NonProjectDirectoryInfo extends DirectoryInfo {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExcluded(@NotNull VirtualFile file) {
|
||||
return isExcluded();
|
||||
}
|
||||
|
||||
public Module getModule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ public class ProjectFileIndexFacade extends FileIndexFacade {
|
||||
while (true) {
|
||||
if (childDir == null) return false;
|
||||
if (childDir.equals(baseDir)) return true;
|
||||
if (!myDirectoryIndex.getInfoForFile(childDir).isInProject()) return false;
|
||||
if (!myDirectoryIndex.getInfoForFile(childDir).isInProject(childDir)) return false;
|
||||
childDir = childDir.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -69,13 +69,13 @@ public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIn
|
||||
for (VirtualFile[] roots : getModuleContentAndSourceRoots(module)) {
|
||||
for (VirtualFile root : roots) {
|
||||
DirectoryInfo info = getInfoForFileOrDirectory(root);
|
||||
if (!info.isInProject()) continue; // is excluded or ignored
|
||||
if (!info.isInProject(root)) continue; // is excluded or ignored
|
||||
if (!module.equals(info.getModule())) continue; // maybe 2 modules have the same content root?
|
||||
|
||||
VirtualFile parent = root.getParent();
|
||||
if (parent != null) {
|
||||
DirectoryInfo parentInfo = getInfoForFileOrDirectory(parent);
|
||||
if (parentInfo.isInProject() && parentInfo.getModule() != null) continue;
|
||||
if (parentInfo.isInProject(parent) && parentInfo.getModule() != null) continue;
|
||||
}
|
||||
result.add(root);
|
||||
}
|
||||
@@ -88,7 +88,7 @@ public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIn
|
||||
@Override
|
||||
public boolean isExcluded(@NotNull VirtualFile file) {
|
||||
DirectoryInfo info = getInfoForFileOrDirectory(file);
|
||||
return info.isIgnored() || info.isExcluded();
|
||||
return info.isIgnored() || info.isExcluded(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,7 +106,7 @@ public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIn
|
||||
public Module getModuleForFile(@NotNull VirtualFile file, boolean honorExclusion) {
|
||||
if (file instanceof VirtualFileWindow) file = ((VirtualFileWindow)file).getDelegate();
|
||||
DirectoryInfo info = getInfoForFileOrDirectory(file);
|
||||
if (info.isInProject() || !honorExclusion && info.isExcluded()) {
|
||||
if (info.isInProject(file) || !honorExclusion && info.isExcluded(file)) {
|
||||
return info.getModule();
|
||||
}
|
||||
return null;
|
||||
@@ -121,14 +121,14 @@ public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIn
|
||||
@Override
|
||||
public VirtualFile getClassRootForFile(@NotNull VirtualFile file) {
|
||||
final DirectoryInfo info = getInfoForFileOrDirectory(file);
|
||||
if (!info.isInProject()) return null;
|
||||
if (!info.isInProject(file)) return null;
|
||||
return info.getLibraryClassRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getSourceRootForFile(@NotNull VirtualFile file) {
|
||||
final DirectoryInfo info = getInfoForFileOrDirectory(file);
|
||||
if (!info.isInProject()) return null;
|
||||
if (!info.isInProject(file)) return null;
|
||||
return info.getSourceRoot();
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIn
|
||||
@Override
|
||||
public VirtualFile getContentRootForFile(@NotNull VirtualFile file, final boolean honorExclusion) {
|
||||
final DirectoryInfo info = getInfoForFileOrDirectory(file);
|
||||
if (info.isInProject() || !honorExclusion && info.isExcluded()) {
|
||||
if (info.isInProject(file) || !honorExclusion && info.isExcluded(file)) {
|
||||
return info.getContentRoot();
|
||||
}
|
||||
return null;
|
||||
@@ -156,7 +156,7 @@ public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIn
|
||||
public boolean isLibraryClassFile(@NotNull VirtualFile file) {
|
||||
if (file.isDirectory()) return false;
|
||||
DirectoryInfo parentInfo = getInfoForFileOrDirectory(file);
|
||||
return parentInfo.isInProject() && parentInfo.hasLibraryClassRoot();
|
||||
return parentInfo.isInProject(file) && parentInfo.hasLibraryClassRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,19 +168,19 @@ public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIn
|
||||
@Override
|
||||
public boolean isInLibraryClasses(@NotNull VirtualFile fileOrDir) {
|
||||
DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
|
||||
return info.isInProject() && info.hasLibraryClassRoot();
|
||||
return info.isInProject(fileOrDir) && info.hasLibraryClassRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInLibrarySource(@NotNull VirtualFile fileOrDir) {
|
||||
DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
|
||||
return info.isInProject() && info.isInLibrarySource();
|
||||
return info.isInProject(fileOrDir) && info.isInLibrarySource();
|
||||
}
|
||||
|
||||
// a slightly faster implementation then the default one
|
||||
public boolean isInLibrary(@NotNull VirtualFile fileOrDir) {
|
||||
DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
|
||||
return info.isInProject() && (info.hasLibraryClassRoot() || info.isInLibrarySource());
|
||||
return info.isInProject(fileOrDir) && (info.hasLibraryClassRoot() || info.isInLibrarySource());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -191,7 +191,7 @@ public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIn
|
||||
@Override
|
||||
public boolean isInContent(@NotNull VirtualFile fileOrDir) {
|
||||
DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
|
||||
return info.isInProject() && info.getModule() != null;
|
||||
return info.isInProject(fileOrDir) && info.getModule() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.openapi.roots.impl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.fileTypes.impl.FileTypeAssocTable;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -38,6 +39,7 @@ import com.intellij.util.containers.SLRUMap;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.model.fileTypes.FileNameMatcherFactory;
|
||||
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
|
||||
|
||||
import java.util.*;
|
||||
@@ -81,7 +83,7 @@ public class RootIndex {
|
||||
myPackageDirectoryCache = new PackageDirectoryCache(rootsByPackagePrefix) {
|
||||
@Override
|
||||
protected boolean isPackageDirectory(@NotNull VirtualFile dir, @NotNull String packageName) {
|
||||
return getInfoForFile(dir).isInProject() && packageName.equals(getPackageName(dir));
|
||||
return getInfoForFile(dir).isInProject(dir) && packageName.equals(getPackageName(dir));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -109,6 +111,14 @@ public class RootIndex {
|
||||
|
||||
info.excludedFromModule.put(excludeRoot, module);
|
||||
}
|
||||
List<String> patterns = contentEntry.getExcludePatterns();
|
||||
if (!patterns.isEmpty()) {
|
||||
FileTypeAssocTable<Boolean> table = new FileTypeAssocTable<>();
|
||||
for (String pattern : patterns) {
|
||||
table.addAssociation(FileNameMatcherFactory.getInstance().createMatcher(pattern), Boolean.TRUE);
|
||||
}
|
||||
info.excludeFromContentRootTables.put(contentEntry.getFile(), table);
|
||||
}
|
||||
}
|
||||
|
||||
// Init module sources
|
||||
@@ -469,7 +479,7 @@ public class RootIndex {
|
||||
if (!includeLibrarySources) {
|
||||
result = ContainerUtil.filter(result, file -> {
|
||||
DirectoryInfo info = getInfoForFile(file);
|
||||
return info.isInProject() && (!info.isInLibrarySource() || info.isInModuleSource() || info.hasLibraryClassRoot());
|
||||
return info.isInProject(file) && (!info.isInLibrarySource() || info.isInModuleSource() || info.hasLibraryClassRoot());
|
||||
});
|
||||
}
|
||||
return new CollectionQuery<>(result);
|
||||
@@ -547,6 +557,7 @@ public class RootIndex {
|
||||
@NotNull final MultiMap<VirtualFile, /*Library|SyntheticLibrary*/ Object> sourceOfLibraries = MultiMap.createSmart();
|
||||
@NotNull final Set<VirtualFile> excludedFromProject = ContainerUtil.newHashSet();
|
||||
@NotNull final Map<VirtualFile, Module> excludedFromModule = ContainerUtil.newHashMap();
|
||||
@NotNull final Map<VirtualFile, FileTypeAssocTable<Boolean>> excludeFromContentRootTables = ContainerUtil.newHashMap();
|
||||
@NotNull final Map<VirtualFile, String> packagePrefix = ContainerUtil.newHashMap();
|
||||
|
||||
@NotNull
|
||||
@@ -571,6 +582,12 @@ public class RootIndex {
|
||||
for (VirtualFile root : hierarchy) {
|
||||
Module module = contentRootOf.get(root);
|
||||
Module excludedFrom = excludedFromModule.get(root);
|
||||
if (module != null) {
|
||||
FileTypeAssocTable<Boolean> table = excludeFromContentRootTables.get(root);
|
||||
if (table != null && isExcludedByPattern(root, hierarchy, table)) {
|
||||
excludedFrom = module;
|
||||
}
|
||||
}
|
||||
if (module != null && (excludedFrom != module || underExcludedSourceRoot && sourceRootOwners.contains(module))) {
|
||||
return root;
|
||||
}
|
||||
@@ -598,6 +615,18 @@ public class RootIndex {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isExcludedByPattern(VirtualFile contentRoot, List<VirtualFile> hierarchy, FileTypeAssocTable<Boolean> table) {
|
||||
for (VirtualFile file : hierarchy) {
|
||||
if (table.findAssociatedFileType(file.getNameSequence()) != null) {
|
||||
return true;
|
||||
}
|
||||
if (file.equals(contentRoot)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VirtualFile findNearestContentRootForExcluded(@NotNull List<VirtualFile> hierarchy) {
|
||||
for (VirtualFile root : hierarchy) {
|
||||
@@ -727,8 +756,12 @@ public class RootIndex {
|
||||
int typeId = moduleSourceRoot != null ? info.rootTypeId.get(moduleSourceRoot) : 0;
|
||||
|
||||
Module module = info.contentRootOf.get(nearestContentRoot);
|
||||
DirectoryInfo directoryInfo =
|
||||
new DirectoryInfoImpl(root, module, nearestContentRoot, sourceRoot, libraryClassRoot, inModuleSources, inLibrarySource, !inProject, typeId);
|
||||
FileTypeAssocTable<Boolean> excludePatterns = moduleContentRoot != null ? info.excludeFromContentRootTables.get(moduleContentRoot) : null;
|
||||
DirectoryInfo directoryInfo = excludePatterns != null
|
||||
? new DirectoryInfoWithExcludePatterns(root, module, nearestContentRoot, sourceRoot, libraryClassRoot,
|
||||
inModuleSources, inLibrarySource, !inProject, typeId, excludePatterns)
|
||||
: new DirectoryInfoImpl(root, module, nearestContentRoot, sourceRoot, libraryClassRoot, inModuleSources,
|
||||
inLibrarySource, !inProject, typeId);
|
||||
|
||||
String packagePrefix = info.calcPackagePrefix(root, hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot);
|
||||
|
||||
|
||||
+26
@@ -33,6 +33,7 @@ import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.model.JpsElement;
|
||||
import org.jetbrains.jps.model.JpsExcludePattern;
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootProperties;
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootType;
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
|
||||
@@ -54,6 +55,7 @@ public class JpsContentEntry implements ContentEntry, Disposable {
|
||||
private final JpsRootModel myRootModel;
|
||||
private final List<JpsSourceFolder> mySourceFolders;
|
||||
private final List<JpsExcludeFolder> myExcludeFolders;
|
||||
private final List<String> myExcludePatterns;
|
||||
|
||||
public JpsContentEntry(JpsModule module, JpsRootModel rootModel, String rootUrl) {
|
||||
myModule = module;
|
||||
@@ -72,6 +74,12 @@ public class JpsContentEntry implements ContentEntry, Disposable {
|
||||
myExcludeFolders.add(new JpsExcludeFolder(excludedUrl, this));
|
||||
}
|
||||
}
|
||||
myExcludePatterns = new SmartList<>();
|
||||
for (JpsExcludePattern pattern : myModule.getExcludePatterns()) {
|
||||
if (pattern.getBaseDirUrl().equals(rootUrl)) {
|
||||
myExcludePatterns.add(pattern.getPattern());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -286,6 +294,24 @@ public class JpsContentEntry implements ContentEntry, Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getExcludePatterns() {
|
||||
return myExcludePatterns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addExcludePattern(@NotNull String pattern) {
|
||||
myExcludePatterns.add(pattern);
|
||||
myModule.addExcludePattern(getUrl(), pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeExcludePattern(@NotNull String pattern) {
|
||||
myExcludePatterns.remove(pattern);
|
||||
myModule.removeExcludePattern(getUrl(), pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSynthetic() {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user