Skip to content

Commit 5bf71bd

Browse files
committed
refactor glob / resource handling, allowing it to use in a more central way
1 parent 5d6745b commit 5bf71bd

File tree

4 files changed

+85
-212
lines changed

4 files changed

+85
-212
lines changed

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

Lines changed: 78 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
import com.intellij.psi.PsiDirectory;
1111
import com.intellij.psi.PsiElement;
1212
import com.intellij.psi.PsiFile;
13-
import com.intellij.psi.PsiManager;
1413
import com.intellij.psi.search.GlobalSearchScope;
1514
import com.intellij.psi.util.CachedValueProvider;
1615
import com.intellij.psi.util.CachedValuesManager;
1716
import com.intellij.util.PlatformIcons;
1817
import com.intellij.util.indexing.FileBasedIndex;
1918
import com.jetbrains.php.PhpIcons;
2019
import fr.adrienbrault.idea.symfony2plugin.stubs.cache.FileIndexCaches;
20+
import fr.adrienbrault.idea.symfony2plugin.stubs.dict.FileResource;
21+
import fr.adrienbrault.idea.symfony2plugin.stubs.dict.FileResourceContextTypeEnum;
2122
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.FileResourcesIndex;
2223
import fr.adrienbrault.idea.symfony2plugin.util.FileResourceVisitorUtil;
2324
import fr.adrienbrault.idea.symfony2plugin.util.PhpIndexUtil;
@@ -33,6 +34,7 @@
3334
import java.nio.file.*;
3435
import java.nio.file.attribute.BasicFileAttributes;
3536
import java.util.*;
37+
import java.util.function.Function;
3638
import java.util.function.Supplier;
3739
import java.util.regex.PatternSyntaxException;
3840
import java.util.stream.Collectors;
@@ -48,31 +50,6 @@ public class FileResourceUtil {
4850
*/
4951
private static final String[] GLOB_DETECTION_CHARS = {"*", "?", "{", "["};
5052

51-
/**
52-
* Search for files refers to given file
53-
*/
54-
@NotNull
55-
public static Collection<VirtualFile> getFileResourceRefers(@NotNull Project project, @NotNull VirtualFile virtualFile) {
56-
String bundleLocateName = getBundleLocateName(project, virtualFile);
57-
if(bundleLocateName == null) {
58-
return Collections.emptyList();
59-
}
60-
61-
return getFileResourceRefers(project, bundleLocateName);
62-
}
63-
64-
/**
65-
* Search for files refers to given file
66-
*/
67-
@NotNull
68-
private static Collection<VirtualFile> getFileResourceRefers(@NotNull Project project, @NotNull String bundleLocateName) {
69-
return FileBasedIndex.getInstance().getContainingFiles(
70-
FileResourcesIndex.KEY,
71-
bundleLocateName,
72-
GlobalSearchScope.allScope(project)
73-
);
74-
}
75-
7653
/**
7754
* Search for files refers to given file
7855
*/
@@ -85,66 +62,14 @@ public static boolean hasFileResources(@NotNull Project project, @NotNull PsiFil
8562
return CachedValueProvider.Result.create(Boolean.FALSE, FileIndexCaches.getModificationTrackerForIndexId(project, FileResourcesIndex.KEY));
8663
}
8764

88-
Set<String> resources = new HashSet<>(FileBasedIndex.getInstance().getAllKeys(FileResourcesIndex.KEY, project));
65+
final Boolean[] aFalse = {Boolean.FALSE};
8966

90-
for (String resource : resources) {
91-
for (VirtualFile containingFile : FileBasedIndex.getInstance().getContainingFiles(FileResourcesIndex.KEY, resource, GlobalSearchScope.allScope(project))) {
92-
VirtualFile directory = containingFile.getParent();
93-
if (directory == null) {
94-
continue;
95-
}
96-
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("/"));
138-
if (relativeFile != null) {
139-
String relativePath = VfsUtil.getRelativePath(virtualFile, relativeFile);
140-
if (relativePath != null) {
141-
return CachedValueProvider.Result.create(Boolean.TRUE, FileIndexCaches.getModificationTrackerForIndexId(project, FileResourcesIndex.KEY));
142-
}
143-
}
144-
}
145-
}
67+
visitFileResources(project, virtualFile, pair -> {
68+
aFalse[0] = Boolean.TRUE;
69+
return true;
70+
});
14671

147-
return CachedValueProvider.Result.create(Boolean.FALSE, FileIndexCaches.getModificationTrackerForIndexId(project, FileResourcesIndex.KEY));
72+
return CachedValueProvider.Result.create(aFalse[0], FileIndexCaches.getModificationTrackerForIndexId(project, FileResourcesIndex.KEY));
14873
}
14974
);
15075
}
@@ -154,11 +79,32 @@ public static boolean hasFileResources(@NotNull Project project, @NotNull PsiFil
15479
*/
15580
@NotNull
15681
public static Collection<Pair<VirtualFile, String>> getFileResources(@NotNull Project project, @NotNull VirtualFile virtualFile) {
157-
Set<String> resources = new HashSet<>(FileBasedIndex.getInstance().getAllKeys(FileResourcesIndex.KEY, project));
158-
15982
Collection<Pair<VirtualFile, String>> files = new ArrayList<>();
160-
for (String resource : resources) {
161-
for (VirtualFile containingFile : FileBasedIndex.getInstance().getContainingFiles(FileResourcesIndex.KEY, resource, GlobalSearchScope.allScope(project))) {
83+
84+
visitFileResources(project, virtualFile, pair -> {
85+
files.add(Pair.create(pair.getFirst(), pair.getSecond()));
86+
return false;
87+
});
88+
89+
return files;
90+
}
91+
92+
/**
93+
* Search for files refers to given file
94+
*/
95+
public static void visitFileResources(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull Function<Pair<VirtualFile, String>, Boolean> consumer) {
96+
Set<VirtualFile> files = new HashSet<>();
97+
for (String resource : FileBasedIndex.getInstance().getAllKeys(FileResourcesIndex.KEY, project)) {
98+
files.addAll(FileBasedIndex.getInstance().getContainingFiles(FileResourcesIndex.KEY, resource, GlobalSearchScope.allScope(project)));
99+
}
100+
101+
for (VirtualFile containingFile : files) {
102+
for (FileResource fileResourceContext : FileBasedIndex.getInstance().getFileData(FileResourcesIndex.KEY, containingFile, project).values()) {
103+
String resource = fileResourceContext.getResource();
104+
if (resource == null) {
105+
continue;
106+
}
107+
162108
VirtualFile directory = containingFile.getParent();
163109
if (directory == null) {
164110
continue;
@@ -169,7 +115,14 @@ public static Collection<Pair<VirtualFile, String>> getFileResources(@NotNull Pr
169115
if (resource.startsWith("@")) {
170116
String replace = resource.replace("\\", "/");
171117
int i = replace.indexOf("/");
172-
if (i > 2) {
118+
119+
boolean resolved = false;
120+
121+
if (i > 2 || i == -1) {
122+
if (i == -1) {
123+
i = resource.length();
124+
}
125+
173126
String substring = resource.substring(1, i);
174127
Collection<SymfonyBundle> bundle = new SymfonyBundleUtil(project).getBundle(substring);
175128

@@ -179,15 +132,22 @@ public static Collection<Pair<VirtualFile, String>> getFileResources(@NotNull Pr
179132
continue;
180133
}
181134

182-
String substring1 = resource.substring(i);
183-
String path = directory1.getVirtualFile().getPath();
184-
resourceResolved = path + substring1;
135+
resourceResolved = resource.substring(replace.contains("/") ? i + 1 : replace.length());
136+
directory = directory1.getVirtualFile();
137+
138+
resolved = true;
185139

186140
break;
187141
}
188142
}
143+
144+
if (!resolved) {
145+
continue;
146+
}
189147
}
190148

149+
// '../src/{Entity}'
150+
// '../src/*Controller.php'
191151
if (Arrays.stream(GLOB_DETECTION_CHARS).anyMatch(resource::contains)) {
192152
String path = directory.getPath();
193153

@@ -196,62 +156,41 @@ public static Collection<Pair<VirtualFile, String>> getFileResources(@NotNull Pr
196156
String s1 = Paths.get(path + File.separatorChar + StringUtils.stripStart(resourceResolved, "\\/")).normalize().toString();
197157
String syntaxAndPattern = "glob:" + s1;
198158
if (FileSystems.getDefault().getPathMatcher(syntaxAndPattern).matches(Paths.get(virtualFile.getPath()))) {
199-
files.add(Pair.create(containingFile, resource));
159+
if (consumer.apply(new Pair<>(containingFile, resource))) {
160+
return;
161+
}
200162
}
201163
} catch (PatternSyntaxException | InvalidPathException ignored) {
202164
}
203165

204166
continue;
205167
}
206168

169+
// '../src/FooController.php'
207170
VirtualFile relativeFile = VfsUtil.findRelativeFile(directory, resourceResolved.replace("\\", "/").split("/"));
208-
if (relativeFile != null) {
209-
String relativePath = VfsUtil.getRelativePath(virtualFile, relativeFile);
210-
if (relativePath != null) {
211-
files.add(Pair.create(containingFile, resource));
171+
if (relativeFile != null && relativeFile.equals(virtualFile)) {
172+
if (consumer.apply(new Pair<>(containingFile, resource))) {
173+
return;
212174
}
213175
}
214-
}
215-
}
216176

217-
return files;
218-
}
219-
220-
@Nullable
221-
public static String getBundleLocateName(@NotNull Project project, @NotNull VirtualFile virtualFile) {
222-
SymfonyBundle containingBundle = new SymfonyBundleUtil(project).getContainingBundle(virtualFile);
223-
if(containingBundle == null) {
224-
return null;
225-
}
226-
227-
String relativePath = containingBundle.getRelativePath(virtualFile);
228-
if(relativePath == null) {
229-
return null;
230-
}
231-
232-
return "@" + containingBundle.getName() + "/" + relativePath;
233-
}
234-
235-
/**
236-
* Search for line definition of "@FooBundle/foo.xml"
237-
*/
238-
@NotNull
239-
private static Collection<PsiElement> getBundleLocateStringDefinitions(@NotNull Project project, final @NotNull String bundleFileName) {
240-
final Collection<PsiElement> psiElements = new HashSet<>();
241-
for (VirtualFile refVirtualFile : getFileResourceRefers(project, bundleFileName)) {
242-
PsiFile psiFile = PsiManager.getInstance(project).findFile(refVirtualFile);
243-
if(psiFile == null) {
244-
continue;
245-
}
177+
// '..src/Controller'
178+
if (fileResourceContext.getContextType() == FileResourceContextTypeEnum.ROUTE) {
179+
if (StringUtils.isNotBlank(resourceResolved)) {
180+
directory = VfsUtil.findRelativeFile(directory, resourceResolved.replace("\\", "/").split("/"));
181+
if (directory == null) {
182+
continue;
183+
}
184+
}
246185

247-
FileResourceVisitorUtil.visitFile(psiFile, consumer -> {
248-
if (bundleFileName.equals(consumer.getResource())) {
249-
psiElements.add(consumer.getPsiElement());
186+
if (VfsUtil.isAncestor(directory, virtualFile, false)) {
187+
if (consumer.apply(new Pair<>(containingFile, resource))) {
188+
return;
189+
}
190+
}
250191
}
251-
});
192+
}
252193
}
253-
254-
return psiElements;
255194
}
256195

257196
@Nullable
@@ -263,15 +202,6 @@ public static RelatedItemLineMarkerInfo<PsiElement> getFileImplementsLineMarker(
263202
return null;
264203
}
265204

266-
String bundleLocateName = FileResourceUtil.getBundleLocateName(project, virtualFile);
267-
if(bundleLocateName != null && FileResourceUtil.getFileResourceRefers(project, bundleLocateName).size() > 0) {
268-
NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder.create(PhpIcons.IMPLEMENTS)
269-
.setTargets(NotNullLazyValue.lazy(new FileResourceBundleNotNullLazyValue(project, bundleLocateName)))
270-
.setTooltipText("Navigate to resource");
271-
272-
return builder.createLineMarkerInfo(psiFile);
273-
}
274-
275205
if (hasFileResources(project, psiFile)) {
276206
NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder.create(PhpIcons.IMPLEMENTS)
277207
.setTargets(NotNullLazyValue.lazy(new FileResourceNotNullLazyValue(project, virtualFile)))
@@ -288,69 +218,22 @@ public static RelatedItemLineMarkerInfo<PsiElement> getFileImplementsLineMarker(
288218
*/
289219
@Nullable
290220
public static RelatedItemLineMarkerInfo<PsiElement> getFileImplementsLineMarkerInFolderScope(@NotNull PsiFile psiFile) {
291-
VirtualFile virtualFile = psiFile.getVirtualFile();
292-
if(virtualFile == null) {
293-
return null;
294-
}
295-
296-
final Project project = psiFile.getProject();
297-
String bundleLocateName = FileResourceUtil.getBundleLocateName(project, virtualFile);
298-
if(bundleLocateName == null) {
221+
if (!hasFileResources(psiFile.getProject(), psiFile)) {
299222
return null;
300223
}
301224

302-
Set<String> names = new HashSet<>();
303-
names.add(bundleLocateName);
304-
305-
// strip filename
306-
int i = bundleLocateName.lastIndexOf("/");
307-
if(i > 0) {
308-
names.add(bundleLocateName.substring(0, i));
309-
}
310-
311-
int targets = 0;
312-
for (String name : names) {
313-
targets += FileResourceUtil.getFileResourceRefers(project, name).size();
314-
}
315-
316-
if(targets == 0) {
225+
VirtualFile virtualFile = psiFile.getVirtualFile();
226+
if (virtualFile == null) {
317227
return null;
318228
}
319229

320230
NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder.create(PlatformIcons.ANNOTATION_TYPE_ICON)
321-
.setTargets(NotNullLazyValue.lazy(new FileResourceBundleNotNullLazyValue(project, names)))
231+
.setTargets(NotNullLazyValue.lazy(new FileResourceNotNullLazyValue(psiFile.getProject(), virtualFile)))
322232
.setTooltipText("Symfony: <a href=\"https://symfony.com/doc/current/routing.html#creating-routes-as-annotations\">Annotation Routing</a>");
323233

324234
return builder.createLineMarkerInfo(psiFile);
325235
}
326236

327-
private static class FileResourceBundleNotNullLazyValue implements Supplier<Collection<? extends PsiElement>> {
328-
329-
private final Collection<String> resources;
330-
private final Project project;
331-
332-
public FileResourceBundleNotNullLazyValue(@NotNull Project project, @NotNull Collection<String> resource) {
333-
this.resources = resource;
334-
this.project = project;
335-
}
336-
337-
public FileResourceBundleNotNullLazyValue(@NotNull Project project, @NotNull String resource) {
338-
this.resources = Collections.singleton(resource);
339-
this.project = project;
340-
}
341-
342-
@Override
343-
public Collection<? extends PsiElement> get() {
344-
Collection<PsiElement> psiElements = new HashSet<>();
345-
346-
for (String resource : this.resources) {
347-
psiElements.addAll(getBundleLocateStringDefinitions(project, resource));
348-
}
349-
350-
return psiElements;
351-
}
352-
}
353-
354237
/**
355238
* Gives targets to files on Bundle locate syntax. "@FooBundle/.../foo.yml"
356239
*/
@@ -474,7 +357,7 @@ private static class FileResourceNotNullLazyValue implements Supplier<Collection
474357
private final Project project;
475358
private final VirtualFile virtualFile;
476359

477-
public FileResourceNotNullLazyValue(Project project, VirtualFile virtualFile) {
360+
public FileResourceNotNullLazyValue(@NotNull Project project, @NotNull VirtualFile virtualFile) {
478361
this.project = project;
479362
this.virtualFile = virtualFile;
480363
}

0 commit comments

Comments
 (0)