|
3 | 3 | import com.intellij.codeInsight.completion.*;
|
4 | 4 | import com.intellij.codeInsight.lookup.LookupElement;
|
5 | 5 | import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
| 6 | +import com.intellij.codeInsight.lookup.LookupElementPresentation; |
6 | 7 | import com.intellij.openapi.project.Project;
|
7 | 8 | import com.intellij.openapi.util.Pair;
|
8 |
| -import com.intellij.patterns.*; |
| 9 | +import com.intellij.openapi.util.text.StringUtil; |
| 10 | +import com.intellij.patterns.PatternCondition; |
| 11 | +import com.intellij.patterns.PlatformPatterns; |
| 12 | +import com.intellij.patterns.StandardPatterns; |
9 | 13 | import com.intellij.psi.PsiElement;
|
10 | 14 | import com.intellij.psi.PsiFile;
|
11 | 15 | import com.intellij.psi.PsiWhiteSpace;
|
|
16 | 20 | import com.jetbrains.php.lang.psi.elements.Field;
|
17 | 21 | import com.jetbrains.php.lang.psi.elements.Method;
|
18 | 22 | import com.jetbrains.php.lang.psi.elements.PhpClass;
|
| 23 | +import com.jetbrains.php.lang.psi.elements.PhpTypedElement; |
| 24 | +import com.jetbrains.php.lang.psi.resolve.types.PhpType; |
19 | 25 | import com.jetbrains.twig.TwigTokenTypes;
|
20 | 26 | import com.jetbrains.twig.elements.TwigElementTypes;
|
21 | 27 | import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
|
@@ -427,6 +433,13 @@ public void addCompletions(@NotNull CompletionParameters parameters, ProcessingC
|
427 | 433 | TwigPattern.getCompletablePattern(),
|
428 | 434 | new IncompleteIncludePrintBlockCompletionProvider()
|
429 | 435 | );
|
| 436 | + |
| 437 | + // {% for => "for flash in app.flashes" |
| 438 | + extend( |
| 439 | + CompletionType.BASIC, |
| 440 | + PlatformPatterns.psiElement(TwigTokenTypes.TAG_NAME), |
| 441 | + new IncompleteForCompletionProvider() |
| 442 | + ); |
430 | 443 | }
|
431 | 444 |
|
432 | 445 | private boolean isCompletionStartingMatch(@NotNull String fullText, @NotNull CompletionParameters completionParameters, int minLength) {
|
@@ -801,5 +814,81 @@ public boolean accepts(@NotNull String s, ProcessingContext processingContext) {
|
801 | 814 | }
|
802 | 815 | }
|
803 | 816 | }
|
| 817 | + |
| 818 | + /** |
| 819 | + * {% for => "for flash in app.flashes" |
| 820 | + */ |
| 821 | + private class IncompleteForCompletionProvider extends CompletionProvider<CompletionParameters> { |
| 822 | + @Override |
| 823 | + protected void addCompletions(@NotNull CompletionParameters completionParameters, @NotNull ProcessingContext processingContext, @NotNull CompletionResultSet resultSet) { |
| 824 | + if(!Symfony2ProjectComponent.isEnabled(completionParameters.getPosition())) { |
| 825 | + return; |
| 826 | + } |
| 827 | + |
| 828 | + resultSet.restartCompletionOnPrefixChange(StandardPatterns.string().longerThan(1).with(new PatternCondition<>("for startsWith") { |
| 829 | + @Override |
| 830 | + public boolean accepts(@NotNull String s, ProcessingContext processingContext) { |
| 831 | + return "for".startsWith(s); |
| 832 | + } |
| 833 | + })); |
| 834 | + |
| 835 | + if (!isCompletionStartingMatch("for", completionParameters, 2)) { |
| 836 | + return; |
| 837 | + } |
| 838 | + |
| 839 | + Set<Map.Entry<String, PsiVariable>> entries = TwigTypeResolveUtil.collectScopeVariables(completionParameters.getPosition()).entrySet(); |
| 840 | + |
| 841 | + Map<String, Pair<String, LookupElement>> arrays = new HashMap<>(); |
| 842 | + |
| 843 | + Project project = completionParameters.getPosition().getProject(); |
| 844 | + |
| 845 | + for(Map.Entry<String, PsiVariable> entry: entries) { |
| 846 | + Collection<PhpClass> classFromPhpTypeSet = PhpElementsUtil.getClassFromPhpTypeSet(project, entry.getValue().getTypes()); |
| 847 | + for (PhpClass phpClass : classFromPhpTypeSet) { |
| 848 | + for(Method method: phpClass.getMethods()) { |
| 849 | + if(!(!method.getModifier().isPublic() || method.getName().startsWith("set") || method.getName().startsWith("__"))) { |
| 850 | + if (PhpType.isArray(PhpIndex.getInstance(project).completeType(project, method.getType(), new HashSet<>()))) { |
| 851 | + String propertyShortcutMethodName = TwigTypeResolveUtil.getPropertyShortcutMethodName(method); |
| 852 | + arrays.put(entry.getKey() + "." + propertyShortcutMethodName, Pair.create(propertyShortcutMethodName, new PhpTwigMethodLookupElement(method))); |
| 853 | + } |
| 854 | + } |
| 855 | + } |
| 856 | + |
| 857 | + for(Field field: phpClass.getFields()) { |
| 858 | + if(field.getModifier().isPublic()) { |
| 859 | + if (PhpType.isArray(PhpIndex.getInstance(project).completeType(project, field.getType(), new HashSet<>()))) { |
| 860 | + arrays.put(entry.getKey() + "." + field.getName(), Pair.create(field.getName(), new PhpTwigMethodLookupElement(field))); |
| 861 | + } |
| 862 | + } |
| 863 | + } |
| 864 | + } |
| 865 | + } |
| 866 | + |
| 867 | + for (Map.Entry<String, Pair<String, LookupElement>> entry : arrays.entrySet()) { |
| 868 | + String var = entry.getValue().getFirst(); |
| 869 | + String unpluralize = StringUtil.unpluralize(var); |
| 870 | + if (unpluralize != null) { |
| 871 | + var = unpluralize; |
| 872 | + } |
| 873 | + |
| 874 | + LookupElementPresentation lookupElementPresentation = new LookupElementPresentation(); |
| 875 | + entry.getValue().getSecond().renderElement(lookupElementPresentation); |
| 876 | + |
| 877 | + Set<String> types = new HashSet<>(); |
| 878 | + PsiElement psiElement = entry.getValue().getSecond().getPsiElement(); |
| 879 | + if (psiElement instanceof PhpTypedElement) { |
| 880 | + types.addAll(((PhpTypedElement) psiElement).getType().getTypes()); |
| 881 | + } |
| 882 | + |
| 883 | + String content = String.format("for %s in %s", var, entry.getKey()); |
| 884 | + LookupElementBuilder lookupElement = LookupElementBuilder.create(content) |
| 885 | + .withIcon(lookupElementPresentation.getIcon()) |
| 886 | + .withStrikeoutness(lookupElementPresentation.isStrikeout()) |
| 887 | + .withTypeText(StringUtils.stripStart(TwigTypeResolveUtil.getTypeDisplayName(project, types), "\\")); |
| 888 | + |
| 889 | + resultSet.addElement(lookupElement); |
| 890 | + } |
| 891 | + } |
| 892 | + } |
804 | 893 | }
|
805 | 894 |
|
0 commit comments