Skip to content

Commit 5d6745b

Browse files
authored
Merge pull request #1950 from Haehnchen/feature/glob-support-central-step-1
refactor glob / resource handling, allowing it to use in a more central way
2 parents 31b834e + 2962990 commit 5d6745b

File tree

3 files changed

+136
-15
lines changed

3 files changed

+136
-15
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/util/resource/FileResourceUtil.java

Lines changed: 95 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,19 @@
3434
import java.nio.file.attribute.BasicFileAttributes;
3535
import java.util.*;
3636
import java.util.function.Supplier;
37+
import java.util.regex.PatternSyntaxException;
3738
import java.util.stream.Collectors;
3839
import java.util.stream.Stream;
3940

4041
/**
4142
* @author Daniel Espendiller <daniel@espendiller.net>
4243
*/
4344
public class FileResourceUtil {
45+
/**
46+
* chars that trigger a glob resolving on symfony
47+
* extracted from: \Symfony\Component\Config\Loader\FileLoader::import
48+
*/
49+
private static final String[] GLOB_DETECTION_CHARS = {"*", "?", "{", "["};
4450

4551
/**
4652
* Search for files refers to given file
@@ -79,19 +85,56 @@ public static boolean hasFileResources(@NotNull Project project, @NotNull PsiFil
7985
return CachedValueProvider.Result.create(Boolean.FALSE, FileIndexCaches.getModificationTrackerForIndexId(project, FileResourcesIndex.KEY));
8086
}
8187

82-
Set<String> collect = FileBasedIndex.getInstance().getAllKeys(FileResourcesIndex.KEY, project)
83-
.stream()
84-
.filter(s -> !s.startsWith("@"))
85-
.collect(Collectors.toSet());
88+
Set<String> resources = new HashSet<>(FileBasedIndex.getInstance().getAllKeys(FileResourcesIndex.KEY, project));
8689

87-
for (String s : collect) {
88-
for (VirtualFile containingFile : FileBasedIndex.getInstance().getContainingFiles(FileResourcesIndex.KEY, s, GlobalSearchScope.allScope(project))) {
90+
for (String resource : resources) {
91+
for (VirtualFile containingFile : FileBasedIndex.getInstance().getContainingFiles(FileResourcesIndex.KEY, resource, GlobalSearchScope.allScope(project))) {
8992
VirtualFile directory = containingFile.getParent();
9093
if (directory == null) {
9194
continue;
9295
}
9396

94-
VirtualFile relativeFile = VfsUtil.findRelativeFile(directory, s.replace("\\", "/").split("/"));
97+
String resourceResolved = resource;
98+
99+
if (resource.startsWith("@")) {
100+
String replace = resource.replace("\\", "/");
101+
int i = replace.indexOf("/");
102+
if (i > 2) {
103+
String substring = resource.substring(1, i);
104+
Collection<SymfonyBundle> bundle = new SymfonyBundleUtil(project).getBundle(substring);
105+
106+
for (SymfonyBundle symfonyBundle : bundle) {
107+
PsiDirectory directory1 = symfonyBundle.getDirectory();
108+
if (directory1 == null) {
109+
continue;
110+
}
111+
112+
String substring1 = resource.substring(i);
113+
String path = directory1.getVirtualFile().getPath();
114+
resourceResolved = path + substring1;
115+
116+
break;
117+
}
118+
}
119+
}
120+
121+
if (Arrays.stream(GLOB_DETECTION_CHARS).anyMatch(resource::contains)) {
122+
String path = directory.getPath();
123+
124+
// nested types not support by java glob implementation so just catch the exception: "../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php,Service/{IspConfiguration,DataCollection}}"
125+
try {
126+
String s1 = Paths.get(path + File.separatorChar + StringUtils.stripStart(resourceResolved, "\\/")).normalize().toString();
127+
String syntaxAndPattern = "glob:" + s1;
128+
if (FileSystems.getDefault().getPathMatcher(syntaxAndPattern).matches(Paths.get(virtualFile.getPath()))) {
129+
return CachedValueProvider.Result.create(Boolean.TRUE, FileIndexCaches.getModificationTrackerForIndexId(project, FileResourcesIndex.KEY));
130+
}
131+
} catch (PatternSyntaxException | InvalidPathException ignored) {
132+
}
133+
134+
continue;
135+
}
136+
137+
VirtualFile relativeFile = VfsUtil.findRelativeFile(directory, resourceResolved.replace("\\", "/").split("/"));
95138
if (relativeFile != null) {
96139
String relativePath = VfsUtil.getRelativePath(virtualFile, relativeFile);
97140
if (relativePath != null) {
@@ -111,24 +154,61 @@ public static boolean hasFileResources(@NotNull Project project, @NotNull PsiFil
111154
*/
112155
@NotNull
113156
public static Collection<Pair<VirtualFile, String>> getFileResources(@NotNull Project project, @NotNull VirtualFile virtualFile) {
114-
Set<String> collect = FileBasedIndex.getInstance().getAllKeys(FileResourcesIndex.KEY, project)
115-
.stream()
116-
.filter(s -> !s.startsWith("@"))
117-
.collect(Collectors.toSet());
157+
Set<String> resources = new HashSet<>(FileBasedIndex.getInstance().getAllKeys(FileResourcesIndex.KEY, project));
118158

119159
Collection<Pair<VirtualFile, String>> files = new ArrayList<>();
120-
for (String s : collect) {
121-
for (VirtualFile containingFile : FileBasedIndex.getInstance().getContainingFiles(FileResourcesIndex.KEY, s, GlobalSearchScope.allScope(project))) {
160+
for (String resource : resources) {
161+
for (VirtualFile containingFile : FileBasedIndex.getInstance().getContainingFiles(FileResourcesIndex.KEY, resource, GlobalSearchScope.allScope(project))) {
122162
VirtualFile directory = containingFile.getParent();
123163
if (directory == null) {
124164
continue;
125165
}
126166

127-
VirtualFile relativeFile = VfsUtil.findRelativeFile(directory, s.replace("\\", "/").split("/"));
167+
String resourceResolved = resource;
168+
169+
if (resource.startsWith("@")) {
170+
String replace = resource.replace("\\", "/");
171+
int i = replace.indexOf("/");
172+
if (i > 2) {
173+
String substring = resource.substring(1, i);
174+
Collection<SymfonyBundle> bundle = new SymfonyBundleUtil(project).getBundle(substring);
175+
176+
for (SymfonyBundle symfonyBundle : bundle) {
177+
PsiDirectory directory1 = symfonyBundle.getDirectory();
178+
if (directory1 == null) {
179+
continue;
180+
}
181+
182+
String substring1 = resource.substring(i);
183+
String path = directory1.getVirtualFile().getPath();
184+
resourceResolved = path + substring1;
185+
186+
break;
187+
}
188+
}
189+
}
190+
191+
if (Arrays.stream(GLOB_DETECTION_CHARS).anyMatch(resource::contains)) {
192+
String path = directory.getPath();
193+
194+
// nested types not support by java glob implementation so just catch the exception: "../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php,Service/{IspConfiguration,DataCollection}}"
195+
try {
196+
String s1 = Paths.get(path + File.separatorChar + StringUtils.stripStart(resourceResolved, "\\/")).normalize().toString();
197+
String syntaxAndPattern = "glob:" + s1;
198+
if (FileSystems.getDefault().getPathMatcher(syntaxAndPattern).matches(Paths.get(virtualFile.getPath()))) {
199+
files.add(Pair.create(containingFile, resource));
200+
}
201+
} catch (PatternSyntaxException | InvalidPathException ignored) {
202+
}
203+
204+
continue;
205+
}
206+
207+
VirtualFile relativeFile = VfsUtil.findRelativeFile(directory, resourceResolved.replace("\\", "/").split("/"));
128208
if (relativeFile != null) {
129209
String relativePath = VfsUtil.getRelativePath(virtualFile, relativeFile);
130210
if (relativePath != null) {
131-
files.add(Pair.create(containingFile, s));
211+
files.add(Pair.create(containingFile, resource));
132212
}
133213
}
134214
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/util/resource/FileResourceUtilTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.intellij.openapi.util.Pair;
44
import com.intellij.openapi.vfs.VirtualFile;
55
import com.intellij.psi.PsiFile;
6+
import com.intellij.psi.PsiManager;
67
import com.intellij.util.containers.ContainerUtil;
78
import com.jetbrains.php.lang.psi.elements.PhpClass;
89
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
@@ -76,12 +77,51 @@ public void testFileResources() {
7677
assertTrue(fileResources.stream().anyMatch(pair -> pair.getFirst().getPath().equals(services.getPath())));
7778
}
7879

80+
public void testFileResourcesForBundle() {
81+
myFixture.copyFileToProject("classes.php");
82+
myFixture.configureByText("target.xml", "" +
83+
"<routes>\n" +
84+
" <import resource=\"@FooBundle/*Controller.php\" />\n" +
85+
"</routes>"
86+
);
87+
88+
VirtualFile virtualFile = myFixture.copyFileToProject("dummy.php", "src/TestController.php");
89+
90+
assertTrue(FileResourceUtil.hasFileResources(getProject(), PsiManager.getInstance(getProject()).findFile(virtualFile)));
91+
92+
Collection<Pair<VirtualFile, String>> fileResources = FileResourceUtil.getFileResources(getProject(), virtualFile);
93+
assertTrue(fileResources.stream().anyMatch(pair -> pair.getSecond().equals("@FooBundle/*Controller.php")));
94+
}
95+
96+
public void testFileResourcesForBundleNoMatch() {
97+
myFixture.copyFileToProject("classes.php");
98+
99+
PsiFile psiFile = myFixture.configureByText("target.xml", "" +
100+
"<routes>\n" +
101+
" <import resource=\"@FooBundle/*Foobar.php\" />\n" +
102+
"</routes>"
103+
);
104+
105+
VirtualFile virtualFile = myFixture.copyFileToProject("dummy.php", "src/TestController.php");
106+
107+
assertFalse(FileResourceUtil.hasFileResources(getProject(), PsiElementUtils.virtualFileToPsiFile(getProject(), virtualFile)));
108+
109+
Collection<Pair<VirtualFile, String>> fileResources = FileResourceUtil.getFileResources(getProject(), virtualFile);
110+
assertFalse(fileResources.stream().anyMatch(pair -> pair.getFirst().getPath().equals(psiFile.getVirtualFile().getPath())));
111+
}
112+
79113
public void testGetFileImplementsLineMarker() {
80114
myFixture.copyFileToProject("services.xml", "config/services.xml");
81115
VirtualFile virtualFile = myFixture.copyFileToProject("classes.php", "src/Test.php");
82116
assertNotNull(FileResourceUtil.getFileImplementsLineMarker(PsiElementUtils.virtualFileToPsiFile(getProject(), virtualFile)));
83117
}
84118

119+
public void testGetFileImplementsLineMarkerForGlob() {
120+
myFixture.copyFileToProject("services.xml", "config/services.xml");
121+
VirtualFile virtualFile = myFixture.copyFileToProject("classes.php", "src/TestController.php");
122+
assertNotNull(FileResourceUtil.getFileImplementsLineMarker(PsiElementUtils.virtualFileToPsiFile(getProject(), virtualFile)));
123+
}
124+
85125
public void testGetFileImplementsLineMarkerForBundle() {
86126
createBundleScopeProject();
87127

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?php

0 commit comments

Comments
 (0)