Skip to content

Commit 06ee32a

Browse files
committed
add Twig "extends" generator action
1 parent b8ebae2 commit 06ee32a

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/templating/action/TwigBlockOverwriteGenerator.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,17 @@ protected boolean isValidForFile(@NotNull Project project, @NotNull Editor edito
4949
}
5050

5151
@Nullable
52-
private static PsiElement getInjectedTwigElement(@NotNull PsiFile psiFile, @NotNull Editor editor) {
52+
public static PsiElement getInjectedTwigElement(@NotNull PsiFile psiFile, @NotNull Editor editor) {
5353
int caretOffset = editor.getCaretModel().getOffset();
54-
if(caretOffset <= 0) {
54+
if(caretOffset < 0) {
5555
return null;
5656
}
5757

58+
// last and first element of file are tricky :)
59+
if (caretOffset == 0) {
60+
return psiFile;
61+
}
62+
5863
PsiElement psiElement = psiFile.findElementAt(caretOffset - 1);
5964
if(psiElement == null) {
6065
return null;
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package fr.adrienbrault.idea.symfony2plugin.templating.action;
2+
3+
import com.intellij.codeInsight.CodeInsightActionHandler;
4+
import com.intellij.codeInsight.actions.CodeInsightAction;
5+
import com.intellij.codeInsight.hint.HintManager;
6+
import com.intellij.openapi.application.ApplicationManager;
7+
import com.intellij.openapi.command.WriteCommandAction;
8+
import com.intellij.openapi.editor.Editor;
9+
import com.intellij.openapi.project.Project;
10+
import com.intellij.openapi.ui.popup.JBPopupFactory;
11+
import com.intellij.openapi.vfs.VirtualFile;
12+
import com.intellij.psi.PsiElement;
13+
import com.intellij.psi.PsiFile;
14+
import com.intellij.psi.impl.source.html.HtmlFileImpl;
15+
import com.intellij.psi.search.GlobalSearchScope;
16+
import com.intellij.util.ThrowableRunnable;
17+
import com.intellij.util.indexing.FileBasedIndex;
18+
import com.jetbrains.php.completion.insert.PhpInsertHandlerUtil;
19+
import com.jetbrains.twig.TwigFile;
20+
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
21+
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.TwigExtendsStubIndex;
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 TwigExtendsGenerator extends CodeInsightAction {
32+
@Override
33+
protected @NotNull
34+
CodeInsightActionHandler getHandler() {
35+
return new TwigExtendsGenerator.MyCodeInsightActionHandler();
36+
}
37+
38+
@Override
39+
protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
40+
return Symfony2ProjectComponent.isEnabled(project) && (
41+
file instanceof TwigFile
42+
|| (file instanceof HtmlFileImpl && file.getName().toLowerCase().endsWith(".twig"))
43+
|| TwigBlockOverwriteGenerator.getInjectedTwigElement(file, editor) != null
44+
);
45+
}
46+
47+
private static class MyCodeInsightActionHandler implements CodeInsightActionHandler {
48+
@Override
49+
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
50+
PsiElement psiElement = TwigBlockOverwriteGenerator.getInjectedTwigElement(file, editor);
51+
if(psiElement == null) {
52+
return;
53+
}
54+
55+
Set<String> allKeys = FileBasedIndex.getInstance().getAllKeys(TwigExtendsStubIndex.KEY, project)
56+
.stream()
57+
.filter(s -> !s.toLowerCase().contains("@webprofiler") && !s.toLowerCase().contains("/profiler/") && !s.toLowerCase().contains("@twig") && !s.equalsIgnoreCase("form_div_layout.html.twig"))
58+
.collect(Collectors.toSet());
59+
60+
Map<String, Integer> extendsWithFileCountUsage = new HashMap<>();
61+
for (String allKey : allKeys) {
62+
Collection<VirtualFile> containingFiles = FileBasedIndex.getInstance().getContainingFiles(TwigExtendsStubIndex.KEY, allKey, GlobalSearchScope.allScope(project));
63+
extendsWithFileCountUsage.put(allKey, containingFiles.size());
64+
}
65+
66+
List<String> prioritizedKeys = extendsWithFileCountUsage.entrySet()
67+
.stream()
68+
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
69+
.map(Map.Entry::getKey)
70+
.limit(40)
71+
.collect(Collectors.toList());
72+
73+
if (prioritizedKeys.size() == 0) {
74+
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
75+
HintManager.getInstance().showErrorHint(editor, "No extends found");
76+
}
77+
78+
return;
79+
}
80+
81+
JBPopupFactory.getInstance().createPopupChooserBuilder(prioritizedKeys)
82+
.setTitle("Symfony: Twig Extends")
83+
.setItemsChosenCallback(strings -> {
84+
try {
85+
WriteCommandAction.writeCommandAction(editor.getProject())
86+
.withName("Twig Extends")
87+
.run((ThrowableRunnable<Throwable>) () -> {
88+
String content = strings.stream()
89+
.map((Function<String, String>) s -> "{% extends '" + s + "' %}")
90+
.collect(Collectors.joining("\n"));
91+
92+
PhpInsertHandlerUtil.insertStringAtCaret(editor, content);
93+
});
94+
} catch (Throwable ignored) {
95+
}
96+
})
97+
.createPopup()
98+
.showInBestPositionFor(editor);
99+
}
100+
}
101+
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,13 @@
725725
<add-to-group group-id="GenerateGroup"/>
726726
</action>
727727

728+
<action icon="TwigIcons.TwigFileIcon"
729+
id="SymfonyTwigExtendsGenerator"
730+
class="fr.adrienbrault.idea.symfony2plugin.templating.action.TwigExtendsGenerator"
731+
text="Extends Tag">
732+
<add-to-group group-id="GenerateGroup"/>
733+
</action>
734+
728735
</actions>
729736
</idea-plugin>
730737

0 commit comments

Comments
 (0)