Hi 馃憢馃徎
Need
Many Twig functions take a hash of options, like button({ size: 'md' }). The PHP method behind the function often documents the accepted keys and values with a PHPDoc array shape. Language Tools could use that shape to complete the hash's keys and each key's literal values.
This is what css() needs in symfony/ux-css, proposed in symfony/ux#3933: it generates config/reference_css.php with a CssStyles shape (about 800 keys), and css() declares @param CssStyles|null $styles. But the need is generic: it applies to any function that takes a hash of options.
Current behavior
With Language Tools 0.23.0 and runtime indexing enabled, completion inside such a hash only offers the app global variable, for keys and for string values alike. Route names complete in the same template, so runtime indexing works.
Reproduction
// src/Twig/ButtonExtension.php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
/**
* @psalm-type ButtonOptions = array{size?: 'sm'|'md'|'lg', variant?: 'primary'|'secondary'|string, icon?: IconOptions}
* @psalm-type IconOptions = array{name?: string, position?: 'start'|'end'}
*/
final class ButtonExtension extends AbstractExtension
{
public function getFunctions(): array
{
return [
new TwigFunction('button_direct', $this->direct(...)),
new TwigFunction('button_alias', $this->alias(...)),
new TwigFunction('button_imported', [ButtonRuntime::class, 'render']),
];
}
/**
* @param array{size?: 'sm'|'md'|'lg', variant?: 'primary'|'secondary'} $options
*/
public function direct(array $options): string { return ''; }
/**
* @param ButtonOptions $options
*/
public function alias(array $options): string { return ''; }
}
// src/Twig/ButtonRuntime.php
namespace App\Twig;
use Twig\Extension\RuntimeExtensionInterface;
/**
* @psalm-import-type ButtonOptions from ButtonExtension
*/
final class ButtonRuntime implements RuntimeExtensionInterface
{
/**
* @param ButtonOptions $options
*/
public function render(array $options): string { return ''; }
}
{# templates/probe.html.twig, | marks the cursor #}
{{ button_direct({ | }) }}
{{ button_direct({ size: '|' }) }}
{{ button_alias({ | }) }}
{{ button_alias({ icon: { | } }) }}
{{ button_imported({ variant: '|' }) }}
Expected behavior
| Line |
Cursor |
Expected items |
| 1 |
key of the hash |
size, variant |
| 2 |
value of size |
sm, md, lg |
| 3 |
key, local alias |
size, variant, icon |
| 4 |
key of a nested hash |
name, position |
| 5 |
value, imported alias |
primary, secondary |
The rules behind these cases:
- The PHP parameter's type is an array shape, written directly or through an alias declared with
@psalm-type or @phpstan-type, possibly imported from another class with @psalm-import-type or @phpstan-import-type.
- In a hash at that argument's position, the shape's keys are completed, optional ones included.
- In a string value, the literal members of the key's type are completed. Other members, like
string or int, are ignored.
- In a nested hash, the key's type is resolved, following aliases, and its keys are completed.
- The PHP method is found for the usual callable forms:
$this->method(...), [$this, 'method'], and a runtime [Runtime::class, 'method'].
Constraints
- The shape can be large: the one
symfony/ux-css generates is about 125 KB with more than 800 keys, so parsing it once per file change matters more than parsing it fast.
- Language Tools has no PHPDoc parser in its dependencies today (
phpstan/phpdoc-parser is not required). How to read the docblock is your call.
Hi 馃憢馃徎
Need
Many Twig functions take a hash of options, like
button({ size: 'md' }). The PHP method behind the function often documents the accepted keys and values with a PHPDoc array shape. Language Tools could use that shape to complete the hash's keys and each key's literal values.This is what
css()needs insymfony/ux-css, proposed in symfony/ux#3933: it generatesconfig/reference_css.phpwith aCssStylesshape (about 800 keys), andcss()declares@param CssStyles|null $styles. But the need is generic: it applies to any function that takes a hash of options.Current behavior
With Language Tools 0.23.0 and runtime indexing enabled, completion inside such a hash only offers the
appglobal variable, for keys and for string values alike. Route names complete in the same template, so runtime indexing works.Reproduction
Expected behavior
size,variantsizesm,md,lgsize,variant,iconname,positionprimary,secondaryThe rules behind these cases:
@psalm-typeor@phpstan-type, possibly imported from another class with@psalm-import-typeor@phpstan-import-type.stringorint, are ignored.$this->method(...),[$this, 'method'], and a runtime[Runtime::class, 'method'].Constraints
symfony/ux-cssgenerates is about 125 KB with more than 800 keys, so parsing it once per file change matters more than parsing it fast.phpstan/phpdoc-parseris not required). How to read the docblock is your call.