From bca0c120b90da4385c25e51bc740e9c5d3630546 Mon Sep 17 00:00:00 2001 From: Daniel Espendiller Date: Fri, 25 Mar 2022 15:04:30 +0100 Subject: [PATCH] add Twig block overwrite generator action --- .../idea/symfony2plugin/Symfony2Icons.java | 2 + .../action/TwigBlockOverwriteGenerator.java | 124 ++++++++++++++++++ src/main/java/icons/SymfonyIcons.java | 1 + src/main/resources/META-INF/plugin.xml | 7 + .../resources/icons/twig_block_overwrite.png | Bin 0 -> 6576 bytes .../icons/twig_block_overwrite@2x.png | Bin 0 -> 8752 bytes 6 files changed, 134 insertions(+) create mode 100644 src/main/java/fr/adrienbrault/idea/symfony2plugin/templating/action/TwigBlockOverwriteGenerator.java create mode 100644 src/main/resources/icons/twig_block_overwrite.png create mode 100644 src/main/resources/icons/twig_block_overwrite@2x.png diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/Symfony2Icons.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/Symfony2Icons.java index fff4b8bdc..529672bd1 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/Symfony2Icons.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/Symfony2Icons.java @@ -74,6 +74,8 @@ public class Symfony2Icons { public static final Icon CONFIG_VALUE = IconLoader.getIcon("/icons/config_value.png"); public static final Icon CONFIG_VALUE_SHORTCUT = IconLoader.getIcon("/icons/config_value_shortcut.png"); + public static final Icon TWIG_BLOCK_OVERWRITE = IconLoader.getIcon("/icons/twig_block_overwrite.png"); + public static Image getImage(Icon icon) { if (icon instanceof ImageIcon) { diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/templating/action/TwigBlockOverwriteGenerator.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/templating/action/TwigBlockOverwriteGenerator.java new file mode 100644 index 000000000..3071ee4f6 --- /dev/null +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/templating/action/TwigBlockOverwriteGenerator.java @@ -0,0 +1,124 @@ +package fr.adrienbrault.idea.symfony2plugin.templating.action; + +import com.intellij.codeInsight.CodeInsightActionHandler; +import com.intellij.codeInsight.actions.CodeInsightAction; +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.source.html.HtmlFileImpl; +import com.intellij.util.ThrowableRunnable; +import com.jetbrains.php.completion.insert.PhpInsertHandlerUtil; +import com.jetbrains.twig.TwigFile; +import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent; +import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil; +import fr.adrienbrault.idea.symfony2plugin.twig.utils.TwigFileUtil; +import icons.TwigIcons; +import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author Daniel Espendiller + */ +public class TwigBlockOverwriteGenerator extends CodeInsightAction { + @Override + protected @NotNull + CodeInsightActionHandler getHandler() { + return new MyCodeInsightActionHandler(); + } + + @Override + protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { + return Symfony2ProjectComponent.isEnabled(project) && ( + file instanceof TwigFile + || (file instanceof HtmlFileImpl && file.getName().toLowerCase().endsWith(".twig")) + || getInjectedTwigElement(file, editor) != null + ); + } + + @Nullable + private static PsiElement getInjectedTwigElement(@NotNull PsiFile psiFile, @NotNull Editor editor) { + int caretOffset = editor.getCaretModel().getOffset(); + if(caretOffset <= 0) { + return null; + } + + PsiElement psiElement = psiFile.findElementAt(caretOffset - 1); + if(psiElement == null) { + return null; + } + + return TwigUtil.getElementOnTwigViewProvider(psiElement); + } + + private static class MyCodeInsightActionHandler implements CodeInsightActionHandler { + @Override + public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { + int caretOffset = editor.getCaretModel().getOffset(); + if(caretOffset <= 0) { + return; + } + + PsiElement psiElement = getInjectedTwigElement(file, editor); + if(psiElement == null) { + return; + } + + // collect blocks in all related files + Pair, Boolean> scopedContext = TwigUtil.findScopedFile(psiElement); + + Collection blockLookupElements = TwigUtil.getBlockLookupElements( + project, + TwigFileUtil.collectParentFiles(scopedContext.getSecond(), scopedContext.getFirst()) + ); + + List items = blockLookupElements.stream() + .map(LookupElement::getLookupString) + .distinct() + .collect(Collectors.toList()); + + if (items.size() == 0) { + if (!ApplicationManager.getApplication().isHeadlessEnvironment()) { + HintManager.getInstance().showErrorHint(editor, "No block found"); + } + + return; + } + + JBPopupFactory.getInstance().createPopupChooserBuilder(items) + .setTitle("Symfony: Twig Blocks") + .setItemsChosenCallback(strings -> { + try { + String titleBlocks = StringUtils.abbreviate(strings.stream() + .map((Function) s -> s) + .collect(Collectors.joining(", ")), 10); + + WriteCommandAction.writeCommandAction(editor.getProject()) + .withName("Block Overwrite: " + titleBlocks) + .run((ThrowableRunnable) () -> { + String content = strings.stream() + .map((Function) s -> "{% block " + s + " %}{% endblock %}") + .collect(Collectors.joining("\n")); + + PhpInsertHandlerUtil.insertStringAtCaret(editor, content); + }); + } catch (Throwable ignored) { + } + }) + .createPopup() + .showInBestPositionFor(editor); + } + } +} diff --git a/src/main/java/icons/SymfonyIcons.java b/src/main/java/icons/SymfonyIcons.java index a791d0761..18151ea7f 100644 --- a/src/main/java/icons/SymfonyIcons.java +++ b/src/main/java/icons/SymfonyIcons.java @@ -8,4 +8,5 @@ public class SymfonyIcons { public static final Icon FormType = Symfony2Icons.FORM_TYPE; public static final Icon Translation = Symfony2Icons.TRANSLATION; public static final Icon SymfonyToolWindow = Symfony2Icons.SYMFONY_TOOL_WINDOW; + public static final Icon TwigBlockOverwrite = Symfony2Icons.TWIG_BLOCK_OVERWRITE; } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 972d5a15e..90fc07207 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -718,6 +718,13 @@ + + + + diff --git a/src/main/resources/icons/twig_block_overwrite.png b/src/main/resources/icons/twig_block_overwrite.png new file mode 100644 index 0000000000000000000000000000000000000000..e6809ba5474af7819a3147b8ff7a7dabd1517022 GIT binary patch literal 6576 zcmeHKdpMNq`W_S|g(Z~3YSyT*YR+TKOvafpIW{CpwdU~67-J5;8D_{K9mJ|B9akbt zl2Tz6Av!1>7m8}99Eu{9B&j5-{moEm@3q(dbzQ&xUo+P*@AKZz{XFmeKF|Bkmlohh zo2qN33xmO?(!Jan(0>EfXOcGbchU+LM*?tJtOS4q3O*MG zQ#2PYS$6!{T)h#Vaj51GlP-XYU_d7{(M&5_`X~zA-WsJmH)9IDErNaX<2&hYrx$D! z!72Btwi7n~?(Z1oN$Y*r)#Gz}Wp@J8zq_U4q!^Q8v9ugz_iTul^~~OTN8@&MO6ha+ zu3=?oc|roN)D*mF<#|x(#y1B~i5iIMOG1dVl`GwB5>E8G=k|yn(XCDhBimM0zA?Nj zSQBj_m3Pj+cItWV-XtPw|3eAadUyEVT=a0fgNy6EuB(ate>&_32OrnGHL^h+jar-B zcU4b59Fx_V@UnjA1N6MAxZ)9E*gr0HORgnt%I9u6lUwTuKfu(9c0C!lJ0u;HQ%xl9 zBNzQ{4tSAntv+p>Zof=;Zjr5_)-IQ9Gr;UtaT#O%#_R>O(z=~(cKImq!PBD}yAyvT zkSaUPUa*#E6xZ0?KhtnRRJrR&UPy%@7k6$3^6k)|#jL4HtgS!i^)=&>2Xxm8?AA

d!jv^%~76yML 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/twig_block_overwrite@2x.png b/src/main/resources/icons/twig_block_overwrite@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e981d965edf2895ba06c78460b6e304492bb7294 GIT binary patch literal 8752 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 Q>~jEsL0cIY86G|HUx}AhKL7v# literal 0 HcmV?d00001