Skip to content

languages: Add built-in PHP support via intelephense - #31

Merged
jasonsmithio merged 1 commit into
mainfrom
feat/lang-php
May 16, 2026
Merged

languages: Add built-in PHP support via intelephense#31
jasonsmithio merged 1 commit into
mainfrom
feat/lang-php

Conversation

@jasonsmithio

Copy link
Copy Markdown
Collaborator

Summary

Adds PHP as a built-in language — the final PR in the bake-in series (Swift → Kotlin → Java → PHP). .php and .phtml files get syntax highlighting, indent rules, outline, runnable tests, debugger query, and completion / hover / go-to-def via intelephense — found on $PATH first, otherwise npm installed into the language container dir on first open.

Built-in language count goes from 13 to 17 once this and the prior three PRs land.

Independent of #28, #29, #30 — all four base on main with no shared touch points beyond crates/languages/src/lib.rs::init.

What's here

  • Grammar. Canonical tree-sitter-php = "0.24.2" (MIT). Same dev-dep-only tree-sitter ^0.25 constraint as tree-sitter-java; resolves cleanly against workspace tree-sitter 0.26. Uses LANGUAGE_PHP (mixed-mode PHP + inline HTML) since .php files traditionally interleave HTML.
  • Queries. Pulled from zed-extensions/php (MIT) into crates/grammars/src/php/. 11 files: brackets.scm, config.toml, debugger.scm, embedding.scm, highlights.scm, indents.scm, injections.scm, outline.scm, overrides.scm, runnables.scm, textobjects.scm. Zero patches needed — upstream queries are written against the same canonical grammar.
  • LSP adapter. New crates/languages/src/php.rs (~150 LOC). Modeled directly on typescript.rs (single-package variant, no separate typescript package to install alongside the language server). check_if_user_installed calls delegate.which("intelephense"); otherwise the adapter npm_install_packages("intelephense", latest) into <container>/node_modules/ and invokes node <container>/node_modules/intelephense/lib/intelephense.js --stdio.
  • License note. intelephense is proprietary (not OSS) — the free tier is fine for editor features, paid features (rename across files, advanced code actions) need a license key. We don't redistribute it; npm install fetches it from npmjs.com at runtime. Users who prefer OSS can override via the language_servers setting to point at phpactor or phpls. This is captured in a doc-comment at the top of php.rs so the next reader doesn't have to grep release notes.
  • Wiring. crates/languages/src/lib.rs::init gains a mod php;, an Arc::new(php::PhpLspAdapter::new(node.clone())) instantiation, and a LanguageInfo { name: "php", adapters: vec![php_lsp_adapter], manifest_name: Some("composer.json".into()), .. } entry between markdown-inline and python (alphabetical). All four touch points tagged // PaddleBoard: for upstream-merge resolution.

Bonus: Tailwind autocomplete in .php files just works

The existing tailwind_languages list in lib.rs::init already includes "PHP" as a candidate language for the tailwind LSP. Once this PR lands, tailwind class completion in .php files (Laravel Blade templates, etc.) starts working without any extra wiring on the PHP side.

Test plan

  • cargo check -p grammars --features load-grammars clean (9.8s, fresh tree-sitter-php compile)
  • cargo check -p paddleboard clean (6.2s incremental)
  • Release build (17.97s) clean
  • PHP grammar registers with zero query-loader warnings or errors in PaddleBoard.log
  • LSP smoke test — opening a .php buffer triggers npm install intelephense (~10s on a warm npm cache, ~30s cold) and then the intelephense process spawns. Structurally identical to typescript.rs (verified to work in production); first reviewer can verify by opening any .php file in a project.

Known limitations

  • intelephense is proprietary. Free tier is generous (covers all editor features); paid features require a license key passed via lsp.intelephense.initializationOptions.licenceKey in settings.
  • No composer/PHPUnit context provider — multi-package PHP projects work but won't get composer-package-aware test running. Out of scope here.

Out of scope (follow-ups)

  • OSS alternative adapter: phpactor (composer-distributed) for users avoiding intelephense's license
  • Composer/PHPUnit context provider for test running
  • Laravel Blade language registration (inherits from PHP grammar with HTML injections)

Release Notes:

  • Added built-in support for PHP, including syntax highlighting and language-server features (completion, hover, go-to-definition) via intelephense. The server is downloaded automatically on first use, or picked up from $PATH if installed system-wide. intelephense is proprietary (free tier; paid features require a license key).

Adds PHP as a first-class built-in: tree-sitter grammar registered,
.php/.phtml files recognized, syntax highlighting + outline + indents +
injections + runnables on, and intelephense driven for
completion/hover/go-to-def — found on PATH first, otherwise npm-installed
into the language container dir.

- Grammar: canonical tree-sitter-php 0.24.2 (MIT). Same dev-dep-only
  tree-sitter ^0.25 constraint as tree-sitter-java; resolves cleanly
  against workspace tree-sitter 0.26. Uses LANGUAGE_PHP (mixed-mode PHP
  + inline HTML) since .php files traditionally interleave HTML.
- Queries: pulled from zed-extensions/php (MIT) into
  crates/grammars/src/php/. 11 files. Zero patches needed — upstream
  queries are written against the same canonical grammar.
- Adapter: new crates/languages/src/php.rs (~150 LOC). Modeled directly
  on typescript.rs (single-package variant). $PATH lookup first, then
  npm_install_packages("intelephense", latest) into <container>, then
  node <container>/node_modules/intelephense/lib/intelephense.js --stdio.
  License note in the adapter doc-comment: intelephense is proprietary;
  we don't redistribute it, npm fetches at runtime. Users who prefer
  OSS can override via the `language_servers` setting (phpactor, phpls).
- Wired into crates/languages/src/lib.rs::init with PaddleBoard tags on
  every upstream-shaped edit. Sets `composer.json` as the manifest name
  so intelephense can discover package roots.

Final of four planned bake-in PRs (Swift, Kotlin, Java, PHP). Brings the
built-in language count from 13 to 17.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@jasonsmithio
jasonsmithio merged commit 2460f0c into main May 16, 2026
@jasonsmithio
jasonsmithio deleted the feat/lang-php branch May 16, 2026 16:56
jasonsmithio added a commit that referenced this pull request May 31, 2026
languages: Add built-in PHP support via intelephense
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant