Skip to content

Commit 967915c

Browse files
committed
fix assets reading and provide explicit resolving for asset files instead of rescanning them to improve performance an drop massive opendirectoryd cpu time #809 #1118
1 parent b6d3c01 commit 967915c

File tree

11 files changed

+201
-114
lines changed

11 files changed

+201
-114
lines changed

src/fr/adrienbrault/idea/symfony2plugin/asset/dic/AssetDirectoryReader.java renamed to src/fr/adrienbrault/idea/symfony2plugin/asset/AssetDirectoryReader.java

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package fr.adrienbrault.idea.symfony2plugin.asset.dic;
1+
package fr.adrienbrault.idea.symfony2plugin.asset;
22

33
import com.intellij.openapi.project.Project;
44
import com.intellij.openapi.vfs.VfsUtil;
@@ -9,15 +9,21 @@
99
import fr.adrienbrault.idea.symfony2plugin.Settings;
1010
import fr.adrienbrault.idea.symfony2plugin.util.SymfonyBundleUtil;
1111
import fr.adrienbrault.idea.symfony2plugin.util.dict.SymfonyBundle;
12+
import org.apache.commons.lang.StringUtils;
1213
import org.jetbrains.annotations.NotNull;
1314
import org.jetbrains.annotations.Nullable;
1415

1516
import java.util.*;
17+
import java.util.regex.Matcher;
18+
import java.util.regex.Pattern;
1619

1720
/**
1821
* @author Daniel Espendiller <daniel@espendiller.net>
1922
*/
2023
public class AssetDirectoryReader {
24+
25+
public static AssetDirectoryReader INSTANCE = new AssetDirectoryReader();
26+
2127
final private boolean includeBundleDir;
2228

2329
@NotNull
@@ -39,8 +45,9 @@ public static VirtualFile getProjectAssetRoot(@NotNull Project project) {
3945
return VfsUtil.findRelativeFile(projectDirectory, webDirectoryName.split("/"));
4046
}
4147

42-
public List<AssetFile> getAssetFiles(@NotNull Project project) {
43-
List<AssetFile> files = new ArrayList<>();
48+
@NotNull
49+
public Collection<AssetFile> getAssetFiles(@NotNull Project project) {
50+
Collection<AssetFile> files = new ArrayList<>();
4451

4552
VirtualFile webDirectory = getProjectAssetRoot(project);
4653
if (null == webDirectory) {
@@ -87,11 +94,75 @@ public boolean visitFile(@NotNull VirtualFile virtualFile) {
8794
return files;
8895
}
8996

97+
/**
98+
* '@SampleBundle/Resources/public/js/*'
99+
* 'assets/js/*'
100+
* 'assets/js/*.js'
101+
*/
102+
@NotNull
103+
public Collection<VirtualFile> resolveAssetFile(@NotNull Project project, @NotNull String filename) {
104+
105+
/*
106+
107+
Matcher matcher = Pattern.compile("^(.*[/\\\\])\\*([.\\w+]*)$").matcher(templateName);
108+
if(fileExtension == null && assetFile.toString().matches(Pattern.quote(pathName) + "(?!.*[/\\\\]).*\\.\\w+")) {
109+
virtualFiles.add(assetFile.getFile());
110+
} else if(fileExtension != null && assetFile.toString().matches(Pattern.quote(pathName) + "(?!.*[/\\\\]).*" + Pattern.quote(fileExtension))) {
111+
virtualFiles.add(assetFile.getFile());
112+
}
113+
114+
*/
115+
Collection<VirtualFile> files = new ArrayList<>();
116+
117+
VirtualFile webDirectory = getProjectAssetRoot(project);
118+
if (null == webDirectory) {
119+
return files;
120+
}
121+
122+
String assetName = StringUtils.stripStart(filename.replace("\\", "/").replaceAll("/+", "/"), "/");
123+
124+
Matcher matcher = Pattern.compile("^(.*[/\\\\])\\*([.\\w+]*)$").matcher(assetName);
125+
if (!matcher.find()) {
126+
VirtualFile assetFile = VfsUtil.findRelativeFile(webDirectory, assetName.split("/"));
127+
if(assetFile != null) {
128+
files.add(assetFile);
129+
}
130+
} else {
131+
132+
String pathName = matcher.group(1);
133+
String fileExtension = matcher.group(2).length() > 0 ? matcher.group(2) : null;
134+
135+
pathName = StringUtils.stripEnd(pathName, "/");
136+
137+
if(fileExtension == null) {
138+
// @TODO: filter files
139+
// 'assets/js/*'
140+
VirtualFile assetFile = VfsUtil.findRelativeFile(webDirectory, pathName.split("/"));
141+
if(assetFile != null) {
142+
files.add(assetFile);
143+
}
144+
} else {
145+
// @TODO: filter files
146+
// 'assets/js/*.js'
147+
VirtualFile assetFile = VfsUtil.findRelativeFile(webDirectory, pathName.split("/"));
148+
if(assetFile != null) {
149+
files.add(assetFile);
150+
}
151+
}
152+
}
153+
154+
return files;
155+
}
156+
90157
private boolean isValidFile(@NotNull VirtualFile virtualFile) {
91-
if (this.filterExtension.size() == 0 || virtualFile.isDirectory()) {
158+
if (virtualFile.isDirectory()) {
92159
return false;
93160
}
94161

162+
if(filterExtension.size() == 0) {
163+
return true;
164+
}
165+
95166
String extension = virtualFile.getExtension();
96167
return extension != null && this.filterExtension.contains(extension);
97168
}

src/fr/adrienbrault/idea/symfony2plugin/asset/dic/AssetEnum.java renamed to src/fr/adrienbrault/idea/symfony2plugin/asset/AssetEnum.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package fr.adrienbrault.idea.symfony2plugin.asset.dic;
1+
package fr.adrienbrault.idea.symfony2plugin.asset;
22

33
/**
44
* @author Daniel Espendiller <daniel@espendiller.net>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package fr.adrienbrault.idea.symfony2plugin.asset;
2+
3+
import com.intellij.openapi.vfs.VfsUtil;
4+
import com.intellij.openapi.vfs.VirtualFile;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
/**
8+
* @author Daniel Espendiller <daniel@espendiller.net>
9+
*/
10+
public class AssetFile {
11+
@NotNull
12+
private VirtualFile assetFile;
13+
14+
@NotNull
15+
private AssetEnum.Position assetPosition;
16+
17+
@NotNull
18+
private VirtualFile relativeFolder;
19+
20+
private String prefix = "";
21+
22+
public AssetFile(@NotNull VirtualFile assetFile, @NotNull AssetEnum.Position assetPosition, @NotNull VirtualFile relativeFolder, @NotNull String prefix) {
23+
this(assetFile, assetPosition, relativeFolder);
24+
this.prefix = prefix;
25+
}
26+
27+
public AssetFile(@NotNull VirtualFile assetFile, @NotNull AssetEnum.Position assetPosition, @NotNull VirtualFile relativeFolder) {
28+
this.assetFile = assetFile;
29+
this.assetPosition = assetPosition;
30+
this.relativeFolder = relativeFolder;
31+
}
32+
33+
@NotNull
34+
public VirtualFile getFile() {
35+
return assetFile;
36+
}
37+
38+
@NotNull
39+
public AssetEnum.Position getAssetPosition() {
40+
return assetPosition;
41+
}
42+
43+
public String toString() {
44+
return this.prefix + VfsUtil.getRelativePath(assetFile, relativeFolder, '/');
45+
}
46+
}

src/fr/adrienbrault/idea/symfony2plugin/asset/AssetLookupElement.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import com.intellij.codeInsight.lookup.LookupElementPresentation;
77
import com.intellij.openapi.project.Project;
88
import com.intellij.util.IconUtil;
9-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetEnum;
10-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetFile;
119
import fr.adrienbrault.idea.symfony2plugin.util.dict.ResourceFileInsertHandler;
1210
import org.jetbrains.annotations.NotNull;
1311

src/fr/adrienbrault/idea/symfony2plugin/asset/dic/AssetFile.java

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/fr/adrienbrault/idea/symfony2plugin/asset/provider/AssetCompletionProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
import com.intellij.util.ProcessingContext;
1010
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
1111
import fr.adrienbrault.idea.symfony2plugin.asset.AssetLookupElement;
12-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetDirectoryReader;
13-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetFile;
12+
import fr.adrienbrault.idea.symfony2plugin.asset.AssetDirectoryReader;
13+
import fr.adrienbrault.idea.symfony2plugin.asset.AssetFile;
1414
import fr.adrienbrault.idea.symfony2plugin.twig.assets.TwigNamedAssetsServiceParser;
1515
import fr.adrienbrault.idea.symfony2plugin.util.service.ServiceXmlParserFactory;
1616
import org.jetbrains.annotations.NotNull;

src/fr/adrienbrault/idea/symfony2plugin/templating/TwigTemplateCompletionContributor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import com.jetbrains.twig.elements.TwigElementTypes;
2121
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
2222
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
23-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetDirectoryReader;
23+
import fr.adrienbrault.idea.symfony2plugin.asset.AssetDirectoryReader;
2424
import fr.adrienbrault.idea.symfony2plugin.asset.provider.AssetCompletionProvider;
2525
import fr.adrienbrault.idea.symfony2plugin.routing.RouteHelper;
2626
import fr.adrienbrault.idea.symfony2plugin.templating.completion.QuotedInsertionLookupElement;

src/fr/adrienbrault/idea/symfony2plugin/templating/completion/TwigHtmlCompletionContributor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import com.intellij.util.ProcessingContext;
99
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
1010
import fr.adrienbrault.idea.symfony2plugin.asset.AssetLookupElement;
11-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetDirectoryReader;
12-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetFile;
11+
import fr.adrienbrault.idea.symfony2plugin.asset.AssetDirectoryReader;
12+
import fr.adrienbrault.idea.symfony2plugin.asset.AssetFile;
1313
import fr.adrienbrault.idea.symfony2plugin.routing.RouteHelper;
1414
import fr.adrienbrault.idea.symfony2plugin.routing.RouteLookupElement;
1515
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigHtmlCompletionUtil;

src/fr/adrienbrault/idea/symfony2plugin/templating/inspection/TwigAssetMissingInspection.java

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
import com.intellij.psi.PsiElementVisitor;
77
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
88
import fr.adrienbrault.idea.symfony2plugin.templating.TwigPattern;
9-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetDirectoryReader;
10-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetFile;
119
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
10+
import org.apache.commons.lang.StringUtils;
1211
import org.jetbrains.annotations.NotNull;
1312

1413
/**
@@ -23,25 +22,34 @@ public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, bool
2322
return super.buildVisitor(holder, isOnTheFly);
2423
}
2524

26-
return new PsiElementVisitor() {
27-
@Override
28-
public void visitElement(PsiElement element) {
29-
if(TwigPattern.getAutocompletableAssetPattern().accepts(element) && TwigUtil.isValidStringWithoutInterpolatedOrConcat(element)) {
30-
invoke(element, holder);
31-
}
25+
return new MyPsiElementVisitor(holder);
26+
}
27+
28+
private class MyPsiElementVisitor extends PsiElementVisitor {
29+
30+
private final ProblemsHolder holder;
3231

33-
super.visitElement(element);
32+
MyPsiElementVisitor(ProblemsHolder holder) {
33+
this.holder = holder;
34+
}
35+
36+
@Override
37+
public void visitElement(PsiElement element) {
38+
if(TwigPattern.getAutocompletableAssetPattern().accepts(element) && TwigUtil.isValidStringWithoutInterpolatedOrConcat(element)) {
39+
invoke(element, holder);
3440
}
35-
};
36-
}
3741

38-
private void invoke(@NotNull PsiElement element, @NotNull ProblemsHolder holder) {
39-
for (final AssetFile assetFile : new AssetDirectoryReader().getAssetFiles(element.getProject())) {
40-
if(assetFile.toString().equals(element.getText())) {
42+
super.visitElement(element);
43+
}
44+
45+
private void invoke(@NotNull PsiElement element, @NotNull ProblemsHolder holder) {
46+
String asset = element.getText();
47+
48+
if(StringUtils.isBlank(asset) || TwigUtil.resolveAssetsFiles(element.getProject(), asset).size() > 0) {
4149
return;
4250
}
43-
}
4451

45-
holder.registerProblem(element, "Missing asset");
52+
holder.registerProblem(element, "Missing asset");
53+
}
4654
}
4755
}

src/fr/adrienbrault/idea/symfony2plugin/templating/util/TwigUtil.java

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@
3535
import de.espend.idea.php.annotation.util.AnnotationUtil;
3636
import fr.adrienbrault.idea.symfony2plugin.Settings;
3737
import fr.adrienbrault.idea.symfony2plugin.action.comparator.ValueComparator;
38-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetDirectoryReader;
39-
import fr.adrienbrault.idea.symfony2plugin.asset.dic.AssetFile;
38+
import fr.adrienbrault.idea.symfony2plugin.asset.AssetDirectoryReader;
4039
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtension;
4140
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtensionParameter;
4241
import fr.adrienbrault.idea.symfony2plugin.stubs.SymfonyProcessors;
@@ -1385,15 +1384,15 @@ public static String getTwigMethodString(@Nullable PsiElement transPsiElement) {
13851384
return null;
13861385
}
13871386

1388-
public static Set<VirtualFile> resolveAssetsFiles(@NotNull Project project, @NotNull String templateName, @NotNull String... fileTypes) {
1389-
Set<VirtualFile> virtualFiles = new HashSet<>();
1387+
public static Collection<VirtualFile> resolveAssetsFiles(@NotNull Project project, @NotNull String assetName, @NotNull String... fileTypes) {
1388+
Collection<VirtualFile> virtualFiles = new HashSet<>();
13901389

13911390
// {% javascripts [...] @jquery_js2'%}
1392-
if(templateName.startsWith("@") && templateName.length() > 1) {
1391+
if(assetName.startsWith("@") && assetName.length() > 1) {
13931392
TwigNamedAssetsServiceParser twigPathServiceParser = ServiceXmlParserFactory.getInstance(project, TwigNamedAssetsServiceParser.class);
1394-
String assetName = templateName.substring(1);
1395-
if(twigPathServiceParser.getNamedAssets().containsKey(assetName)) {
1396-
for (String s : twigPathServiceParser.getNamedAssets().get(assetName)) {
1393+
String assetNameShortcut = assetName.substring(1);
1394+
if(twigPathServiceParser.getNamedAssets().containsKey(assetNameShortcut)) {
1395+
for (String s : twigPathServiceParser.getNamedAssets().get(assetNameShortcut)) {
13971396
VirtualFile fileByURL = VfsUtil.findFileByIoFile(new File(s), false);
13981397
if(fileByURL != null) {
13991398
virtualFiles.add(fileByURL);
@@ -1403,41 +1402,7 @@ public static Set<VirtualFile> resolveAssetsFiles(@NotNull Project project, @Not
14031402

14041403
}
14051404

1406-
// dont matches wildcard:
1407-
// {% javascripts '@SampleBundle/Resources/public/js/*' %}
1408-
// {% javascripts 'assets/js/*' %}
1409-
// {% javascripts 'assets/js/*.js' %}
1410-
Matcher matcher = Pattern.compile("^(.*[/\\\\])\\*([.\\w+]*)$").matcher(templateName);
1411-
if (!matcher.find()) {
1412-
1413-
// directly resolve
1414-
VirtualFile projectAssetRoot = AssetDirectoryReader.getProjectAssetRoot(project);
1415-
if(projectAssetRoot != null) {
1416-
VirtualFile relativeFile = VfsUtil.findRelativeFile(projectAssetRoot, templateName);
1417-
if(relativeFile != null) {
1418-
virtualFiles.add(relativeFile);
1419-
}
1420-
}
1421-
1422-
for (final AssetFile assetFile : new AssetDirectoryReader(fileTypes, true).getAssetFiles(project)) {
1423-
if(assetFile.toString().equals(templateName)) {
1424-
virtualFiles.add(assetFile.getFile());
1425-
}
1426-
}
1427-
1428-
return virtualFiles;
1429-
}
1430-
1431-
String pathName = matcher.group(1);
1432-
String fileExtension = matcher.group(2).length() > 0 ? matcher.group(2) : null;
1433-
1434-
for (final AssetFile assetFile : new AssetDirectoryReader(fileTypes, true).getAssetFiles(project)) {
1435-
if(fileExtension == null && assetFile.toString().matches(Pattern.quote(pathName) + "(?!.*[/\\\\]).*\\.\\w+")) {
1436-
virtualFiles.add(assetFile.getFile());
1437-
} else if(fileExtension != null && assetFile.toString().matches(Pattern.quote(pathName) + "(?!.*[/\\\\]).*" + Pattern.quote(fileExtension))) {
1438-
virtualFiles.add(assetFile.getFile());
1439-
}
1440-
}
1405+
virtualFiles.addAll(new AssetDirectoryReader(fileTypes, true).resolveAssetFile(project, assetName));
14411406

14421407
return virtualFiles;
14431408
}

0 commit comments

Comments
 (0)