package fr.adrienbrault.idea.symfony2plugin.translation;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import com.jetbrains.twig.elements.TwigElementTypes;
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
import fr.adrienbrault.idea.symfony2plugin.TwigHelper;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionContributor;
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 fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class TranslationPlaceholderGotoCompletionRegistrar implements GotoCompletionRegistrar {
@Override
public void register(GotoCompletionRegistrarParameter registrar) {
// {{ 'symfony.great'|trans({'fo<caret>f'}, 'symfony')) }}
registrar.register(
TwigHelper.getFunctionWithFirstParameterAsKeyLiteralPattern("trans"),
new MyTwigTransFilterCompletionContributor("trans")
);
// {{ 'symfony.great'|transchoice(12, {'fo<caret>f'}, 'symfony')) }}
registrar.register(
TwigHelper.getFunctionWithSecondParameterAsKeyLiteralPattern("transchoice"),
new MyTwigTransFilterCompletionContributor("transchoice")
);
// $x->trans('symfony.great', ['%fo<caret>obar%', null], 'symfony')
registrar.register(
PlatformPatterns.psiElement().withParent(StringLiteralExpression.class),
new MyPhpTranslationCompletionContributor("trans", 1, 2)
);
// $x->transChoice('symfony.great', 10, ['%fo<caret>obar%', null], 'symfony')
registrar.register(
PlatformPatterns.psiElement().withParent(StringLiteralExpression.class),
new MyPhpTranslationCompletionContributor("transChoice", 2, 3)
);
}
private static class MyTranslationPlaceholderGotoCompletionProvider extends GotoCompletionProvider {
@NotNull
private final String key;
@NotNull
private final String domain;
MyTranslationPlaceholderGotoCompletionProvider(@NotNull PsiElement psiElement, @NotNull String key, @NotNull String domain) {
super(psiElement);
this.key = key;
this.domain = domain;
}
@NotNull
@Override
public Collection<LookupElement> getLookupElements() {
return TranslationUtil.getPlaceholderFromTranslation(getProject(), key, domain).stream()
.map(s -> LookupElementBuilder.create(s).withIcon(Symfony2Icons.TRANSLATION))
.collect(Collectors.toList());
}
@NotNull
@Override
public Collection<PsiElement> getPsiTargets(PsiElement element) {
return Arrays.asList(TranslationUtil.getTranslationPsiElements(getProject(), key, domain));
}
}
private static class MyPhpTranslationCompletionContributor implements GotoCompletionContributor {
@NotNull
private String method;
private int placeHolderParameter;
private int domainParameter;
private MyPhpTranslationCompletionContributor(@NotNull String method, int placeHolderParameter, int domainParameter) {
this.method = method;
this.placeHolderParameter = placeHolderParameter;
this.domainParameter = domainParameter;
}
@Nullable
@Override
public GotoCompletionProvider getProvider(@NotNull PsiElement psiElement) {
PsiElement context = psiElement.getContext();
if (!(context instanceof StringLiteralExpression)) {
return null;
}
MethodMatcher.MethodMatchParameter match = new MethodMatcher.ArrayParameterMatcher(context, placeHolderParameter)
.withSignature("Symfony\\Component\\Translation\\TranslatorInterface", method)
.match();
if (match == null) {
return null;
}
PsiElement[] parameters = match.getMethodReference().getParameters();
String key = PhpElementsUtil.getStringValue(parameters[0]);
if(key == null) {
return null;
}
String domain = "messages";
if(parameters.length > domainParameter) {
domain = PhpElementsUtil.getStringValue(parameters[domainParameter]);
if(domain == null) {
return null;
}
}
return new MyTranslationPlaceholderGotoCompletionProvider(psiElement, key, domain);
}
}
private static class MyTwigTransFilterCompletionContributor implements GotoCompletionContributor {
@NotNull
private final String filter;
MyTwigTransFilterCompletionContributor(@NotNull String filter) {
this.filter = filter;
}
@Nullable
@Override
public GotoCompletionProvider getProvider(@NotNull PsiElement psiElement) {
PsiElement parent = psiElement.getParent();
if(parent.getNode().getElementType() != TwigElementTypes.LITERAL) {
return null;
}
PsiElement function = PsiElementUtils.getPrevSiblingOfType(parent, TwigHelper.getTranslationPattern(this.filter));
if(function == null) {
return null;
}
String key = function.getText();
if(StringUtils.isBlank(key)) {
return null;
}
String domain = TwigUtil.getPsiElementTranslationDomain(function);
if(StringUtils.isBlank(domain)) {
return null;
}
return new MyTranslationPlaceholderGotoCompletionProvider(psiElement, key, domain);
}
}
}