package fr.adrienbrault.idea.symfony2plugin.templating; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.xml.XMLLanguage; import com.intellij.openapi.util.TextRange; import com.intellij.patterns.PlatformPatterns; import com.intellij.patterns.PsiElementPattern; import com.intellij.patterns.VirtualFilePattern; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlToken; import com.jetbrains.twig.TwigLanguage; import com.jetbrains.twig.elements.TwigCompositeElement; import com.jetbrains.twig.elements.TwigElementTypes; import fr.adrienbrault.idea.symfony2plugin.TwigHelper; import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProvider; import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrar; import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrarParameter; import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil; import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.Collection; import java.util.Collections; /** * @author Daniel Espendiller <daniel@espendiller.net> */ public class TranslationTagCompletionRegistrar implements GotoCompletionRegistrar { @Override public void register(GotoCompletionRegistrarParameter registrar) { // {% trans from "app" %}<caret>{% endtrans %} registrar.register( getTranslationTagValuePattern(), psiElement -> { TwigCompositeElement element = getTagOnTwigViewProvider(psiElement); if(element == null) { return null; } String domain = TwigHelper.getDomainFromTranslationTag(element); if(domain == null) { domain = TwigUtil.getTransDefaultDomainOnScope(element); } return new MyTranslationGotoCompletionProvider(element, domain); } ); } @NotNull private PsiElementPattern.Capture<XmlToken> getTranslationTagValuePattern() { return PlatformPatterns.psiElement(XmlToken.class) .inVirtualFile(new VirtualFilePattern().withExtension("twig")) .withLanguage(XMLLanguage.INSTANCE); } /** * Resolve html language injection */ private static PsiElement getElementOnTwigViewProvider(@NotNull PsiElement element) { PsiFile file = element.getContainingFile(); TextRange textRange = element.getTextRange(); return file.getViewProvider().findElementAt(textRange.getStartOffset(), TwigLanguage.INSTANCE); } /** * Find trans tag as this is * <caret>{% endtrans %} */ private static TwigCompositeElement getTagOnTwigViewProvider(@NotNull PsiElement element) { PsiElement psiElement = getElementOnTwigViewProvider(element); if(psiElement == null) { return null; } // end tag given, find start tag PsiElement prevSibling = psiElement.getPrevSibling(); if(prevSibling instanceof TwigCompositeElement && prevSibling.getNode().getElementType() == TwigElementTypes.TAG) { return (TwigCompositeElement) prevSibling; } return null; } private static class MyTranslationGotoCompletionProvider extends GotoCompletionProvider { private final String domain; MyTranslationGotoCompletionProvider(PsiElement element, String domain) { super(element); this.domain = domain; } @NotNull @Override public Collection<LookupElement> getLookupElements() { return TranslationUtil.getTranslationLookupElementsOnDomain(getProject(), domain); } @NotNull @Override public Collection<PsiElement> getPsiTargets(PsiElement element) { String text = element.getText(); if(StringUtils.isBlank(text)) { return Collections.emptyList(); } return Arrays.asList( TranslationUtil.getTranslationPsiElements(getProject(), text, domain) ); } } }