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 000000000..e6809ba54 Binary files /dev/null and b/src/main/resources/icons/twig_block_overwrite.png differ 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 000000000..e981d965e Binary files /dev/null and b/src/main/resources/icons/twig_block_overwrite@2x.png differ