Skip to content

feat(php): PHP code intelligence via Intelephense - on-demand install, full LSP parity#3011

Open
abose wants to merge 3 commits into
mainfrom
ai
Open

feat(php): PHP code intelligence via Intelephense - on-demand install, full LSP parity#3011
abose wants to merge 3 commits into
mainfrom
ai

Conversation

@abose

@abose abose commented Jul 3, 2026

Copy link
Copy Markdown
Member

PHP now gets the same intelligence as JS/TS: completion with a signature
docs popup, hover with full PHP-manual docs, signature help, diagnostics,
jump-to-definition, find references and quickfix plumbing - all on the
shared LSP framework via a new desktop-only PHPSupport default extension.

Licensing shapes the design: the Intelephense server is proprietary
freeware whose license forbids bundling, but permits individual users to
pair it with an LSP-capable editor. So it is NOT shipped - on the first
PHP file the user is offered it (SUBTLE prompt toast with Install/Not Now
and a "Powered by Intelephense" link, once per project per session, plus
a persistent Problems-panel Install row mirroring the TS enable flow).
Consent triggers a pinned npm install intelephense@1.18.5 into
/lspServers/intelephense/ through the existing bundled-npm node
plumbing, tracked as a status-bar TaskManager task with phase progress;
success auto-starts the server. Version upgrades (pin bumps) reinstall
silently and pass clearCache once. Preferences: php.codeIntelligence
(master switch) and php.licenseKey (premium licenceKey; the standard
global licence file also works untouched - the server reads it itself).
Cross-platform by construction: no .bin shims, no shell, array-args npm,
central VFS->platform path conversion.

Framework changes:

  • src-node/lsp-client.js: an absolute command path ending .js is spawned
    on our own node runtime (process.execPath) - user-local servers run
    identically on Windows/macOS/Linux.
  • LSPClient client capabilities now declare completionItem.resolveSupport
    (documentation, detail) - LSP 3.16 servers may gate lazy resolution on
    it. Verified empirically that intelephense provides NO completion-item
    documentation either way (its rich docs come via hover); hence:
  • DefaultProviders composes the docs-popup signature from
    label + labelDetails.detail + return type when a server splits the
    signature across fields (intelephense) - previously the popup showed a
    bare return type. vtsls (whole signature in detail) is untouched.
    Long detail strings (>32 chars) no longer render inline in hint rows;
    the docs popup carries them.

Ecosystem fixes for mixed php/html documents:

  • JavaScriptCodeHints: inline-script host languages (html, php) keep
    their Tern session even when an LSP claims the document language -
    intelephense serves only PHP, so without this every embedded <script>
    in .php files would lose JS intelligence.
  • html-lint: php regions are blanked (same-length whitespace, newlines
    kept, so positions stay valid) before html-validate runs - kills the
    "failed to tokenize <?php" parser-error noise on every php file while
    still linting the surrounding HTML; pure-php files lint clean.
  • gulpfile: PHPSupport registered as a minifyable extension; dist cache
    asset limit raised 75MB -> 78MB (recent features pushed CI past it).

Tests: new integration:PHP LSP 5/5 against a really-installed server
(install via ServerInstaller.installNow, parse diagnostics warm-up,
provider-active flags, hover docs, jump-to-definition, and the
embedded-JS Tern regression). Regressions: integration:TypeScript LSP
20/20 (including after the capability change), integration:JSON LSP 3/3,
releaseProd green (72.96 MB dist).

abose added 3 commits July 3, 2026 13:31
…, full LSP parity

PHP now gets the same intelligence as JS/TS: completion with a signature
docs popup, hover with full PHP-manual docs, signature help, diagnostics,
jump-to-definition, find references and quickfix plumbing - all on the
shared LSP framework via a new desktop-only PHPSupport default extension.

Licensing shapes the design: the Intelephense server is proprietary
freeware whose license forbids bundling, but permits individual users to
pair it with an LSP-capable editor. So it is NOT shipped - on the first
PHP file the user is offered it (SUBTLE prompt toast with Install/Not Now
and a "Powered by Intelephense" link, once per project per session, plus
a persistent Problems-panel Install row mirroring the TS enable flow).
Consent triggers a pinned `npm install intelephense@1.18.5` into
<appData>/lspServers/intelephense/ through the existing bundled-npm node
plumbing, tracked as a status-bar TaskManager task with phase progress;
success auto-starts the server. Version upgrades (pin bumps) reinstall
silently and pass clearCache once. Preferences: php.codeIntelligence
(master switch) and php.licenseKey (premium licenceKey; the standard
global licence file also works untouched - the server reads it itself).
Cross-platform by construction: no .bin shims, no shell, array-args npm,
central VFS->platform path conversion.

Framework changes:
- src-node/lsp-client.js: an absolute command path ending .js is spawned
  on our own node runtime (process.execPath) - user-local servers run
  identically on Windows/macOS/Linux.
- LSPClient client capabilities now declare completionItem.resolveSupport
  (documentation, detail) - LSP 3.16 servers may gate lazy resolution on
  it. Verified empirically that intelephense provides NO completion-item
  documentation either way (its rich docs come via hover); hence:
- DefaultProviders composes the docs-popup signature from
  label + labelDetails.detail + return type when a server splits the
  signature across fields (intelephense) - previously the popup showed a
  bare return type. vtsls (whole signature in `detail`) is untouched.
  Long `detail` strings (>32 chars) no longer render inline in hint rows;
  the docs popup carries them.

Ecosystem fixes for mixed php/html documents:
- JavaScriptCodeHints: inline-script host languages (html, php) keep
  their Tern session even when an LSP claims the document language -
  intelephense serves only PHP, so without this every embedded <script>
  in .php files would lose JS intelligence.
- html-lint: php regions are blanked (same-length whitespace, newlines
  kept, so positions stay valid) before html-validate runs - kills the
  "failed to tokenize <?php" parser-error noise on every php file while
  still linting the surrounding HTML; pure-php files lint clean.
- gulpfile: PHPSupport registered as a minifyable extension; dist cache
  asset limit raised 75MB -> 78MB (recent features pushed CI past it).

Tests: new integration:PHP LSP 5/5 against a really-installed server
(install via ServerInstaller.installNow, parse diagnostics warm-up,
provider-active flags, hover docs, jump-to-definition, and the
embedded-JS Tern regression). Regressions: integration:TypeScript LSP
20/20 (including after the capability change), integration:JSON LSP 3/3,
releaseProd green (72.96 MB dist).
Emmet's markup provider registers for ["html", "php"], but a php file's
HTML regions already report "html" at the cursor and are served by the
html registration - so the php registration only ever receives cursors
inside real <?php ?> code, where a markup abbreviation is never right
(typing `addition(` summoned an Emmet hint mid-function-declaration).

Guard in EmmetMarkupHints.hasHints: decline when the cursor's language is
"php". HTML regions of php files keep full Emmet.

New spec in the Emmet suite covers both sides: no hints after
`function addition(` in a php region; `div` still offered in the same
file's HTML region. unit: HTML Code Hinting 76/76.
Replace the install prompt toast with a ModalBar banner across the top of
the editor - the same surface as the find bar, impossible to miss on the
very file that triggered it, yet passive (autoClose off: clicking back
into the code doesn't dismiss it).

- Terse copy: "Install advanced PHP code intelligence?" followed by an
  (i) icon whose hover shows a compact benefits card (the reusable rich
  tooltip): Completions / Docs on hover / Error checking / Navigation,
  one plain line each. Right side: "Powered by Intelephense" link,
  Not Now, and a primary Install button.
- Reappears on every PHP file switch in the project until explicitly
  dismissed via Not Now (session-scoped per project); switching away just
  closes it for that moment. The Problems-panel row stays as the quiet
  persistent affordance, and php.codeIntelligence remains the durable
  off-switch. Install click closes the bar and hands off to the existing
  TaskManager install task + auto-start.

Verified live: fresh consent -> bar -> Install -> server up; re-show on
file switch; benefits tooltip; bar closes on non-php files.
@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
4.9% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

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