diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlCompletionContributor.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlCompletionContributor.java index 7d0971298..3c4c7404d 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlCompletionContributor.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlCompletionContributor.java @@ -23,6 +23,7 @@ import fr.adrienbrault.idea.symfony2plugin.dic.ContainerParameter; import fr.adrienbrault.idea.symfony2plugin.dic.ServiceCompletionProvider; import fr.adrienbrault.idea.symfony2plugin.dic.container.util.DotEnvUtil; +import fr.adrienbrault.idea.symfony2plugin.dic.container.util.ServiceContainerUtil; import fr.adrienbrault.idea.symfony2plugin.doctrine.DoctrineYamlAnnotationLookupBuilder; import fr.adrienbrault.idea.symfony2plugin.doctrine.EntityHelper; import fr.adrienbrault.idea.symfony2plugin.doctrine.component.PhpEntityClassCompletionProvider; @@ -40,6 +41,7 @@ import fr.adrienbrault.idea.symfony2plugin.util.controller.ControllerCompletionProvider; import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil; import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper; +import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.yaml.psi.YAMLCompoundValue; @@ -48,6 +50,7 @@ import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -244,6 +247,16 @@ public void addCompletions(@NotNull CompletionParameters parameters, YamlElementPatternHelper.getParentKeyName("services"), new MyServiceKeyAsClassCompletionParametersCompletionProvider() ); + + // services: + // _defaults: + // bind: + // $: '' + extend( + CompletionType.BASIC, + YamlElementPatternHelper.getNamedDefaultBindPattern(), + new NamedArgumentCompletionProvider() + ); } /** @@ -377,6 +390,35 @@ protected void addCompletions(@NotNull CompletionParameters parameters, Processi } } + /** + * services: + * _defaults: + * bind: + * $projectDir: '%kernel.project_dir%' + */ + private static class NamedArgumentCompletionProvider extends CompletionProvider { + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) { + HashSet uniqueParameters = new HashSet<>(); + + ServiceContainerUtil.visitNamedArguments(parameters.getPosition().getContainingFile(), parameter -> { + String name = parameter.getName(); + if (uniqueParameters.contains(name)) { + return; + } + + uniqueParameters.add(name); + + // create argument for yaml: $parameter + result.addElement( + LookupElementBuilder.create("$" + name) + .withIcon(parameter.getIcon()) + .withTypeText(StringUtils.stripStart(parameter.getType().toString(), "\\"), true) + ); + }); + } + } + /** * tags: * - { method: 'foobar' } diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlElementPatternHelper.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlElementPatternHelper.java index 4420e190d..3f13ed3aa 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlElementPatternHelper.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlElementPatternHelper.java @@ -711,6 +711,28 @@ public static ElementPattern getTaggedServicePattern() { ); } + /** + * services: + * _defaults: + * bind: + * $: '' + */ + static PsiElementPattern.Capture getNamedDefaultBindPattern() { + return PlatformPatterns.psiElement(YAMLTokenTypes.SCALAR_KEY).withText(PlatformPatterns.string().startsWith("$")).withParent( + PlatformPatterns.psiElement(YAMLKeyValue.class).withParent(PlatformPatterns.psiElement(YAMLMapping.class).withParent(PlatformPatterns.psiElement(YAMLKeyValue.class).with(new PatternCondition("KeyText") { + @Override + public boolean accepts(@NotNull YAMLKeyValue yamlKeyValue, ProcessingContext context) { + return "bind".equals(yamlKeyValue.getKeyText()); + } + }).withParent(PlatformPatterns.psiElement(YAMLMapping.class).withParent(PlatformPatterns.psiElement(YAMLKeyValue.class).with(new PatternCondition("KeyText") { + @Override + public boolean accepts(@NotNull YAMLKeyValue yamlKeyValue, ProcessingContext context) { + return "_defaults".equals(yamlKeyValue.getKeyText()); + } + }))))) + ); + } + /** * Match elements types */ diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlGoToDeclarationHandler.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlGoToDeclarationHandler.java index f454cd1a2..647021f0a 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlGoToDeclarationHandler.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlGoToDeclarationHandler.java @@ -184,21 +184,12 @@ public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int i, Edit private Collection namedDefaultBindArgumentGoto(@NotNull PsiElement psiElement, @NotNull String parameterName) { Collection psiElements = new HashSet<>(); - PsiFile containingFile = psiElement.getContainingFile(); - if (containingFile instanceof YAMLFile) { - for (PhpClass phpClass : YamlHelper.getPhpClassesInYamlFile((YAMLFile) containingFile, new ContainerCollectionResolver.LazyServiceCollector(psiElement.getProject()))) { - Method constructor = phpClass.getConstructor(); - if (constructor == null) { - continue; - } - - for (Parameter parameter : constructor.getParameters()) { - if (parameter.getName().equals(parameterName.substring(1))) { - psiElements.add(parameter); - } - } + String argumentWithoutDollar = parameterName.substring(1); + ServiceContainerUtil.visitNamedArguments(psiElement.getContainingFile(), parameter -> { + if (parameter.getName().equals(argumentWithoutDollar)) { + psiElements.add(parameter); } - } + }); return psiElements; } diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/container/util/ServiceContainerUtil.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/container/util/ServiceContainerUtil.java index 0098f6a83..460da901f 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/container/util/ServiceContainerUtil.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/container/util/ServiceContainerUtil.java @@ -37,10 +37,7 @@ import org.jetbrains.yaml.YAMLUtil; import org.jetbrains.yaml.psi.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; +import java.util.*; /** * @author Daniel Espendiller @@ -403,6 +400,25 @@ public static Parameter getYamlNamedArgument(@NotNull PsiElement psiElement, @No return null; } + /** + * services: + * _defaults: + * bind: + * $: '' + */ + public static void visitNamedArguments(@NotNull PsiFile psiFile, @NotNull Consumer processor) { + if (psiFile instanceof YAMLFile) { + for (PhpClass phpClass : YamlHelper.getPhpClassesInYamlFile((YAMLFile) psiFile, new ContainerCollectionResolver.LazyServiceCollector(psiFile.getProject()))) { + Method constructor = phpClass.getConstructor(); + if (constructor == null) { + continue; + } + + Arrays.stream(constructor.getParameters()).forEach(processor::consume); + } + } + } + /** * Symfony 3.3: "class" is optional; use service name for its it * diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/yaml/YamlCompletionContributorTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/yaml/YamlCompletionContributorTest.java index fa316714a..d512835b6 100644 --- a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/yaml/YamlCompletionContributorTest.java +++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/yaml/YamlCompletionContributorTest.java @@ -302,4 +302,15 @@ public void testCompletionForServiceKeyAsClassMustNotBeFiredNonShortcutDefinitio "Bar" ); } + + public void testNamedArgumentCompletionForDefaultsBinding() { + assertCompletionContains(YAMLFileType.YML, "" + + "services:\n" + + " _defaults:\n" + + " bind:\n" + + " $: ~\n" + + " Foo\\Bar: ~", + "$i" + ); + } }