Skip to content

Improve lang tooling: Docker, tree-sitter, IntelliJ plugin, CI#384

Merged
lagergren merged 24 commits intomasterfrom
lagergren/extend-lsp1
Feb 7, 2026
Merged

Improve lang tooling: Docker, tree-sitter, IntelliJ plugin, CI#384
lagergren merged 24 commits intomasterfrom
lagergren/extend-lsp1

Conversation

@lagergren
Copy link
Contributor

Summary

This branch improves the lang/ tooling subsystem across several areas:

Docker build environment

  • Add lang/Dockerfile for reproducible builds of the full lang stack (LSP server, tree-sitter, IntelliJ plugin)
  • Zig cross-compilation for tree-sitter native libs targeting all 5 platforms
  • JDK 25 base image with Gradle toolchain provisioning
  • X11 forwarding instructions for Linux and Windows WSL2

Tree-sitter improvements

  • Switch to native QuickJS runtime instead of requiring Node.js
  • Fix tree-sitter not included in aggregate clean task
  • Add path assertions for native library lookup
  • CI: skip tree-sitter validation when lang/ files are unchanged

IntelliJ plugin

  • Default to downloaded IntelliJ Community IDE (cached in ~/.gradle by version) instead of requiring a local installation
  • Fix SlowOperations EDT assertion in New Project wizard (async VFS refresh)
  • Add buildPlugin task logging with distribution ZIP path and installation instructions
  • Make buildSearchableOptions controllable via -Plsp.buildSearchableOptions=true property
  • Log sandbox paths and idea.log location during runIde
  • Clean sandbox on ./gradlew clean
  • Disable Ultimate-only plugins in sandbox when local IDE is Ultimate

JRE provisioning

  • Move JRE cache from IDE-specific directory to {GRADLE_USER_HOME}/caches/xtc-jre/ so it survives IDE cache invalidation
  • Check IntelliJ's registered JDKs before downloading
  • Add metadata tracking with periodic update checks

CI & build

  • Gate integration tests behind RUN_INTEGRATION_TESTS env var
  • Gate manual test composite builds on include-lang workflow dispatch flag
  • Disable lang/ composite build by default (includeBuildLang=false) to avoid impacting regular XDK development
  • Remove hardcoded JVM memory limits from Dockerfile

Plan updates

  • Expand semantic tokens roadmap into two phases:
    • Phase 1: Lexer/tree-sitter based (annotations, keywords, strings — no compiler needed)
    • Phase 2: Compiler-based (full type-aware classification)
  • Update feature matrix to reflect tree-sitter semantic token capabilities

Test plan

  • ./gradlew :lang:intellij-plugin:buildPlugin succeeds with configuration cache
  • Plugin distribution ZIP logged with install instructions
  • runIde launches sandbox IDE without SlowOperations assertion on project creation
  • buildSearchableOptions property toggles correctly
  • CI passes with lang/ disabled by default
  • Docker build produces working LSP server fat JAR

🤖 Generated with Claude Code

Add path filtering to conditionally run tree-sitter grammar validation
only when relevant files change. Uses dorny/paths-filter to detect
changes in:
- lang/** (grammar DSL, tree-sitter, LSP server)
- lib_ecstasy/**/*.x (XTC source files used as parsing corpus)

When no lang-related files change, the tree-sitter validation step is
skipped to save CI time. Gradle's content-based caching ensures that
even when the step runs, only tasks with actual input changes execute.
- Move JRE cache from IntelliJ system path to GRADLE_USER_HOME/caches/xtc-jre/
  (persists across IDE sessions, not cleared by "Invalidate Caches")
- Add metadata tracking (package ID, platform, timestamp) for cache validation
- Check Foojay for newer JRE versions every 7 days
- Default to downloading IntelliJ Community instead of using local IDE
  (avoids incompatible bundled plugins like Full Line Code Completion)
- Use -PuseLocalIde=true to override and use local installation
- Fix macOS JRE extraction: search recursively for bin/java instead of
  hardcoding paths (handles Contents/Home structure)
- Update plan docs with current implementation status
- Add lang/Dockerfile demonstrating runIde works with clean environment
  (only JDK 21/24 and IntelliJ pre-installed, all other tools downloaded)
- Add lang/.dockerignore to exclude build artifacts from Docker context
- Add logging and assertions to tree-sitter tasks to verify we're using
  build-local CLI and grammar.js (not system-installed tree-sitter)

The assertions will fail the build if anyone accidentally uses a
system-installed tree-sitter or grammar.js from outside the build tree.
Remove manual JDK 24 download - let Gradle auto-provision it like JDK 25.
Add assertions to verify:
- Base image JDK is version 21 (for IntelliJ)
- Gradle provisions JDK 24 (org.xtclang.kotlin.jdk from version.properties)
- Gradle provisions JDK 25 (org.xtclang.java.jdk from version.properties)

This ensures the Dockerfile stays in sync with version.properties and
demonstrates that Gradle handles all JDK provisioning automatically.
- Explain headless operation (Xvfb virtual display, nothing on host)
- Add command to capture output to log file for debugging
- Add instructions for X11 forwarding on Mac (XQuartz)
- Fix inline comment that broke multi-line RUN
- Update build instructions to run from project root with -f lang/Dockerfile
- Keep .git in build context for palantir-git-version plugin
- Sort apt packages alphabetically
- Use eclipse-temurin:25-jdk-noble (was 21-jdk-jammy)
- Run ./gradlew build to provision JDK 24 via Foojay
- JDK 25 comes from base image, only JDK 24 needs provisioning
- Download architecture-specific IntelliJ (arm64/x86_64)
- Pre-install JDK 24 to avoid Foojay API dependency
- Add BuildKit cache mounts for faster rebuilds
- Set JVM memory limits to prevent OOM in constrained environments
- Add build caching documentation
- Add :tree-sitter to coreProjects in lang/build.gradle.kts
- Use IntelliJ bundled JBR-21 instead of separate JDK 21 install
…idiomatic Kotlin

- Make local IntelliJ IDE the default instead of downloading (use -PdownloadIde=true to override)
- Switch to Provider API for Gradle properties (CC-compatible)
- Add lifecycle-level build logging for IDE selection, TextMate/LSP resource copying, and sandbox config
- Add humanSize() and logCopiedFiles() utilities to build-logic for CC-safe task instrumentation
- Use idiomatic Kotlin patterns: buildList, in operator, method references, two-arg System.getProperty
Make includeBuildManualTests and includeBuildAttachManualTests false by
default for workflow_dispatch, enabled only when include-lang is true.
Push and PR events continue to include manual tests automatically.
Add @EnabledIfEnvironmentVariable annotations to XDK integration tests
so they only run when RUN_INTEGRATION_TESTS=true is set, and set that
env var in the CI workflow. Fix FileUtil.delete() calls in JreProvisioner
to pass File instead of Path.
Flip the default IDE resolution: download IntelliJ Community (cached in
~/.gradle by version) instead of auto-detecting a local installation.
Use -PuseLocalIde=true or -PintellijLocalPath=/path to opt in to local.

Log the sandbox directory and idea.log path when runIde starts so the
paths are clickable in the IDE console.

Extend the clean task to also delete build/idea-sandbox/ so that version
or dependency changes are picked up on the next run.

Re-enable lang composite build includes in gradle.properties.
… searchable options

Fix SlowOperations EDT assertion in project wizard by making VFS refresh
async. Add buildPlugin task logging with ZIP path and installation
instructions. Make buildSearchableOptions controllable via
-Plsp.buildSearchableOptions property. Expand semantic tokens plan into
two phases (lexer-based and compiler-based).
The lang/ subtree (IntelliJ plugin, LSP server, tree-sitter) adds
significant build time and has dependencies (Java 25, native libs) that
not all contributors need. Default to includeBuildLang=false so regular
XDK development is unaffected. Enable with -PincludeBuildLang=true or
by editing gradle.properties.
Copy link
Collaborator

@ggleyzer ggleyzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

The env vars were overriding gradle.properties and forcing
includeBuildLang=true on all push/PR events. Now lang is only included
when explicitly requested via workflow_dispatch with include-lang=true.
…arsing

Add LspIntegrationTest that exercises the LSP server against real .x source
files (Boolean.x, Exception.x, Closeable.x, TestSimple.x) using the
TreeSitter adapter with native parsing. Tests cover hover, completion,
definition, references, documentSymbol, formatting, and structural features.

The build passes xtc.composite.root to the test JVM (same marker-file
approach as XdkPropertiesService) and enables FFM native access to suppress
JDK warnings for tree-sitter's SymbolLookup calls.

Update PLAN_TREE_SITTER.md: mark Phase 3 query tests and Phase 4 LSP
features as complete.
@lagergren lagergren merged commit c62614d into master Feb 7, 2026
4 checks passed
@lagergren lagergren deleted the lagergren/extend-lsp1 branch February 7, 2026 17:49
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.

2 participants