|
52 | 52 | import org.apache.commons.lang.StringUtils; |
53 | 53 | import org.jetbrains.annotations.NotNull; |
54 | 54 | import org.jetbrains.annotations.Nullable; |
| 55 | +import org.jetbrains.yaml.YAMLTokenTypes; |
55 | 56 | import org.jetbrains.yaml.psi.YAMLCompoundValue; |
56 | 57 | import org.jetbrains.yaml.psi.YAMLKeyValue; |
| 58 | +import org.jetbrains.yaml.psi.YAMLMapping; |
57 | 59 | import org.jetbrains.yaml.psi.YAMLScalar; |
58 | 60 |
|
59 | 61 | import java.util.*; |
@@ -265,6 +267,9 @@ public void addCompletions(@NotNull CompletionParameters parameters, |
265 | 267 | // _defaults: |
266 | 268 | // bind: |
267 | 269 | // $<caret>: '' |
| 270 | + // service: |
| 271 | + // arguments: |
| 272 | + // $<caret>: '' |
268 | 273 | extend( |
269 | 274 | CompletionType.BASIC, |
270 | 275 | YamlElementPatternHelper.getNamedDefaultBindPattern(), |
@@ -408,56 +413,142 @@ protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull |
408 | 413 | * _defaults: |
409 | 414 | * bind: |
410 | 415 | * $projectDir: '%kernel.project_dir%' |
| 416 | + * foobar: |
| 417 | + * arguments: |
| 418 | + * $projectDir: '%kernel.project_dir%' |
411 | 419 | */ |
412 | 420 | private static class NamedArgumentCompletionProvider extends CompletionProvider<CompletionParameters> { |
413 | 421 | @Override |
414 | 422 | protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet result) { |
415 | | - HashSet<String> uniqueParameters = new HashSet<>(); |
416 | | - |
417 | 423 | PsiElement position = parameters.getPosition(); |
418 | 424 | boolean hasEmptyNextElement = position.getNextSibling() == null; |
419 | 425 |
|
420 | | - ServiceContainerUtil.visitNamedArguments(position.getContainingFile(), pair -> { |
421 | | - Parameter parameter = pair.getFirst(); |
422 | | - String parameterName = parameter.getName(); |
423 | | - if (uniqueParameters.contains(parameterName)) { |
| 426 | + YAMLMapping serviceDefintion = null; |
| 427 | + |
| 428 | + if (position.getNode().getElementType() == YAMLTokenTypes.SCALAR_KEY) { |
| 429 | + YAMLKeyValue parentOfType = PsiTreeUtil.getParentOfType(position, YAMLKeyValue.class); |
| 430 | + YAMLKeyValue parentOfType2 = PsiTreeUtil.getParentOfType(parentOfType, YAMLKeyValue.class); |
| 431 | + if (parentOfType2 == null) { |
424 | 432 | return; |
425 | 433 | } |
426 | 434 |
|
427 | | - uniqueParameters.add(parameterName); |
| 435 | + String keyText2 = parentOfType2.getKeyText(); |
| 436 | + if (!"bind".equals(keyText2)) { |
| 437 | + serviceDefintion = parentOfType2.getParentMapping(); |
| 438 | + } |
| 439 | + } else { |
| 440 | + YAMLKeyValue parentOfType = PsiTreeUtil.getParentOfType(position, YAMLKeyValue.class); |
| 441 | + if (parentOfType == null) { |
| 442 | + return; |
| 443 | + } |
428 | 444 |
|
429 | | - // create argument for yaml: $parameter |
430 | | - result.addElement( |
431 | | - LookupElementBuilder.create("$" + parameterName) |
432 | | - .withIcon(parameter.getIcon()) |
433 | | - .withTypeText(StringUtils.stripStart(parameter.getType().toString(), "\\")) |
434 | | - ); |
| 445 | + if (!"bind".equals(parentOfType.getKeyText())) { |
| 446 | + serviceDefintion = parentOfType.getParentMapping(); |
| 447 | + } |
| 448 | + } |
| 449 | + |
| 450 | + if (serviceDefintion == null) { |
| 451 | + // "defaults => bind": scope |
| 452 | + HashSet<String> uniqueParameters = new HashSet<>(); |
435 | 453 |
|
436 | | - if (hasEmptyNextElement) { |
437 | | - // iterable $handlers => can also provide "!tagged_iterator" |
438 | | - if (parameter.getType().getTypes().stream().anyMatch(s -> s.equalsIgnoreCase(PhpType._ITERABLE))) { |
439 | | - LookupElementBuilder element = LookupElementBuilder.create("$" + parameterName + ": !tagged_iterator") |
| 454 | + ServiceContainerUtil.visitNamedArguments(position.getContainingFile(), pair -> { |
| 455 | + Parameter parameter = pair.getFirst(); |
| 456 | + String parameterName = parameter.getName(); |
| 457 | + if (uniqueParameters.contains(parameterName)) { |
| 458 | + return; |
| 459 | + } |
| 460 | + |
| 461 | + uniqueParameters.add(parameterName); |
| 462 | + |
| 463 | + // create argument for yaml: $parameter |
| 464 | + result.addElement( |
| 465 | + LookupElementBuilder.create("$" + parameterName) |
440 | 466 | .withIcon(parameter.getIcon()) |
441 | | - .withTypeText(StringUtils.stripStart(parameter.getType().toString(), "\\"), true); |
| 467 | + .withTypeText(StringUtils.stripStart(parameter.getType().toString(), "\\")) |
| 468 | + ); |
442 | 469 |
|
443 | | - result.addElement(PrioritizedLookupElement.withPriority(element, -1000)); |
| 470 | + if (hasEmptyNextElement) { |
| 471 | + // iterable $handlers => can also provide "!tagged_iterator" |
| 472 | + if (parameter.getType().getTypes().stream().anyMatch(s -> s.equalsIgnoreCase(PhpType._ITERABLE))) { |
| 473 | + LookupElementBuilder element = LookupElementBuilder.create("$" + parameterName + ": !tagged_iterator") |
| 474 | + .withIcon(parameter.getIcon()) |
| 475 | + .withTypeText(StringUtils.stripStart(parameter.getType().toString(), "\\"), true); |
| 476 | + |
| 477 | + result.addElement(PrioritizedLookupElement.withPriority(element, -1000)); |
| 478 | + } |
| 479 | + |
| 480 | + if (!parameter.getType().getTypes().stream().allMatch(PhpType::isPrimitiveType)) { |
| 481 | + // $foobar: '@service' |
| 482 | + result.addAllElements(getServiceSuggestion(position, pair, parameterName, new ContainerCollectionResolver.LazyServiceCollector(position.getProject()))); |
| 483 | + } else { |
| 484 | + String parameterNormalized = parameterName.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]", ""); |
| 485 | + if (parameterNormalized.length() > 5) { |
| 486 | + // $projectDir: '%kernel.project_dir%' |
| 487 | + result.addAllElements(getParameterSuggestion(parameter, parameterName, parameterNormalized)); |
| 488 | + |
| 489 | + // $kernelClass: '%env(KERNEL_CLASS)%' |
| 490 | + result.addAllElements(getDotEnvSuggestion(parameter, parameterName, parameterNormalized)); |
| 491 | + } |
| 492 | + } |
444 | 493 | } |
| 494 | + }); |
445 | 495 |
|
446 | | - if (!parameter.getType().getTypes().stream().allMatch(PhpType::isPrimitiveType)) { |
447 | | - // $foobar: '@service' |
448 | | - result.addAllElements(getServiceSuggestion(position, pair, parameterName, new ContainerCollectionResolver.LazyServiceCollector(position.getProject()))); |
449 | | - } else { |
450 | | - String parameterNormalized = parameterName.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]", ""); |
451 | | - if (parameterNormalized.length() > 5) { |
452 | | - // $projectDir: '%kernel.project_dir%' |
453 | | - result.addAllElements(getParameterSuggestion(parameter, parameterName, parameterNormalized)); |
| 496 | + return; |
| 497 | + } |
| 498 | + |
| 499 | + // service |
| 500 | + ContainerCollectionResolver.LazyServiceCollector lazyServiceCollector = new ContainerCollectionResolver.LazyServiceCollector(position.getProject()); |
454 | 501 |
|
455 | | - // $kernelClass: '%env(KERNEL_CLASS)%' |
456 | | - result.addAllElements(getDotEnvSuggestion(parameter, parameterName, parameterNormalized)); |
| 502 | + @Nullable PhpClass yamlNamedArgumentPhpClass = ServiceContainerUtil.getServicePhpClassFromServiceMapping(serviceDefintion, lazyServiceCollector); |
| 503 | + if (yamlNamedArgumentPhpClass != null) { |
| 504 | + Method constructor = yamlNamedArgumentPhpClass.getConstructor(); |
| 505 | + if (constructor != null) { |
| 506 | + HashSet<String> uniqueParameters = new HashSet<>(); |
| 507 | + |
| 508 | + Parameter @NotNull [] constructorParameters = constructor.getParameters(); |
| 509 | + for (int i = 0; i < constructorParameters.length; i++) { |
| 510 | + Parameter parameter = constructorParameters[i]; |
| 511 | + String parameterName = parameter.getName(); |
| 512 | + if (uniqueParameters.contains(parameterName)) { |
| 513 | + return; |
| 514 | + } |
| 515 | + |
| 516 | + uniqueParameters.add(parameterName); |
| 517 | + |
| 518 | + // create argument for yaml: $parameter |
| 519 | + result.addElement( |
| 520 | + LookupElementBuilder.create("$" + parameterName) |
| 521 | + .withIcon(parameter.getIcon()) |
| 522 | + .withTypeText(StringUtils.stripStart(parameter.getType().toString(), "\\")) |
| 523 | + ); |
| 524 | + |
| 525 | + if (hasEmptyNextElement) { |
| 526 | + // iterable $handlers => can also provide "!tagged_iterator" |
| 527 | + if (parameter.getType().getTypes().stream().anyMatch(s -> s.equalsIgnoreCase(PhpType._ITERABLE))) { |
| 528 | + LookupElementBuilder element = LookupElementBuilder.create("$" + parameterName + ": !tagged_iterator") |
| 529 | + .withIcon(parameter.getIcon()) |
| 530 | + .withTypeText(StringUtils.stripStart(parameter.getType().toString(), "\\"), true); |
| 531 | + |
| 532 | + result.addElement(PrioritizedLookupElement.withPriority(element, -1000)); |
| 533 | + } |
| 534 | + |
| 535 | + if (!parameter.getType().getTypes().stream().allMatch(PhpType::isPrimitiveType)) { |
| 536 | + // $foobar: '@service' |
| 537 | + result.addAllElements(getServiceSuggestion(position, Pair.create(parameter, i), parameterName, lazyServiceCollector)); |
| 538 | + } else { |
| 539 | + String parameterNormalized = parameterName.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]", ""); |
| 540 | + if (parameterNormalized.length() > 5) { |
| 541 | + // $projectDir: '%kernel.project_dir%' |
| 542 | + result.addAllElements(getParameterSuggestion(parameter, parameterName, parameterNormalized)); |
| 543 | + |
| 544 | + // $kernelClass: '%env(KERNEL_CLASS)%' |
| 545 | + result.addAllElements(getDotEnvSuggestion(parameter, parameterName, parameterNormalized)); |
| 546 | + } |
| 547 | + } |
457 | 548 | } |
458 | 549 | } |
459 | 550 | } |
460 | | - }); |
| 551 | + } |
461 | 552 | } |
462 | 553 |
|
463 | 554 | @NotNull |
|
0 commit comments