Skip to content

Commit da05362

Browse files
committed
Refactor translation index handling with caching and improve domain/key resolution logic
1 parent 0cb113b commit da05362

5 files changed

Lines changed: 99 additions & 42 deletions

File tree

src/main/java/fr/adrienbrault/idea/symfony2plugin/config/ServiceLineMarkerProvider.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,8 @@ private void constraintMessagePropertyMarker(@NotNull PsiElement psiElement, @No
341341
PsiElement parent = psiElement.getParent();
342342
if (parent instanceof StringLiteralExpression && TranslationUtil.isConstraintPropertyField((StringLiteralExpression) parent)) {
343343
String contents = ((StringLiteralExpression) parent).getContents();
344-
PsiElement[] validators = TranslationUtil.getTranslationPsiElements(psiElement.getProject(), contents, "validators");
345344

346-
if (validators.length > 0) {
345+
if (TranslationUtil.hasTranslationKey(psiElement.getProject(), contents, "validators")) {
347346
NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder.create(Symfony2Icons.TRANSLATION)
348347
.setTargets(NotNullLazyValue.lazy(() -> Arrays.asList(TranslationUtil.getTranslationPsiElements(psiElement.getProject(), contents, "validators"))))
349348
.setTooltipText("Navigate to translation");

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/dict/TranslationUtil.java

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,10 @@ public static Collection<VirtualFile> getDomainFilesFromCompiledContainer(@NotNu
8686
DomainMappings domainMappings = ServiceXmlParserFactory.getInstance(project, DomainMappings.class);
8787
Collection<VirtualFile> virtualFiles = new ArrayList<>();
8888

89-
for(DomainFileMap domain: domainMappings.getDomainFileMaps()) {
90-
if(domain.getDomain().equals(domainName)) {
91-
VirtualFile virtualFile = domain.getFile();
92-
if(virtualFile != null) {
93-
virtualFiles.add(virtualFile);
94-
}
89+
for(DomainFileMap domain: domainMappings.getDomainFileMaps(domainName)) {
90+
VirtualFile virtualFile = domain.getFile();
91+
if(virtualFile != null) {
92+
virtualFiles.add(virtualFile);
9593
}
9694
}
9795

@@ -116,21 +114,13 @@ public static Collection<PsiElement> getTranslationKeyFromCompiledContainerDomai
116114

117115
public static boolean hasDomainInsideCompiledContainer(@NotNull Project project, @NotNull String domainName) {
118116
DomainMappings domainMappings = ServiceXmlParserFactory.getInstance(project, DomainMappings.class);
119-
for(DomainFileMap domain: domainMappings.getDomainFileMaps()) {
120-
if(domain.getDomain().equals(domainName)) {
121-
return true;
122-
}
123-
}
124-
125-
return false;
117+
return domainMappings.hasDomain(domainName);
126118
}
127119

128120
static public Collection<String> getDomainsFromContainer(@NotNull Project project) {
129121
DomainMappings domainMappings = ServiceXmlParserFactory.getInstance(project, DomainMappings.class);
130122

131-
return domainMappings.getDomainFileMaps().stream()
132-
.map(DomainFileMap::getDomain)
133-
.collect(Collectors.toSet());
123+
return domainMappings.getDomains();
134124
}
135125

136126
/**
@@ -263,10 +253,6 @@ public static boolean hasDomain(@NotNull Project project, @NotNull String domain
263253
}
264254

265255
public static boolean hasTranslationKey(@NotNull Project project, String keyName, String domainName) {
266-
if(!hasDomain(project, domainName)) {
267-
return false;
268-
}
269-
270256
return Arrays.stream(getTranslationProviders())
271257
.anyMatch(translatorProvider -> translatorProvider.hasTranslationKey(project, keyName, domainName));
272258
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/parser/DomainMappings.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import fr.adrienbrault.idea.symfony2plugin.translation.dict.DomainFileMap;
44
import fr.adrienbrault.idea.symfony2plugin.util.service.AbstractServiceParser;
55
import org.apache.commons.lang3.StringUtils;
6+
import org.jetbrains.annotations.NotNull;
67
import org.w3c.dom.Element;
78
import org.w3c.dom.NodeList;
89

@@ -12,6 +13,9 @@
1213
import java.util.Collection;
1314
import java.util.Collections;
1415
import java.util.List;
16+
import java.util.Map;
17+
import java.util.Set;
18+
import java.util.concurrent.ConcurrentHashMap;
1519
import java.util.concurrent.CopyOnWriteArrayList;
1620

1721
/**
@@ -20,6 +24,8 @@
2024
public class DomainMappings extends AbstractServiceParser {
2125

2226
protected final List<DomainFileMap> domainFileMaps = new CopyOnWriteArrayList<>();
27+
private final Map<String, List<DomainFileMap>> domainFileMapsByDomain = new ConcurrentHashMap<>();
28+
private final Set<String> domains = ConcurrentHashMap.newKeySet();
2329

2430
@Override
2531
public String getXPathFilter() {
@@ -51,7 +57,7 @@ public void parser(InputStream file, VirtualFile sourceFile, Project project) {
5157
}
5258

5359
if (StringUtils.isNotBlank(domain)) {
54-
this.domainFileMaps.add(new DomainFileMap(
60+
this.addDomainFileMap(new DomainFileMap(
5561
arguments.item(0).getTextContent(),
5662
arguments.item(1).getTextContent(),
5763
arguments.item(2).getTextContent(),
@@ -78,7 +84,7 @@ public void parser(InputStream file, VirtualFile sourceFile, Project project) {
7884
}
7985

8086
if (StringUtils.isNotBlank(split[0])) {
81-
this.domainFileMaps.add(new DomainFileMap(split[2], path, split[1], split[0]));
87+
this.addDomainFileMap(new DomainFileMap(split[2], path, split[1], split[0]));
8288
}
8389
}
8490
}
@@ -89,4 +95,24 @@ public void parser(InputStream file, VirtualFile sourceFile, Project project) {
8995
public Collection<DomainFileMap> getDomainFileMaps() {
9096
return Collections.synchronizedList(domainFileMaps);
9197
}
92-
}
98+
99+
public Collection<DomainFileMap> getDomainFileMaps(@NotNull String domainName) {
100+
return domainFileMapsByDomain.getOrDefault(domainName, Collections.emptyList());
101+
}
102+
103+
public boolean hasDomain(@NotNull String domainName) {
104+
return domains.contains(domainName);
105+
}
106+
107+
public Collection<String> getDomains() {
108+
return Collections.unmodifiableSet(domains);
109+
}
110+
111+
private void addDomainFileMap(@NotNull DomainFileMap domainFileMap) {
112+
this.domainFileMaps.add(domainFileMap);
113+
this.domains.add(domainFileMap.getDomain());
114+
this.domainFileMapsByDomain
115+
.computeIfAbsent(domainFileMap.getDomain(), ignored -> new CopyOnWriteArrayList<>())
116+
.add(domainFileMap);
117+
}
118+
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/translation/provider/IndexTranslatorProvider.java

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
package fr.adrienbrault.idea.symfony2plugin.translation.provider;
22

33
import com.intellij.openapi.project.Project;
4+
import com.intellij.openapi.util.Key;
45
import com.intellij.openapi.vfs.VirtualFile;
56
import com.intellij.psi.PsiElement;
67
import com.intellij.psi.PsiFile;
78
import com.intellij.psi.search.GlobalSearchScope;
9+
import com.intellij.psi.util.CachedValue;
10+
import com.intellij.psi.util.CachedValueProvider;
11+
import com.intellij.psi.util.CachedValuesManager;
812
import com.intellij.util.indexing.FileBasedIndex;
913
import com.jetbrains.php.PhpIndex;
1014
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProvider;
1115
import fr.adrienbrault.idea.symfony2plugin.extension.TranslatorProviderDict;
1216
import fr.adrienbrault.idea.symfony2plugin.stubs.SymfonyProcessors;
17+
import fr.adrienbrault.idea.symfony2plugin.stubs.cache.FileIndexCaches;
1318
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TranslationStubIndex;
1419
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
1520
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
1621
import org.jetbrains.annotations.NotNull;
1722

1823
import java.util.*;
24+
import java.util.concurrent.ConcurrentHashMap;
1925
import java.util.stream.Collectors;
2026

2127
/**
@@ -24,31 +30,26 @@
2430
* @author Daniel Espendiller <daniel@espendiller.net>
2531
*/
2632
public class IndexTranslatorProvider implements TranslatorProvider {
33+
private static final Key<CachedValue<Set<String>>> TRANSLATION_DOMAINS =
34+
Key.create("SYMFONY_TRANSLATION_DOMAINS");
35+
36+
private static final Key<CachedValue<Map<String, Set<String>>>> TRANSLATION_KEYS_BY_DOMAIN =
37+
Key.create("SYMFONY_TRANSLATION_KEYS_BY_DOMAIN");
38+
2739
@Override
2840
public boolean hasTranslationKey(@NotNull Project project, @NotNull String keyName, @NotNull String domainName) {
29-
for(Set<String> keys: FileBasedIndex.getInstance().getValues(TranslationStubIndex.KEY, domainName, GlobalSearchScope.allScope(project))){
30-
if(keys.contains(keyName)) {
31-
return true;
32-
}
33-
}
34-
35-
return false;
41+
return hasIndexedTranslationKey(project, keyName, domainName);
3642
}
3743

3844
@Override
3945
public boolean hasDomain(@NotNull Project project, @NotNull String domainName) {
40-
return !FileBasedIndex.getInstance().getValues(
41-
TranslationStubIndex.KEY,
42-
domainName,
43-
GlobalSearchScope.allScope(project)
44-
).isEmpty();
46+
return hasIndexedDomain(project, domainName);
4547
}
4648

4749
@NotNull
4850
@Override
4951
public Collection<TranslatorProviderDict.TranslationDomain> getTranslationDomains(@NotNull Project project) {
50-
return SymfonyProcessors
51-
.createResult(project, TranslationStubIndex.KEY)
52+
return getIndexedDomains(project)
5253
.stream()
5354
.map(s -> new TranslatorProviderDict.TranslationDomain(s, true))
5455
.collect(Collectors.toList());
@@ -88,11 +89,52 @@ public Collection<VirtualFile> getDomainPsiFiles(Project project, @NotNull Strin
8889
@NotNull
8990
@Override
9091
public Collection<TranslatorProviderDict.TranslationKey> getTranslationsForDomain(@NotNull Project project, @NotNull String domainName) {
91-
return FileBasedIndex.getInstance()
92-
.getValues(TranslationStubIndex.KEY, domainName, GlobalSearchScope.allScope(project))
92+
return getIndexedTranslationKeys(project, domainName)
9393
.stream()
94-
.flatMap(Collection::stream)
9594
.map(key -> new TranslatorProviderDict.TranslationKey(key, true))
9695
.collect(Collectors.toSet());
9796
}
97+
98+
@NotNull
99+
private static Map<String, Set<String>> getTranslationKeysByDomain(@NotNull Project project) {
100+
return CachedValuesManager.getManager(project).getCachedValue(
101+
project,
102+
TRANSLATION_KEYS_BY_DOMAIN,
103+
() -> CachedValueProvider.Result.create(
104+
new ConcurrentHashMap<>(),
105+
FileIndexCaches.getModificationTrackerForIndexId(project, TranslationStubIndex.KEY)
106+
),
107+
false
108+
);
109+
}
110+
111+
public static boolean hasIndexedTranslationKey(@NotNull Project project, @NotNull String keyName, @NotNull String domainName) {
112+
return getIndexedTranslationKeys(project, domainName).contains(keyName);
113+
}
114+
115+
public static boolean hasIndexedDomain(@NotNull Project project, @NotNull String domainName) {
116+
return getIndexedDomains(project).contains(domainName);
117+
}
118+
119+
@NotNull
120+
private static Set<String> getIndexedDomains(@NotNull Project project) {
121+
return FileIndexCaches.getIndexKeysCache(project, TRANSLATION_DOMAINS, TranslationStubIndex.KEY);
122+
}
123+
124+
@NotNull
125+
private static Set<String> getIndexedTranslationKeys(@NotNull Project project, @NotNull String domainName) {
126+
if (!hasIndexedDomain(project, domainName)) {
127+
return Collections.emptySet();
128+
}
129+
130+
return getTranslationKeysByDomain(project).computeIfAbsent(domainName, domain -> {
131+
FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();
132+
GlobalSearchScope scope = GlobalSearchScope.allScope(project);
133+
134+
return fileBasedIndex.getValues(TranslationStubIndex.KEY, domain, scope)
135+
.stream()
136+
.flatMap(Collection::stream)
137+
.collect(Collectors.toSet());
138+
});
139+
}
98140
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/translation/parser/DomainMappingsTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ public void testParser() throws Exception {
2828
Collection<DomainFileMap> domainFileMaps = domainMappings.getDomainFileMaps();
2929

3030
assertEquals(16, domainFileMaps.size());
31+
assertTrue(domainMappings.hasDomain("CraueFormFlowBundle"));
32+
assertFalse(domainMappings.hasDomain("missing_domain"));
33+
assertTrue(domainMappings.getDomains().contains("foobar_domain1"));
34+
assertEquals(1, domainMappings.getDomainFileMaps("foobar_domain1").size());
3135

3236
DomainFileMap craueFormFlowBundle = domainFileMaps.stream().filter(domainFileMap -> domainFileMap.getDomain().equals("CraueFormFlowBundle")).findFirst().get();
3337

0 commit comments

Comments
 (0)