Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
435b67a
chore: split CI per package and document monorepo layout
math3usmartins May 21, 2026
2c5ed0a
chore: split Makefile per package (pure separation, no root delegation)
math3usmartins May 21, 2026
d13fb7d
lsp: add Humbug Box PHAR build pipeline (chunk 1/7 of phpstorm-plugin)
math3usmartins May 22, 2026
f23352e
phpstorm-plugin: scaffold Gradle + Kotlin project (chunk 2/7)
math3usmartins May 23, 2026
ed8babe
phpstorm-plugin: register .xphp file type + bundle TextMate grammar (…
math3usmartins May 23, 2026
fbfbc23
phpstorm-plugin: wire the LSP via a settings-driven binary path (chun…
math3usmartins May 23, 2026
6f3e355
phpstorm-plugin: bundle xphp-lsp.phar with auto-extract on first load…
math3usmartins May 23, 2026
508f973
ci: add per-package CI workflow for the PhpStorm plugin (chunk 6/7)
math3usmartins May 23, 2026
4956440
docs: promote PhpStorm plugin in roadmap + finalize package README (c…
math3usmartins May 23, 2026
5950154
chore: jdk container service + per-package Makefile routing
math3usmartins May 23, 2026
34a92a8
phpstorm-plugin: declare com.intellij.modules.platform module dependency
math3usmartins May 23, 2026
ea96b0b
phpstorm-plugin: fix settings persistence via BoundConfigurable
math3usmartins May 23, 2026
76ddebb
phpstorm-plugin: enable xphp syntax highlighting via TextMate
math3usmartins May 23, 2026
54a7612
phpstorm-plugin: refactor PharExtractor for testability + race-free temp
math3usmartins May 23, 2026
47f17ac
phpstorm-plugin: notify and open settings when LSP binary missing
math3usmartins May 23, 2026
a156dfe
phpstorm-plugin: add phpPath setting (VS Code parity)
math3usmartins May 23, 2026
7eeb791
phpstorm-plugin: misc polish (build inputs, xhost guard)
math3usmartins May 23, 2026
9c138cf
phpstorm-plugin: declare the TextMate v2 module dependency
math3usmartins May 23, 2026
86d2458
phpstorm-plugin: register TextMate bundle via user-bundles registry
math3usmartins May 23, 2026
c929013
phpstorm-plugin: ship info.plist so TextMate accepts the bundle format
math3usmartins May 23, 2026
4fb73e6
phpstorm-plugin: drop PhpLanguage parent so .xphp files actually open
math3usmartins May 23, 2026
ef80ca4
phpstorm-plugin: declare com.intellij.modules.lsp dependency
math3usmartins May 23, 2026
b1c7120
phpstorm-plugin: drop XphpFileType + XphpLanguage; LSP filters by ext…
math3usmartins May 23, 2026
6428e41
phpstorm-plugin: resolveBinary falls back to bundled PHAR on missing …
math3usmartins May 24, 2026
459e864
lsp: encode hoverProvider as bool so IntelliJ's LSP4J accepts it
math3usmartins May 24, 2026
a127f60
phpstorm-plugin: always refresh bundled PHAR so plugin upgrades take …
math3usmartins May 24, 2026
9e5a0cf
phpstorm-plugin: stop LSP-server bounce-and-die cycle
math3usmartins May 24, 2026
94efa4c
lsp: fix xphp-extras grammar look-behind for IntelliJ Joni compatibility
math3usmartins May 24, 2026
bf5b2be
lsp: GTD on type-args inside generic clauses (Box<User>, identity<Use…
math3usmartins May 24, 2026
cc059fb
phpstorm-plugin: opt into LSP-routed editor actions via LspCustomization
math3usmartins May 24, 2026
c97f1b5
lsp: add worse-reflection + phpstorm-stubs deps and reflection plumbing
math3usmartins May 24, 2026
c10d31d
lsp: PHP-semantic Go-To-Declaration via worse-reflection
math3usmartins May 24, 2026
946ac48
lsp: PHP-semantic hover via worse-reflection
math3usmartins May 24, 2026
579b72d
lsp: PHP-semantic completion (member + static access) via worse-refle…
math3usmartins May 24, 2026
2332ef0
docs(lsp): reflect broader scope of hover / definition / completion
math3usmartins May 24, 2026
0ecb23c
lsp: harden resolvers against MissingType + protect LSP transport
math3usmartins May 24, 2026
1ae92cf
lsp: variable GTD + extract phpstorm-stubs from PHAR to file:// cache
math3usmartins May 24, 2026
d3f4161
lsp: completion in expression position (functions, classes, variables)
math3usmartins May 24, 2026
02c8b1d
lsp: fix didChange dropping all updates + add resolver stderr traces
math3usmartins May 24, 2026
1183028
lsp: strip nullable prefix + tolerant-parse for variable completion
math3usmartins May 24, 2026
789699d
lsp: hover on variables shows their inferred type
math3usmartins May 24, 2026
13eafec
lsp: monomorphization-aware hover + completion for generic instantiat…
math3usmartins May 24, 2026
109bd00
lsp(phase 0): unified FqnIndex; substitution works on closed files
math3usmartins May 24, 2026
e2d47ea
lsp(phase 1): substitution coverage for 5 new shapes
math3usmartins May 24, 2026
813f18c
lsp(phase 0.5): GenericParamRegistry consumes FqnIndex
math3usmartins May 24, 2026
6c768c4
playground: fix doubled-namespace return type in InMemoryRepository::…
math3usmartins May 24, 2026
fe63e4c
lsp(phase 0.6): substitute parameter types in method hovers
math3usmartins May 24, 2026
d159158
lsp(phase 0.7): substitute receiver type on property hover + GTD
math3usmartins May 24, 2026
7f8e25b
lsp: substitute receiver type on completion through chained calls
math3usmartins May 24, 2026
e42c3d5
lsp(phase 2.1): emit document symbols for outline + Cmd+O
math3usmartins May 24, 2026
8358514
lsp(phase 2.1): preserve byte offsets when emitting document symbols
math3usmartins May 24, 2026
9e818e8
lsp(phase 2.2): workspace/symbol search across open + filesystem
math3usmartins May 24, 2026
c09731d
lsp(phase 2.3): GTD on unopened-file targets resolves via FqnIndex
math3usmartins May 24, 2026
2adaf7e
lsp(phase 2.4): refresh FqnIndex on filesystem changes
math3usmartins May 24, 2026
0f939aa
lsp(phase 3): skip test/fixture in FqnIndex + deterministic short-nam…
math3usmartins May 25, 2026
fc7143d
lsp(phase 3): workspace/symbol strips PhpStorm's Class::member suffix
math3usmartins May 25, 2026
d950ecc
lsp(phase 3): surface private/protected members when caller is in the…
math3usmartins May 25, 2026
08cfea4
lsp(phase 3): suppress completion inside strings, comments, and heredocs
math3usmartins May 25, 2026
7a146b9
lsp(phase 4.1): textDocument/references for classes and top-level fun…
math3usmartins May 25, 2026
5c1c467
lsp(phase 4.1+): method and property references
math3usmartins May 25, 2026
990e6d9
lsp(phase 4.2): textDocument/rename for classes, functions, methods, …
math3usmartins May 25, 2026
2a63295
lsp: static property hover + GTD + render `static` modifier
math3usmartins May 25, 2026
3f4fa06
lsp(followups): alias-aware rename + use-function references
math3usmartins May 25, 2026
9f6d5df
lsp(followups): GTD + hover inside `use function ...` import
math3usmartins May 25, 2026
7fdb662
lsp(followups): hover on declaration line + GTD-on-decl as find-usages
math3usmartins May 25, 2026
3188634
lsp(followups): emit RenameFile alongside class rename (gated on clie…
math3usmartins May 25, 2026
f604dec
lsp(followups): param substitution for static + free-function calls
math3usmartins May 25, 2026
3d94db0
lsp(followups): inheritance walks for references / rename / GTD
math3usmartins May 25, 2026
c77ecb7
lsp(phase-2.3): lock in hover on filesystem-only classes
math3usmartins May 25, 2026
ebfc18c
lsp(phase-3): subclass-protected member completion
math3usmartins May 25, 2026
78def6a
lsp(phase-3): scope-aware variable completion
math3usmartins May 25, 2026
d1ddff1
lsp(phase-3): bound-aware type-arg completion
math3usmartins May 25, 2026
a5b7b5d
lsp(phase-3): Cls::\$prop completion
math3usmartins May 25, 2026
ac72180
lsp(phase-3): short-name tie-break in findClassByName
math3usmartins May 25, 2026
6513959
lsp(phase-3): UTF-16 column counting in PositionMap
math3usmartins May 25, 2026
f91d1d6
lsp(phase-3): prod follow-ups + playground fixtures
math3usmartins May 25, 2026
297874e
docs: refresh LSP feature inventory across roadmap + READMEs
math3usmartins May 25, 2026
64e6d62
docs(roadmap): rename Vision -> Long-term; add LSP capability inventory
math3usmartins May 25, 2026
d040b02
ci(phpstorm-plugin): release workflow on tag push + manual dispatch
math3usmartins May 25, 2026
ce526dd
ci(lsp): raise memory_limit for Infection initial coverage run
math3usmartins May 25, 2026
651477e
ci(lsp): switch Infection coverage driver from Xdebug to PCOV
math3usmartins May 25, 2026
61def3e
ci(phpstorm-plugin): route gradle through host-side wrapper on CI
math3usmartins May 25, 2026
de16528
ci(lsp): gate Infection job to manual dispatch
math3usmartins May 25, 2026
0f95378
ci(phpstorm-plugin): build PHAR before verifyPlugin
math3usmartins May 25, 2026
3e4f95c
test(core): close mutation-testing gaps; Covered MSI 92.71% -> 93%
math3usmartins May 25, 2026
039eb1a
test(core): mutation testing now at 100% MSI; raise gate to 95%
math3usmartins May 25, 2026
8afd3a1
chore(compose): promote jdk service to tracked docker-compose.yml
math3usmartins May 25, 2026
0ab0511
phpstorm-plugin: fix Plugin Verifier failures (override-only + deprec…
math3usmartins May 25, 2026
70463fd
phpstorm-plugin: disable Gradle parallel mode to dodge zip race
math3usmartins May 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .docker/jdk.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM eclipse-temurin:21-jdk

# X11 + font + GTK libs PhpStorm needs to render its Swing UI under
# `./gradlew runIde`. The base image ships headless deps only; without
# these the JVM boots but dies on the first Toolkit.getDefaultToolkit()
# call with "Can't connect to X11 window server" or a font-config error.
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
libxext6 libxrender1 libxi6 libxtst6 libxrandr2 libxcursor1 \
libxinerama1 libfontconfig1 libfreetype6 libgtk-3-0 \
fonts-dejavu-core \
&& rm -rf /var/lib/apt/lists/*
22 changes: 20 additions & 2 deletions .docker/php.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
FROM php:8.4-cli-alpine

# Composer: copied from the official multi-arch image instead of curl-
# piped install. Reproducible across rebuilds and gets composer 2.x
# without an interactive installer. Both Makefile entry points
# (`make test` and `make test/mutation`) shell out to `composer
# install`, so this needs to be in PATH.
COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer

RUN apk add --update --no-cache linux-headers
RUN apk add --no-cache \
php84-dev \
build-base
build-base \
git \
unzip

# Both coverage drivers are installed. Xdebug runs as the dev-time
# debugger; PCOV is used exclusively for Infection's coverage pass
# (orders of magnitude less memory than Xdebug, which avoids the
# host OOM-killer firing during the initial test run on tight
# containers). Infection auto-detects PCOV when it's loaded and
# Xdebug is disabled via XDEBUG_MODE=off; the mutation Makefile
# target does both.
RUN pecl install \
xdebug \
pcov \
&& docker-php-ext-enable \
xdebug
xdebug \
pcov
69 changes: 69 additions & 0 deletions .github/workflows/ci-core.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Core CI

on:
pull_request:
push:
branches: [main]

# Cancel superseded runs on the same branch (e.g. when a PR gets a new push)
# so we don't pay for stale-commit mutation runs. The concurrency group is
# keyed on the workflow name + ref, so this is per-workflow — the LSP CI
# can run concurrently with this one without queueing.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
phpunit:
name: PHPUnit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup PHP 8.4
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: dom, json, mbstring, tokenizer
coverage: none
tools: composer:v2

- name: Install dependencies
uses: ramsey/composer-install@v3

- name: Run PHPUnit
run: make test/unit

infection:
name: Mutation testing
runs-on: ubuntu-latest
needs: phpunit
steps:
- uses: actions/checkout@v4

- name: Setup PHP 8.4 (with Xdebug for coverage)
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: dom, json, mbstring, tokenizer
coverage: xdebug
tools: composer:v2

- name: Install dependencies
uses: ramsey/composer-install@v3

- name: Run Infection
# --min-covered-msi=93 fails CI if mutation score drops below 93 (current baseline: 94%).
# --threads=4 parallelizes mutant runs; safe on the 2-core ubuntu-latest runner.
run: make test/mutation

- name: Upload Infection report
if: always()
uses: actions/upload-artifact@v4
with:
name: infection-report
path: |
var/infection.log
var/infection.html
if-no-files-found: ignore
retention-days: 14
94 changes: 94 additions & 0 deletions .github/workflows/ci-lsp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: LSP CI

# PHPUnit runs on every PR + push to main as a hard gate.
# Infection (mutation testing) is opt-in via workflow_dispatch -- its
# resource envelope outgrew GitHub-hosted `ubuntu-latest` (~7 GB RAM)
# once the suite passed ~150 tests, and the initial coverage run now
# OOMs as SIGTERM 143 mid-stream. Re-enable as a PR gate once the
# job is reshaped to filter / batch the test set (see follow-up).
on:
pull_request:
push:
branches: [main]
workflow_dispatch:

# Per-workflow concurrency. See ci-core.yml for the rationale.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
phpunit-lsp:
name: PHPUnit (LSP)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup PHP 8.4
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: dom, json, mbstring, tokenizer
coverage: none
tools: composer:v2

# The LSP package has its own composer.json under tools/lsp/ with a
# path-repo pointing back at the repo root. Cache its deps separately
# from the core install so a core-only change doesn't bust the LSP cache.
- name: Install LSP dependencies
uses: ramsey/composer-install@v3
with:
working-directory: tools/lsp

- name: Run PHPUnit (LSP)
run: make -C tools/lsp test

infection-lsp:
name: Mutation testing (LSP)
# Gate: only run when explicitly requested via the Actions tab. The
# 424-test suite plus per-mutation reruns overruns the GitHub-hosted
# runner's RAM, killing the initial coverage subprocess with SIGTERM
# 143. PRs and merges to main get fast unambiguous signal from the
# PHPUnit job above; Infection scoring is opt-in until the job is
# reshaped to filter / batch the test set.
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
needs: phpunit-lsp
steps:
- uses: actions/checkout@v4

- name: Setup PHP 8.4 (with PCOV for coverage)
# PCOV is preferred over Xdebug for Infection's initial run: an
# order of magnitude less memory under the same coverage scope,
# which keeps the runner well clear of the OOM-killer. The
# Makefile target sets pcov.directory + XDEBUG_MODE=off so the
# driver choice is deterministic regardless of what else is loaded.
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: dom, json, mbstring, tokenizer
coverage: pcov
tools: composer:v2

- name: Install LSP dependencies
uses: ramsey/composer-install@v3
with:
working-directory: tools/lsp

- name: Run Infection (LSP)
# `make -C tools/lsp test/mutation` lazily downloads infection.phar
# 0.33.1 into tools/lsp/var/ (PHAR sidesteps the composer dep conflict
# with phpactor/language-server documented in tools/lsp/README.md).
# Runs with --min-covered-msi=93; current baseline is 94%.
run: make -C tools/lsp test/mutation

- name: Upload Infection report (LSP)
if: always()
uses: actions/upload-artifact@v4
with:
name: infection-lsp-report
path: |
tools/lsp/var/infection.log
tools/lsp/var/infection.html
if-no-files-found: ignore
retention-days: 14
141 changes: 141 additions & 0 deletions .github/workflows/ci-phpstorm-plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
name: PhpStorm Plugin CI

on:
pull_request:
push:
branches: [main]

# Per-workflow concurrency. See ci-core.yml for the rationale.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
gradle-build:
name: Gradle build (PhpStorm plugin)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# PHP + Composer are needed to build the bundled xphp-lsp.phar that
# processResources copies into the plugin jar at build time. Skipping
# this step would still produce a buildable plugin, but it would warn
# and ship without an embedded LSP -- defeating the zero-config
# install path we shipped in chunk 5.
- name: Setup PHP 8.4
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: dom, json, mbstring, tokenizer
coverage: none
tools: composer:v2

- name: Install LSP dependencies
uses: ramsey/composer-install@v3
with:
working-directory: tools/lsp

- name: Build xphp-lsp.phar
# Same target ci-lsp.yml's runtime relies on; the plugin's
# processResources picks this up from tools/lsp/var/.
run: make -C tools/lsp build/phar

- name: Setup JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
# Cache key is built from the wrapper version + build script
# hash, so this stays warm across PRs that don't touch the plugin
# build config.
gradle-home-cache-cleanup: true

- name: Build plugin (compile + test)
# `make build` from this directory is `./gradlew build`, which runs
# compileKotlin, test, and packages the plugin jar via the
# IntelliJ Platform Gradle Plugin's `composedJar` task.
run: make -C tools/phpstorm-plugin build

- name: Upload plugin jar
uses: actions/upload-artifact@v4
with:
name: xphp-phpstorm-plugin-jar
path: tools/phpstorm-plugin/build/libs/xphp-phpstorm-plugin-*.jar
if-no-files-found: error
retention-days: 14

- name: Upload test reports on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: phpstorm-plugin-test-reports
path: |
tools/phpstorm-plugin/build/reports/tests/
tools/phpstorm-plugin/build/test-results/
if-no-files-found: ignore
retention-days: 14

verify-plugin:
name: Plugin Verifier (PhpStorm plugin)
runs-on: ubuntu-latest
needs: gradle-build
steps:
- uses: actions/checkout@v4

# The verifier itself doesn't read the PHAR, but Gradle's build graph
# treats `processResources` as a prerequisite of `verifyPlugin` --
# and `processResources` declares xphp-lsp.phar as a required input
# via `inputs.file(...)` in build.gradle.kts. Without the PHAR on
# disk, the build aborts before the verifier even runs:
#
# property 'xphpLspPhar' specifies file '.../xphp-lsp.phar'
# which doesn't exist.
#
# So we rebuild the same PHAR the gradle-build job built. Both
# jobs sit on fresh runners; sharing via an artifact would also
# work but the PHAR rebuild is cheap (~2s) compared to the verifier
# downloading the IDE matrix that follows.
- name: Setup PHP 8.4
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: dom, json, mbstring, tokenizer
coverage: none
tools: composer:v2

- name: Install LSP dependencies
uses: ramsey/composer-install@v3
with:
working-directory: tools/lsp

- name: Build xphp-lsp.phar
run: make -C tools/lsp build/phar

- name: Setup JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Run IntelliJ Plugin Verifier
# `verifyPlugin` checks binary compatibility across the IDE matrix
# declared in build.gradle.kts `pluginVerification.ides {}` -- the
# `recommended()` set for since-build 261. A failure here means a
# platform API we depend on changed shape between IDE builds.
run: make -C tools/phpstorm-plugin verify

- name: Upload Plugin Verifier reports on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: phpstorm-plugin-verifier-reports
path: tools/phpstorm-plugin/build/reports/pluginVerifier/
if-no-files-found: ignore
retention-days: 14
Loading
Loading