Twig Pathfinder 🚀
Twig Pathfinder is a powerful VS Code extension that provides seamless navigation between Twig templates, Symfony routes, and PHP controllers. It supercharges your Symfony development workflow by allowing you to instantly jump to referenced files with a single click.
✨ Features
🎯 Core Navigation
Twig → Template Navigation
Jump directly to included, extended, or embedded Twig templates:
{# Click on the template path to navigate #}
{% include 'partials/header.twig' %}
{% extends 'base.html.twig' %}
{% embed 'forms/contact.twig' %}
{% import 'macros.twig' as macros %}
✨ Works with:
- Relative paths:
'partials/header.twig'
- Absolute paths:
'@templates/base.html.twig'
- Template directories:
'templates/', 'views/'
- Any file extension:
.twig, .html.twig
Twig → Route Navigation
Navigate to Symfony route definitions from Twig:
{# Click on route name to navigate #}
<a href="{{ path('app_home') }}">Home</a>
<a href="{{ url('app_contact') }}">Contact</a>
✨ Supports:
- PHP Route Attributes (Symfony 5.4+):
#[Route('/path', name: 'route_name')]
- PHP Annotations (Symfony 5.3 and earlier):
@Route("/path", name="route_name")
- YAML Route Files:
config/routes/*.yaml
PHP → Twig Navigation ⭐ NEW!
Navigate from PHP controllers to Twig templates:
// Click on template name to navigate
$this->render('index.html.twig');
$this->renderView('partials/header.twig');
return $this->render('forms/contact.twig');
✨ Works with:
$this->render('...')
$this->renderView('...')
return $this->render('...')
$twig->render('...')
📦 Installation
From VS Code Marketplace (Recommended)
- Open VS Code
- Go to Extensions (Ctrl+Shift+X or Cmd+Shift+X)
- Search for "Twig Pathfinder"
- Click Install
- Reload VS Code if prompted
From Source (Development)
Clone the repository:
git clone https://github.com/c4n4r/twig-pathfinder.git
cd twig-pathfinder
Install dependencies:
npm install
Compile TypeScript:
npm run compile
Launch Extension Development Host:
- Press
F5 in VS Code
- A new VS Code window will open with the extension loaded
Open your Symfony project in this new window
🚀 Usage
Quick Start
- Open a Twig file in your Symfony project
- Position your cursor on a template path or route name
- Press
F12 (or Cmd+Click / Ctrl+Click) to navigate
That's it! The extension automatically:
- Indexes your workspace on startup
- Resolves template paths and route names
- Opens the target file in a new tab
Keyboard Shortcuts
| Action |
Windows/Linux |
Mac |
| Go to Definition |
F12 |
F12 |
| Go to Definition (alternative) |
Ctrl+Click |
Cmd+Click |
| Peek Definition |
Alt+F12 |
Option+F12 |
| Go Back |
Alt+← |
Option+← |
⚙️ Configuration
Customize the extension behavior via VS Code settings:
Opening Settings
- GUI:
Ctrl+, (or Cmd+, on Mac) → Search for "Twig Pathfinder"
- JSON: Open
settings.json (Ctrl+, → Open Settings (JSON))
Available Settings
📁 Indexing
| Setting |
Type |
Default |
Description |
twigOpenInclude.indexing.enabled |
boolean |
true |
Enable workspace indexing for faster resolution |
twigOpenInclude.indexing.eagerIndexTwig |
boolean |
true |
Eagerly index Twig templates on startup |
twigOpenInclude.indexing.indexRoutes |
boolean |
true |
Index Symfony routes for faster resolution |
twigOpenInclude.indexing.indexControllers |
boolean |
true |
Index Symfony controllers for PHP → Twig navigation |
🎨 Twig
| Setting |
Type |
Default |
Description |
twigOpenInclude.twig.templateDirectories |
array |
["templates", ""] |
Directories to search for Twig templates |
twigOpenInclude.twig.fileExtensions |
array |
[".twig"] |
File extensions to recognize as Twig templates |
twigOpenInclude.twig.searchLimit |
number |
5000 |
Max files to search when template not in index |
🏗️ Symfony
| Setting |
Type |
Default |
Description |
twigOpenInclude.symfony.routeFilePatterns |
array |
["**/config/routes/**/*.{yaml,yml}", "**/config/routing/**/*.{yaml,yml}"] |
Glob patterns for Symfony route YAML files |
twigOpenInclude.symfony.phpFilePatterns |
array |
["**/*.php"] |
Glob patterns for PHP files to search |
twigOpenInclude.symfony.controllerPatterns |
array |
["**/src/Controller/**/*.php", "**/src/Controller/*.php"] |
Glob patterns for Symfony controller files |
💾 Cache
| Setting |
Type |
Default |
Description |
twigOpenInclude.cache.enabled |
boolean |
true |
Enable caching for file operations and resolutions |
twigOpenInclude.cache.ttl.fileExists |
number |
300000 |
Cache TTL for file existence checks (ms) |
twigOpenInclude.cache.ttl.fileContent |
number |
300000 |
Cache TTL for file content (ms) |
twigOpenInclude.cache.ttl.resolution |
number |
600000 |
Cache TTL for path resolutions (ms) |
twigOpenInclude.cache.maxSize |
number |
1000 |
Maximum cache entries |
👀 File Watching
| Setting |
Type |
Default |
Description |
twigOpenInclude.watch.enabled |
boolean |
true |
Watch for file changes and update indexes |
twigOpenInclude.watch.debounceMs |
number |
500 |
Debounce delay for file change events (ms) |
twigOpenInclude.watch.excludePatterns |
array |
["**/{node_modules,vendor}/**"] |
Patterns to exclude from watching |
| Setting |
Type |
Default |
Description |
twigOpenInclude.performance.parallelResolution |
boolean |
true |
Use parallel resolution for PHP and YAML routes |
twigOpenInclude.performance.maxParallelOperations |
number |
5 |
Maximum parallel operations |
Example Configuration
{
"twigOpenInclude.indexing.enabled": true,
"twigOpenInclude.indexing.eagerIndexTwig": true,
"twigOpenInclude.twig.templateDirectories": ["templates", "views"],
"twigOpenInclude.twig.fileExtensions": [".twig", ".html.twig"],
"twigOpenInclude.symfony.controllerPatterns": [
"**/src/Controller/**/*.php",
"**/Controller/**/*.php"
],
"twigOpenInclude.cache.enabled": true,
"twigOpenInclude.watch.excludePatterns": [
"**/{node_modules,vendor,var,public}/**",
"**/.git/**"
]
}
🏗️ Project Structure Support
The extension works best with standard Symfony project structures:
your-project/
├── templates/
│ ├── base.html.twig
│ ├── index.html.twig
│ └── partials/
│ └── header.html.twig
├── src/
│ └── Controller/
│ ├── DefaultController.php
│ └── Api/
│ └── RestController.php
└── config/
└── routes/
├── annotations.yaml
└── api/
└── api.yaml
Custom Structures
If your project uses a different structure, update the settings:
{
"twigOpenInclude.twig.templateDirectories": ["app/Resources/views", "resources/views"],
"twigOpenInclude.symfony.controllerPatterns": ["**/app/Http/Controllers/**/*.php"],
"twigOpenInclude.symfony.routeFilePatterns": ["**/routes/*.php"]
}
🔍 How It Works
Architecture
The extension uses a modular architecture with the following components:
┌─────────────────────────────────────────────────────────────┐
│ VS Code Extension │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Providers │ │ Resolvers │ │ Indexer │ │
│ │ │ │ │ │ │ │
│ │ • DocumentLink│ │ • Twig │ │ • Twig │ │
│ │ • Definition │ │ • Symfony │ │ • Routes │ │
│ │ (Twig) │ │ • PHP │ │ • Controllers│ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └───────────────────┼───────────────────┘ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Resolver Dispatch │ │
│ │ (with cache) │ │
│ └──────────────────┘ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ File System │ │
│ │ (with cache) │ │
│ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Workflow
- Activation: Extension loads and indexes your workspace
- Navigation Request: You click on a template path or route name
- Resolution:
- Check cache first (if enabled)
- Check workspace index
- Fall back to file search
- Navigation: Open the target file in VS Code
- Eager Indexing: All templates, routes, and controllers are indexed on startup
- LRU Caching: File operations and resolutions are cached with configurable TTL
- Parallel Resolution: PHP and YAML routes are resolved in parallel
- Debounced Watching: File changes are processed with debouncing to avoid performance issues
- Smart Search: Intelligent fallback when files aren't in the index
🐛 Troubleshooting
Common Issues
❌ Navigation doesn't work
Possible causes:
- File is not a
.twig or .php file
- Template path is not in quotes
- Template doesn't exist
- Indexing is disabled
Solutions:
- Check the file extension is recognized
- Ensure the path is between quotes:
'template.twig' or "template.twig"
- Verify the template exists in your project
- Enable indexing in settings:
twigOpenInclude.indexing.enabled = true
❌ Wrong file opened
Possible causes:
- Multiple templates with the same name
- Custom template directories not configured
- Cache returning stale results
Solutions:
- Use more specific template paths
- Update
templateDirectories in settings
- Clear cache by restarting VS Code or disabling/enabling caching
Possible causes:
- Large project with many files
- Eager indexing enabled on a large project
- Too many parallel operations
Solutions:
- Disable eager indexing:
twigOpenInclude.indexing.eagerIndexTwig = false
- Reduce search limit:
twigOpenInclude.twig.searchLimit = 1000
- Reduce parallel operations:
twigOpenInclude.performance.maxParallelOperations = 2
- Exclude large directories from watching
❌ Extension not activating
Possible causes:
- Extension not installed correctly
- VS Code not reloaded after installation
- Activation events not triggered
Solutions:
- Check extension is installed:
Ctrl+Shift+P → "Extensions: Show Installed Extensions"
- Reload VS Code:
Ctrl+Shift+P → "Developer: Reload Window"
- Check activation events in
package.json
Benchmarks
| Project Size |
Indexing Time |
Memory Usage |
Resolution Time |
| Small (100 files) |
< 1s |
< 20 MB |
< 10ms (cached) |
| Medium (1,000 files) |
2-5s |
20-50 MB |
< 50ms (cached) |
| Large (10,000 files) |
5-15s |
50-100 MB |
< 100ms (cached) |
Tips for Large Projects
Disable eager indexing if startup is too slow:
{
"twigOpenInclude.indexing.eagerIndexTwig": false
}
Limit search scope to relevant directories:
{
"twigOpenInclude.twig.templateDirectories": ["templates"],
"twigOpenInclude.symfony.controllerPatterns": ["**/src/Controller/**/*.php"]
}
Exclude large directories from watching:
{
"twigOpenInclude.watch.excludePatterns": [
"**/{node_modules,vendor,var,public,storage}/**",
"**/.git/**",
"**/tests/**"
]
}
Reduce cache size if memory usage is high:
{
"twigOpenInclude.cache.maxSize": 500
}
🤝 Contributing
We welcome contributions! Here's how you can help:
Reporting Issues
- Check the Output panel for error messages
- Verify the issue with a minimal test case
- Open an issue on GitHub
- Include:
- VS Code version
- Extension version
- Symfony version
- Project structure
- Error messages
- Steps to reproduce
Development
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
npm run test
- Compile:
npm run compile
- Test in VS Code: Press
F5
- Submit a pull request
Code Style
- Follow TypeScript best practices
- Use meaningful variable and function names
- Add comments for complex logic
- Keep functions small and focused
- Write tests for new features
📜 Changelog
See CHANGELOG.md for release history.
📄 License
This extension is licensed under the MIT License.
🙏 Acknowledgments
- Inspired by the need for better Twig navigation in VS Code
- Built with ❤️ for the Symfony community
- Made by Shifumi, with a bit of Mistral AI Help
Happy Coding! 🎉
Twig Pathfinder - Navigate your Symfony templates with ease.