Skip to content

Commit e1d6cef

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

File tree

5 files changed

+134
-47
lines changed

5 files changed

+134
-47
lines changed

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

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@
1919
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
2020
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
2121
import fr.adrienbrault.idea.symfony2plugin.twig.utils.TwigFileUtil;
22-
import icons.TwigIcons;
2322
import org.apache.commons.lang.StringUtils;
2423
import org.jetbrains.annotations.NotNull;
25-
import org.jetbrains.annotations.Nullable;
2624

2725
import java.util.Collection;
2826
import java.util.List;
@@ -44,34 +42,14 @@ protected boolean isValidForFile(@NotNull Project project, @NotNull Editor edito
4442
return Symfony2ProjectComponent.isEnabled(project) && (
4543
file instanceof TwigFile
4644
|| (file instanceof HtmlFileImpl && file.getName().toLowerCase().endsWith(".twig"))
47-
|| getInjectedTwigElement(file, editor) != null
45+
|| TwigUtil.getInjectedTwigElement(file, editor) != null
4846
);
4947
}
5048

51-
@Nullable
52-
private static PsiElement getInjectedTwigElement(@NotNull PsiFile psiFile, @NotNull Editor editor) {
53-
int caretOffset = editor.getCaretModel().getOffset();
54-
if(caretOffset <= 0) {
55-
return null;
56-
}
57-
58-
PsiElement psiElement = psiFile.findElementAt(caretOffset - 1);
59-
if(psiElement == null) {
60-
return null;
61-
}
62-
63-
return TwigUtil.getElementOnTwigViewProvider(psiElement);
64-
}
65-
6649
private static class MyCodeInsightActionHandler implements CodeInsightActionHandler {
6750
@Override
6851
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
69-
int caretOffset = editor.getCaretModel().getOffset();
70-
if(caretOffset <= 0) {
71-
return;
72-
}
73-
74-
PsiElement psiElement = getInjectedTwigElement(file, editor);
52+
PsiElement psiElement = TwigUtil.getInjectedTwigElement(file, editor);
7553
if(psiElement == null) {
7654
return;
7755
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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 fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
23+
import org.jetbrains.annotations.NotNull;
24+
25+
import java.util.*;
26+
import java.util.function.Function;
27+
import java.util.stream.Collectors;
28+
29+
/**
30+
* @author Daniel Espendiller <daniel@espendiller.net>
31+
*/
32+
public class TwigExtendsGenerator extends CodeInsightAction {
33+
@Override
34+
protected @NotNull
35+
CodeInsightActionHandler getHandler() {
36+
return new TwigExtendsGenerator.MyCodeInsightActionHandler();
37+
}
38+
39+
@Override
40+
protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
41+
return Symfony2ProjectComponent.isEnabled(project) && (
42+
file instanceof TwigFile
43+
|| (file instanceof HtmlFileImpl && file.getName().toLowerCase().endsWith(".twig"))
44+
|| TwigUtil.getInjectedTwigElement(file, editor) != null
45+
);
46+
}
47+
48+
private static class MyCodeInsightActionHandler implements CodeInsightActionHandler {
49+
@Override
50+
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
51+
PsiElement psiElement = TwigUtil.getInjectedTwigElement(file, editor);
52+
if(psiElement == null) {
53+
return;
54+
}
55+
56+
Set<String> allKeys = FileBasedIndex.getInstance().getAllKeys(TwigExtendsStubIndex.KEY, project)
57+
.stream()
58+
.filter(s -> !s.toLowerCase().contains("@webprofiler") && !s.toLowerCase().contains("/profiler/") && !s.toLowerCase().contains("@twig") && !s.equalsIgnoreCase("form_div_layout.html.twig"))
59+
.collect(Collectors.toSet());
60+
61+
Map<String, Integer> extendsWithFileCountUsage = new HashMap<>();
62+
for (String allKey : allKeys) {
63+
Collection<VirtualFile> containingFiles = FileBasedIndex.getInstance().getContainingFiles(TwigExtendsStubIndex.KEY, allKey, GlobalSearchScope.allScope(project));
64+
extendsWithFileCountUsage.put(allKey, containingFiles.size());
65+
}
66+
67+
List<String> prioritizedKeys = extendsWithFileCountUsage.entrySet()
68+
.stream()
69+
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
70+
.map(Map.Entry::getKey)
71+
.limit(40)
72+
.collect(Collectors.toList());
73+
74+
if (prioritizedKeys.size() == 0) {
75+
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
76+
HintManager.getInstance().showErrorHint(editor, "No extends found");
77+
}
78+
79+
return;
80+
}
81+
82+
JBPopupFactory.getInstance().createPopupChooserBuilder(prioritizedKeys)
83+
.setTitle("Symfony: Twig Extends")
84+
.setItemsChosenCallback(strings -> {
85+
try {
86+
WriteCommandAction.writeCommandAction(editor.getProject())
87+
.withName("Twig Extends")
88+
.run((ThrowableRunnable<Throwable>) () -> {
89+
String content = strings.stream()
90+
.map((Function<String, String>) s -> "{% extends '" + s + "' %}")
91+
.collect(Collectors.joining("\n"));
92+
93+
PhpInsertHandlerUtil.insertStringAtCaret(editor, content);
94+
});
95+
} catch (Throwable ignored) {
96+
}
97+
})
98+
.createPopup()
99+
.showInBestPositionFor(editor);
100+
}
101+
}
102+
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.intellij.codeInsight.lookup.LookupElement;
44
import com.intellij.codeInsight.lookup.LookupElementBuilder;
5+
import com.intellij.openapi.editor.Editor;
56
import com.intellij.openapi.extensions.ExtensionPointName;
67
import com.intellij.openapi.project.Project;
78
import com.intellij.openapi.util.Key;
@@ -2439,6 +2440,26 @@ public static Collection<PhpClass> getTwigExtensionClasses(@NotNull Project proj
24392440
.collect(Collectors.toCollection(HashSet::new));
24402441
}
24412442

2443+
@Nullable
2444+
public static PsiElement getInjectedTwigElement(@NotNull PsiFile psiFile, @NotNull Editor editor) {
2445+
int caretOffset = editor.getCaretModel().getOffset();
2446+
if(caretOffset < 0) {
2447+
return null;
2448+
}
2449+
2450+
// last and first element of file are tricky :)
2451+
if (caretOffset == 0) {
2452+
return psiFile;
2453+
}
2454+
2455+
PsiElement psiElement = psiFile.findElementAt(caretOffset - 1);
2456+
if(psiElement == null) {
2457+
return null;
2458+
}
2459+
2460+
return TwigUtil.getElementOnTwigViewProvider(psiElement);
2461+
}
2462+
24422463
/**
24432464
* Resolve html language injection
24442465
*/

src/main/java/fr/adrienbrault/idea/symfony2plugin/twig/action/TwigTranslationGeneratorAction.java

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
1919
import org.apache.commons.lang.StringUtils;
2020
import org.jetbrains.annotations.NotNull;
21-
import org.jetbrains.annotations.Nullable;
2221

2322
import java.util.List;
2423
import java.util.stream.Collectors;
@@ -32,7 +31,7 @@ protected boolean isValidForFile(@NotNull Project project, @NotNull Editor edito
3231
return Symfony2ProjectComponent.isEnabled(project) && (
3332
file instanceof TwigFile
3433
|| (file instanceof HtmlFileImpl && file.getName().toLowerCase().endsWith(".twig"))
35-
|| getInjectedTwigElement(file, editor) != null
34+
|| TwigUtil.getInjectedTwigElement(file, editor) != null
3635
);
3736
}
3837

@@ -42,30 +41,10 @@ protected CodeInsightActionHandler getHandler() {
4241
return new MyCodeInsightActionHandler();
4342
}
4443

45-
@Nullable
46-
private static PsiElement getInjectedTwigElement(@NotNull PsiFile psiFile, @NotNull Editor editor) {
47-
int caretOffset = editor.getCaretModel().getOffset();
48-
if(caretOffset <= 0) {
49-
return null;
50-
}
51-
52-
PsiElement psiElement = psiFile.findElementAt(caretOffset);
53-
if(psiElement == null) {
54-
return null;
55-
}
56-
57-
return TwigUtil.getElementOnTwigViewProvider(psiElement);
58-
}
59-
6044
private static class MyCodeInsightActionHandler implements CodeInsightActionHandler {
6145
@Override
6246
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile psiFile) {
63-
int caretOffset = editor.getCaretModel().getOffset();
64-
if(caretOffset <= 0) {
65-
return;
66-
}
67-
68-
PsiElement psiElement = getInjectedTwigElement(psiFile, editor);
47+
PsiElement psiElement = TwigUtil.getInjectedTwigElement(psiFile, editor);
6948
if(psiElement == null) {
7049
return;
7150
}

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)