On August 17, we announced Symfony Language Tools, the official Symfony language server.
Six days and ten releases later, version 0.16 is out. We have added a lot of features: the server now understands applications that look less like Symfony Demo and more like yours.
Twig Knows Your PHP
Custom Twig functions and filters used to be opaque strings. Symfony Language Tools now connects the ones defined by your application to their PHP implementations.
Type a function or filter name to get completion. Hover it to see the PHP signature and its documentation. Use Go to Definition to open the callable, or Find All References to list its usages across templates.
Named arguments work too. The server understands parameters injected by Twig, completes the remaining ones and reports unknown names.
The implementation is deliberately conservative. Dynamic names and callables are ignored.
Typed Twig Templates
Twig's types tag can now describe the variables expected by a template:
1 2 3 4 5
{% types {
## The product displayed on this page.
product: 'App\\Entity\\Product',
featured?: 'boolean',
} %}
Completion and hover include the declared type, whether the variable is optional and its documentation.
Components from Bundles
Twig component support now reads the effective runtime registry. It recognizes anonymous components, custom renderers and components shipped by installed bundles.
That includes components such as ux:icon. Completion knows their names and
Go to Definition opens the vendor class when it is available locally.
Decorated Twig loaders and bundle-provided Stimulus registries are supported as well.
Real Applications as Tests
The first version was tested against the Symfony applications that power
symfony.com and its subdomains.
The test matrix is now public. Every relevant change runs the server against pinned revisions of Kimai, Mautic, Sulu Demo, Sylius, Shopware and Symfony Demo. Together, they cover Symfony 6.4, 7.4 and 8.1.
The server indexes each application from cold and warm states, boots it and runs real completion, hover, navigation, references, code actions and rename requests.
These applications quickly exposed assumptions hidden by small fixtures. The result is support for XML service definitions, INI translation catalogs, Doctrine XML and YAML mappings, public assets, themed Twig loaders, non-standard kernels and configuration shorthands.
XML Services
Symfony Language Tools now indexes services, aliases, parameters, decorators, tags and references declared in XML.
Navigation, references and rename work across XML, YAML and PHP. Completion in XML is not supported yet.
Doctrine Beyond Attributes
Doctrine support originally relied on PHP attributes. Runtime metadata now adds entities and fields declared through XML or YAML mappings, including entities shipped by dependencies.
Field completion, hover and navigation therefore work on many more projects.
Plain Old Public Assets
Not every application uses AssetMapper. The asset() integration now falls
back to files under public/, so Webpack Encore and other build pipelines get
completion and navigation too.
Unknown paths are not reported as errors as Symfony asset packages can have their own fallback logic.
Your PHP Can Stay in Docker
The language server is self-contained, but runtime indexing needs to boot your application. So it meant a compatible PHP executable on the host.
Not anymore. Configure the PHP command and the path of the project inside the container:
1 2 3 4 5 6
{
"symfonyLsp.phpCommand": [
"docker", "compose", "exec", "-T", "php", "php"
],
"symfonyLsp.containerProjectRoot": "/app"
}
The application boots inside Docker while navigation continues to open files on the host. The same mechanism works with a virtual machine or any isolated PHP command.
Project discovery also understands more layouts: kernels outside the App
namespace, legacy app/AppKernel.php applications, Symfony Runtime front
controllers and FrameworkBundle installed transitively.
More Editors
VS Code and Neovim were available on day one. Zed now has an official extension for Linux and macOS. It downloads the appropriate server automatically and runs alongside Zed's PHP language server.
OpenCode can also start Symfony Language Tools as a custom language server. Its coding agent gets Symfony-aware diagnostics, hover, navigation and references. OpenCode does not request every interactive LSP feature yet, but it is already a useful combination.
The standalone server remains available for any other LSP client. On Windows, VS Code now connects to the bundled server over a local socket automatically. The VS Code package can also be installed in VSCodium from the release VSIX.
Saying Less
A language server must know when to say nothing. False positives are annoying, but false edits are dangerous.
This week, Symfony Language Tools learned to ignore many more uncertain cases:
- PHP and Twig comments;
- Twig
verbatimblocks; - dynamic Stimulus controller expressions;
- dynamic Twig callable options;
- unpacked or dynamic translation parameter maps;
- files owned by dependencies.
Rename and quick fixes are now kept inside application-owned files. Quick fixes also use the unsaved editor contents and versioned edits.
There is more: internationalized routes use their canonical names.
Runtime indexing now tolerates noisy consoles, large metadata snapshots and kernel shutdown failures. When a refresh fails, the last valid metadata remains available.
Indexing at Scale
The source index is now streamed to its persistent store instead of keeping a second complete copy in memory. Parser results are reused; ignored and unreadable files are skipped; garbage collection runs during large scans.
CI generates projects with 1,500 and 6,000 source files to enforce linear scaling and per-file memory budgets. The server memory limit is configurable, with a default ceiling of 2 GB.
Live indexing is safer too. A file saved during a full scan can no longer be
overwritten by an older result. Removing a workspace folder cancels its work
and releases its indexes. New directories, changed ignore rules and
composer.lock updates are detected without restarting the editor.
The Tree-sitter parser is now compiled into the server executable as well. One binary, one process.
Still a Beta
Version 0.16 is a large step, but Symfony Language Tools is still a beta. We are releasing often because every real application teaches the server something a fixture did not.
Install the update, open your application and tell us where it gets confused on the issue tracker.