Skip to content

Commit 1f330f4

Browse files
authored
Merge pull request #1924 from Haehnchen/feature/567-block-anywhere-search
#567 support Twig blocks in search everywhere
2 parents a631a02 + 5b36cf5 commit 1f330f4

File tree

5 files changed

+135
-0
lines changed

5 files changed

+135
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package fr.adrienbrault.idea.symfony2plugin.navigation;
2+
3+
import com.intellij.navigation.ChooseByNameContributor;
4+
import com.intellij.navigation.NavigationItem;
5+
import com.intellij.openapi.project.Project;
6+
import com.intellij.openapi.util.Key;
7+
import com.intellij.openapi.vfs.VirtualFile;
8+
import com.intellij.psi.PsiFile;
9+
import com.intellij.psi.search.GlobalSearchScope;
10+
import com.intellij.psi.util.CachedValue;
11+
import com.intellij.psi.util.CachedValueProvider;
12+
import com.intellij.psi.util.CachedValuesManager;
13+
import com.intellij.util.indexing.FileBasedIndex;
14+
import com.jetbrains.twig.TwigFile;
15+
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
16+
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
17+
import fr.adrienbrault.idea.symfony2plugin.stubs.cache.FileIndexCaches;
18+
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TwigBlockIndexExtension;
19+
import fr.adrienbrault.idea.symfony2plugin.templating.dict.TwigBlock;
20+
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
21+
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
22+
import org.jetbrains.annotations.NotNull;
23+
24+
import java.util.*;
25+
import java.util.function.Function;
26+
import java.util.stream.Collectors;
27+
28+
/**
29+
* @author Daniel Espendiller <daniel@espendiller.net>
30+
*/
31+
public class TwigBlockSymbolContributor implements ChooseByNameContributor {
32+
private static final Key<CachedValue<String[]>> SYMFONY_TWIG_BLOCK_NAMES = new Key<>("SYMFONY_TWIG_BLOCK_NAMES");
33+
34+
@Override
35+
public String @NotNull [] getNames(Project project, boolean b) {
36+
if(!Symfony2ProjectComponent.isEnabled(project)) {
37+
return new String[0];
38+
}
39+
40+
return CachedValuesManager.getManager(project).getCachedValue(
41+
project,
42+
SYMFONY_TWIG_BLOCK_NAMES,
43+
() -> {
44+
String[] blocks = FileBasedIndex.getInstance()
45+
.getValues(TwigBlockIndexExtension.KEY, "block", GlobalSearchScope.allScope(project))
46+
.stream()
47+
.flatMap(Collection::stream)
48+
.distinct()
49+
.toArray(String[]::new);
50+
51+
return CachedValueProvider.Result.create(blocks, FileIndexCaches.getModificationTrackerForIndexId(project, TwigBlockIndexExtension.KEY));
52+
},
53+
false
54+
);
55+
}
56+
57+
@NotNull
58+
@Override
59+
public NavigationItem[] getItemsByName(String name, String s2, Project project, boolean b) {
60+
if(!Symfony2ProjectComponent.isEnabled(project)) {
61+
return new NavigationItem[0];
62+
}
63+
64+
FileBasedIndex.AllKeysQuery<String, Set<String>> query = new FileBasedIndex.AllKeysQuery<>(
65+
TwigBlockIndexExtension.KEY,
66+
List.of("block"),
67+
strings -> strings.contains(name)
68+
);
69+
70+
Set<VirtualFile> virtualFiles = new HashSet<>();
71+
FileBasedIndex.getInstance().processFilesContainingAllKeys(List.of(query), GlobalSearchScope.allScope(project), virtualFile -> {
72+
virtualFiles.add(virtualFile);
73+
return true;
74+
});
75+
76+
Collection<NavigationItem> navigationItems = new HashSet<>();
77+
78+
for (PsiFile psiFile : PsiElementUtils.convertVirtualFilesToPsiFiles(project, virtualFiles)) {
79+
if (psiFile instanceof TwigFile) {
80+
navigationItems.addAll(TwigUtil.getBlocksInFile((TwigFile) psiFile).stream().map((Function<TwigBlock, NavigationItem>) twigBlock -> new NavigationItemEx(twigBlock.getTarget(), twigBlock.getName(), Symfony2Icons.TWIG_BLOCK_OVERWRITE, "Block")).collect(Collectors.toSet()));
81+
}
82+
}
83+
84+
return navigationItems.toArray(new NavigationItem[0]);
85+
}
86+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@
242242
<gotoSymbolContributor implementation="fr.adrienbrault.idea.symfony2plugin.navigation.ServiceSymbolContributor"/>
243243
<gotoSymbolContributor implementation="fr.adrienbrault.idea.symfony2plugin.navigation.RouteSymbolContributor"/>
244244
<gotoSymbolContributor implementation="fr.adrienbrault.idea.symfony2plugin.navigation.SymfonyCommandSymbolContributor"/>
245+
<gotoSymbolContributor implementation="fr.adrienbrault.idea.symfony2plugin.navigation.TwigBlockSymbolContributor"/>
245246

246247
<implicitUsageProvider implementation="fr.adrienbrault.idea.symfony2plugin.codeInsight.SymfonyImplicitUsageProvider"/>
247248

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package fr.adrienbrault.idea.symfony2plugin.tests.navigation;
2+
3+
import fr.adrienbrault.idea.symfony2plugin.navigation.TwigBlockSymbolContributor;
4+
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
5+
6+
import java.util.Arrays;
7+
8+
/**
9+
* @author Daniel Espendiller <daniel@espendiller.net>
10+
*
11+
* @see fr.adrienbrault.idea.symfony2plugin.navigation.TwigBlockSymbolContributor
12+
*/
13+
public class TwigBlockSymbolContributorTest extends SymfonyLightCodeInsightFixtureTestCase {
14+
public void setUp() throws Exception {
15+
super.setUp();
16+
myFixture.copyFileToProject("test.html.twig");
17+
myFixture.copyFileToProject("test2.html.twig");
18+
}
19+
20+
protected String getTestDataPath() {
21+
return "src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/navigation/fixtures";
22+
}
23+
24+
25+
public void testThatBlockNamesAreProvidedForSearch() {
26+
TwigBlockSymbolContributor contributor = new TwigBlockSymbolContributor();
27+
28+
assertContainsElements(
29+
Arrays.asList(contributor.getNames(getProject(), false)),
30+
"my_support_block_name",
31+
"my_support_block_name_2"
32+
);
33+
}
34+
35+
public void testThatBlockNavigationIsProvidedForSearch() {
36+
TwigBlockSymbolContributor contributor = new TwigBlockSymbolContributor();
37+
38+
assertTrue(Arrays.stream(contributor.getItemsByName("my_support_block_name", "?", getProject(), false))
39+
.anyMatch(navigationItem -> "my_support_block_name".equals(navigationItem.getName())));
40+
41+
assertTrue(Arrays.stream(contributor.getItemsByName("my_support_block_name_2", "?", getProject(), false))
42+
.anyMatch(navigationItem -> "my_support_block_name_2".equals(navigationItem.getName())));
43+
44+
assertSize(0, contributor.getItemsByName("UNKNOWN_BLOCK", "?", getProject(), false));
45+
}
46+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{% block my_support_block_name %}{% endblock %}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{% block my_support_block_name_2 %}{% endblock %}

0 commit comments

Comments
 (0)