From 22efbad711d328d45f48ae01a7d91cf163d75c0e Mon Sep 17 00:00:00 2001 From: Snjezana Peco Date: Tue, 12 Dec 2023 18:21:48 +0100 Subject: [PATCH] JDT LS Filesystem should respect resource filtering - Resource model filtering is set up after projects are imported, but some import operations (eg. Maven projects) could benefit from this --- .../preferences/PreferenceManager.java | 4 ++ .../filesystem/JDTLSFilesystemActivator.java | 52 +++++++++++++++++++ .../ls/core/internal/filesystem/JLSFile.java | 8 ++- .../core/internal/filesystem/JLSFsUtils.java | 25 +++++++++ .../internal/filesystem/JLSFsUtilsTest.java | 14 +++++ .../AbstractProjectsManagerBasedTest.java | 3 ++ 6 files changed, 104 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/PreferenceManager.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/PreferenceManager.java index 722101da5c..227cf8fe8a 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/PreferenceManager.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/PreferenceManager.java @@ -227,6 +227,10 @@ public void update(Preferences preferences) { Hashtable options = JavaCore.getOptions(); preferences.updateTabSizeInsertSpaces(options); JavaCore.setOptions(options); + List resourceFilters = preferences.getResourceFilters(); + IEclipsePreferences eclipsePreferences = InstanceScope.INSTANCE.getNode(IConstants.PLUGIN_ID); + // add the resourceFilters preference; the org.eclipse.jdt.ls.filesystem plugin uses it + eclipsePreferences.put(Preferences.JAVA_RESOURCE_FILTERS, String.join("::", resourceFilters)); // TODO serialize preferences } diff --git a/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JDTLSFilesystemActivator.java b/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JDTLSFilesystemActivator.java index 6b930e88fc..86d34cf024 100644 --- a/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JDTLSFilesystemActivator.java +++ b/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JDTLSFilesystemActivator.java @@ -1,5 +1,14 @@ package org.eclipse.jdt.ls.core.internal.filesystem; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; + +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; +import org.eclipse.core.runtime.preferences.InstanceScope; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; @@ -15,6 +24,12 @@ public class JDTLSFilesystemActivator implements BundleActivator { private static BundleContext context; + private static final String JAVA_LS_PLUGIN_ID = "org.eclipse.jdt.ls.core"; + private static final String JAVA_RESOURCE_FILTERS = "java.project.resourceFilters"; + private static final String JAVA_RESOURCE_FILTERS_DEFAULT = "node_modules::\\.git"; + private List resourcePatterns; + private String resourceFilters; + private static JDTLSFilesystemActivator instance; static BundleContext getContext() { return context; @@ -22,10 +37,47 @@ static BundleContext getContext() { public void start(BundleContext bundleContext) throws Exception { JDTLSFilesystemActivator.context = bundleContext; + JDTLSFilesystemActivator.instance = this; + configureResourceFilters(); + } + + private void configureResourceFilters() { + IEclipsePreferences eclipsePreferences = InstanceScope.INSTANCE.getNode(JAVA_LS_PLUGIN_ID); + if (eclipsePreferences != null) { + resourceFilters = eclipsePreferences.get(JAVA_RESOURCE_FILTERS, JAVA_RESOURCE_FILTERS_DEFAULT); + eclipsePreferences.addPreferenceChangeListener(new IPreferenceChangeListener() { + + @Override + public void preferenceChange(PreferenceChangeEvent event) { + if (event.getNewValue() instanceof String newValue && Objects.equals(JAVA_RESOURCE_FILTERS, event.getKey()) && !Objects.equals(resourceFilters, event.getNewValue())) { + resourceFilters = newValue; + setResourcePatterns(); + } + } + }); + } else { + resourceFilters = JAVA_RESOURCE_FILTERS_DEFAULT; + } + setResourcePatterns(); + } + + protected void setResourcePatterns() { + resourcePatterns = new ArrayList<>(); + for (String element : resourceFilters.split("::")) { + Pattern pattern = Pattern.compile(element); + resourcePatterns.add(pattern); + } } public void stop(BundleContext bundleContext) throws Exception { JDTLSFilesystemActivator.context = null; } + public static List getResourcePatterns() { + if (instance != null) { + return instance.resourcePatterns; + } + return null; + } + } diff --git a/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFile.java b/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFile.java index f5770486f3..a07f5c8e53 100644 --- a/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFile.java +++ b/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFile.java @@ -20,6 +20,7 @@ import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.internal.filesystem.local.LocalFile; +import org.eclipse.core.internal.preferences.EclipsePreferences; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; @@ -50,6 +51,9 @@ public String[] childNames(int options, IProgressMonitor monitor) { } IPath filePath = new Path(this.filePath); + if (JLSFsUtils.isExcluded(filePath)) { + return childNames; + } String projectName = JLSFsUtils.getProjectNameIfLocationIsProjectRoot(filePath); if (projectName == null) { return childNames; @@ -69,7 +73,7 @@ public String[] childNames(int options, IProgressMonitor monitor) { @Override public IFileStore getChild(String name) { IPath path = new Path(this.filePath).append(name); - if (JLSFsUtils.shouldStoreInMetadataArea(path)) { + if (JLSFsUtils.shouldStoreInMetadataArea(path) && !JLSFsUtils.isExcluded(path)) { IPath containerPath = JLSFsUtils.getContainerPath(path); String projectName = JLSFsUtils.getProjectNameIfLocationIsProjectRoot(containerPath); if (projectName == null) { @@ -87,7 +91,7 @@ public IFileStore getChild(String name) { @Override public IFileStore getFileStore(IPath path) { IPath fullPath = new Path(this.filePath).append(path); - if (JLSFsUtils.shouldStoreInMetadataArea(fullPath)) { + if (JLSFsUtils.shouldStoreInMetadataArea(fullPath) && !JLSFsUtils.isExcluded(fullPath)) { IPath containerPath = JLSFsUtils.getContainerPath(fullPath); String projectName = JLSFsUtils.getProjectNameIfLocationIsProjectRoot(containerPath); if (projectName == null) { diff --git a/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFsUtils.java b/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFsUtils.java index b898ccda93..513426a97d 100644 --- a/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFsUtils.java +++ b/org.eclipse.jdt.ls.filesystem/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFsUtils.java @@ -17,6 +17,8 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.core.internal.preferences.EclipsePreferences; import org.eclipse.core.resources.IContainer; @@ -24,6 +26,8 @@ import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jdt.core.IJavaProject; /** @@ -110,6 +114,27 @@ static boolean isProjectMetadataFile(IPath location) { return true; } + /** + * Check whether the given location is excluded + * @param location file location. + * @return whether the given location is excluded. + */ + public static boolean isExcluded(IPath path) { + if (path != null && JDTLSFilesystemActivator.getResourcePatterns() != null) { + for (String segment: path.segments()) { + for (Pattern pattern: JDTLSFilesystemActivator.getResourcePatterns()) { + Matcher m = pattern.matcher(segment); + if (m.matches()) { + return true; + } + } + } + return false; + } else { + return true; + } + } + /** * Get the container path of the given file path. * If the file path is a preferences file, the grand-parent container will be returned. diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFsUtilsTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFsUtilsTest.java index 51699f796a..09d1744bd4 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFsUtilsTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/filesystem/JLSFsUtilsTest.java @@ -16,6 +16,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.junit.After; import org.junit.Test; public class JLSFsUtilsTest { @@ -35,4 +38,15 @@ public void testNotGeneratesMetadataFilesAtProjectRoot() { public void testGeneratesMetadataFilesAtProjectRootWhenNotSet() { assertTrue(JLSFsUtils.generatesMetadataFilesAtProjectRoot()); } + + @Test + public void testExcluded() { + IPath path = new Path("/project/node_modules"); + assertTrue(JLSFsUtils.isExcluded(path)); + } + + @After + public void cleanUp() throws Exception { + System.clearProperty(JLSFsUtils.GENERATES_METADATA_FILES_AT_PROJECT_ROOT); + } } diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/AbstractProjectsManagerBasedTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/AbstractProjectsManagerBasedTest.java index 1fa094c876..ebb8c15b65 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/AbstractProjectsManagerBasedTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/AbstractProjectsManagerBasedTest.java @@ -97,6 +97,8 @@ public abstract class AbstractProjectsManagerBasedTest { private static final java.lang.String REFERENCE_PREFIX = "reference:"; + private static final String GENERATES_METADATA_FILES_AT_PROJECT_ROOT = "java.import.generatesMetadataFilesAtProjectRoot"; + protected IProgressMonitor monitor; protected StandardProjectsManager projectsManager; @Mock @@ -302,6 +304,7 @@ public void cleanUp() throws Exception { } ResourcesPlugin.getWorkspace().save(true/*full save*/, null/*no progress*/); CoreASTProvider.getInstance().disposeAST(); + System.clearProperty(GENERATES_METADATA_FILES_AT_PROJECT_ROOT); } protected void assertIsJavaProject(IProject project) {