package fr.adrienbrault.idea.symfony2plugin.templating.annotation;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.PhpPsiElement;
import de.espend.idea.php.annotation.extension.PhpAnnotationDocTagAnnotator;
import de.espend.idea.php.annotation.extension.parameter.PhpAnnotationDocTagAnnotatorParameter;
import fr.adrienbrault.idea.symfony2plugin.Settings;
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
import fr.adrienbrault.idea.symfony2plugin.TwigHelper;
import fr.adrienbrault.idea.symfony2plugin.templating.PhpTemplateAnnotator;
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class TemplateAnnotationAnnotator implements PhpAnnotationDocTagAnnotator {
@Override
public void annotate(PhpAnnotationDocTagAnnotatorParameter parameter) {
if(!Symfony2ProjectComponent.isEnabled(parameter.getProject()) ||
!Settings.getInstance(parameter.getProject()).phpAnnotateTemplateAnnotation ||
!PhpElementsUtil.isEqualClassName(parameter.getAnnotationClass(), TwigHelper.TEMPLATE_ANNOTATION_CLASS))
{
return;
}
PhpPsiElement phpDocAttrList = parameter.getPhpDocTag().getFirstPsiChild();
if(phpDocAttrList == null) {
return;
}
String tagValue = phpDocAttrList.getText();
Collection<String> templateNames = new HashSet<>();
// @Template("FooBundle:Folder:foo.html.twig")
// @Template("FooBundle:Folder:foo.html.twig", "asdas")
// @Template(tag="name")
Matcher matcher = Pattern.compile("\\(\"(.*)\"").matcher(tagValue);
if (matcher.find()) {
templateNames.add(matcher.group(1));
} else {
// find template name on last method
PhpDocComment docComment = PsiTreeUtil.getParentOfType(parameter.getPhpDocTag(), PhpDocComment.class);
if(null == docComment) {
return;
}
Method method = PsiTreeUtil.getNextSiblingOfType(docComment, Method.class);
if(null == method || !method.getName().endsWith("Action")) {
return;
}
String[] controllerMethodShortcut = TwigUtil.getControllerMethodShortcut(method);
if(controllerMethodShortcut != null) {
templateNames.addAll(Arrays.asList(controllerMethodShortcut));
}
}
if(templateNames.size() == 0) {
return;
}
for (String templateName : templateNames) {
if (TwigHelper.getTemplatePsiElements(parameter.getProject(), templateName).length > 0) {
return;
}
}
// find html target, as this this our first priority for end users condition
String templateName = ContainerUtil.find(templateNames, s -> s.toLowerCase().endsWith(".html.twig"));
// fallback on first item
if(templateName == null) {
templateName = templateNames.iterator().next();
}
// add fix to doc tag
PsiElement firstChild = parameter.getPhpDocTag().getFirstChild();
if(null == firstChild) {
return;
}
parameter.getHolder()
.createWarningAnnotation(firstChild.getTextRange(), "Create Template")
.registerFix(new PhpTemplateAnnotator.CreateTemplateFix(templateName))
;
}
}