Add XTC Language Support: LSP server, IntelliJ plugin, and VS Code extension#377
Add XTC Language Support: LSP server, IntelliJ plugin, and VS Code extension#377
Conversation
4f18ce7 to
2a95b68
Compare
ggleyzer
left a comment
There was a problem hiding this comment.
I wonder if we could move the "lang" module into its own repo (e.g. "xtclang/lsp")? It seems that would make everything a bit cleaner...
b6c9d0f to
58785c2
Compare
|
It is super news for LSP4IJ ! When your plugin will be available please add it to the lsp4j readme https://github.com/redhat-developer/lsp4ij?tab=readme-ov-file#who-is-using-lsp4ij And if you like LSP4IJ please add a review in Jetbrains marketplace to help us to promote LSP4IJ Thanks! |
It is a composite build. There is virtually nothing outside the lang repo that were are referring to in any other place, except for the version catalog. I also heavily depend on project independent build logic, the javatools, and various other things that I access from lang but not in the other way around. I see no "cleaner" way to do it that would not inline both new and modified gradle work. I also want to be able to do stuff line run intellij on the current code base. It certainly not in the way for anyone, and if you don't even want to resolve the build against it, you can, just like manualTests, replace the attach and include flags in gradle.properties to ignore the gradle project. So I would very much like to get these changes in ASAP, without having to risk the rather complicated dependencies towards the rest of the XDK for now. The build structure for lang was very hard to get working, and I would appreciate it if we could work more incrementally with that. I need this code base to continue, and I am heavily relying on our common build logic for version control against what the XDK is built on. As fast as a I understand it, this seems to be best practice. |
ee2c1b2 to
d149057
Compare
cpurdy
left a comment
There was a problem hiding this comment.
- I like the changes to the README, particularly moving massive chunks into their own specific "read more" files. I was going to suggest something like this, so I'm glad to see you beat me to it.
- I like the changes to the .gitignore file.
- gradle.properties "TODO: LSP do not check in true/true here. Used for dev" -- can you verify that you actually want this in the commit?
- DockerTest.x -- was this change intentional? (Trailing whitespace only.) The only thing that worries me if it wasn't intentional is that you let the reviewer (me) find this.
- Initializer tool -- I have no issues with having support for tools, including Gradle/Maven, as long as developers using Ecstasy have zero required dependencies on those tools. My big concern here is that the Initializer stuff seems a bit brittle, but I guess we'll find out over time if that concern is real.
- javatools-utils/build.gradle.kts -- I think I found where that trailing whitespace in DockerTest.x came from!
- javatools-utils/README.md -- never mind, it probably came from here 🤣
- Lazy/Suppiers -- These look fine, but were unnecessary as part of this overall change. I understand the desire to "upgrade" things as you go, and it's a good desire. It's something that we also try to do consistently. But work on building consensus in advance, though, i.e. involve others in the process up front. In this case, you replaced thread safe (via idempotency) code with thread safe (via a different mechanism) code. The upside of the change is unlikely to be realized in this particular change set, but I can see opportunities for benefits down the road, which is exactly why getting more buy-in (and thus awareness) is such an important part of the process! I would like you to do a walk through of this functionality on a team call to get others up to speed!
- lang/README.md -- Very good overall. We try not to refer to "XTC" ... Ecstasy is the language name, and xtclang is also usable, referring to the "language project" I guess.
- vscode extension -- Hard for me to provide much feedback. I've read through everything, but this is not my area of expertise. Again, I worry about some brittleness, but I also accept that tool integration is likely where we will be forced to deal with brittleness no matter how clever we are.
- IntelliJ plugin -- Similar summary as for vscode, in that I am not an expert on the IDE integration, and I am worried about brittleness. But the README is well done and we're still in a learning phase, so I am comfortable with the content in that context.
Next up I plan to go through the LSP Server and DSL sub-projects. I've simply run out of hours today. Overall, this is a huge effort, and I am looking forward to seeing it in action!
ef29121 to
9b3c2c0
Compare
Replace manual temp directory creation and cleanup with JUnit 5's @tempdir annotation which guarantees cleanup even if tests fail. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move LSP server code to dedicated lang/lsp-server subproject - Implement in-process StreamConnectionProvider using piped streams - Fix LSP4J dependency conflict: use compileOnly since LSP4IJ provides LSP4J at runtime (avoids ClassCastException from classloader conflicts) - Remove subprocess approach and hardcoded JAR paths - Target JDK 21 for IntelliJ 2025.1 compatibility - Add TextMateBundleProvider for dynamically generated grammar - Remove System.exit() from server exit() to support in-process execution The LSP server now runs in the same JVM as IntelliJ, communicating via piped input/output streams. This eliminates subprocess management issues and resolves the "Cannot start server (pid=null)" errors. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add InitializerOptions to LauncherOptions.java with CLI schema - Refactor Initializer.java to use new Launcher<T> pattern - Add CMD_INIT to Launcher.java COMMANDS map and launch() switch - Update showHelp() to include init command - Fix InitializerTest to use isError() instead of private field - Add comprehensive XTC CLI documentation (doc/XTC_CLI.md) - Link CLI docs from main README The xtc init command now works like other commands (build, run, test): xtc init myapp # Create application xtc init mylib --type=library # Create library xtc init myproj --multi-module # Create multi-module project Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allows specifying the parent directory for project creation: xtc init myapp --dir=/path/to/parent The project is created at <dir>/<name> instead of ./<name>. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
These are generated files from the IntelliJ Platform Gradle Plugin and should not be tracked. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensures the latest XTC Gradle plugin is published to local Maven before the sandbox IDE starts. This fixes Run Configurations that use the --module, --method, --args command-line options which older plugin versions don't support. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Key changes: - Remove safe_call_else_expression which was blocking member expression + call - Fix x?.foo() to correctly parse as call_expression(member_expression) - Support static @abstract const (annotations after static modifier) - Add $._non_bi_type vs generic_type conflict Coverage: 355/691 (51%). The x?.foo() fix is critical for correct parsing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes: - Add support for empty array creation: new Type[] Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added the following grammar features: - Else expression: `expr?.method() : fallback` for short-circuit fallbacks - Short-circuit postfix: `expr?` for null checking - TODO expression: `TODO`, `TODO(msg)`, `TODO text` for placeholders - Type patterns in case: `case List<String>:` for type matching Coverage improved from 381/691 (55.1%) to 419/692 (60.5%) XTC files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
9b3c2c0 to
a4dd596
Compare
… versioning - Rename VSCodePackageGenerator to TextMateBundleManifestGenerator to reflect that it generates TextMate bundle manifests used by VS Code, IntelliJ, etc. - Fix version handling: Gradle now passes project.version as system property with proper cache input declaration; generators fail if version not provided - Derive language ID from scopeName for consistency (source.xtc -> xtc) - Rename PLAN_OUT_OF_PROCESS_LSP.md to lsp-processes.md, update all references - Update dsl/README.md to list actual existing files - Sync generated-examples with current generators (was stale) - Remove .claude/ from source control, update .gitignore - Fix typo in grammar.js.template - Fix ktlint formatting issues - Add TODO to README about Ecstasy/XTC naming convention - Add comment explaining tree-sitter workDir and harmless warnings
By default, ktlint only runs as part of the 'check' task, which means development tasks like runIde, jar, and assemble skip ktlint entirely. This caused CI failures when formatting violations were committed. Fix by making compileKotlin depend on ktlintCheck in all lang subprojects.
Replace 620 lines across 3 files (JreProvisioner, FoojayClient, PlatformDetector) with a single 200-line JreProvisioner that: - Uses Foojay Disco API for JRE discovery - Uses IntelliJ's built-in Decompressor.Tar/Zip for extraction - Adds extensive logging for troubleshooting
- Update PLAN_TREE_SITTER.md and lsp-processes.md for Java 25 and JRE provisioning - Add Platform.kt utility to consolidate platform detection in lsp-server - Update TreeSitterAdapter MIN_JAVA_VERSION to 25 - Add detailed logging for definition/references lookups - Remove unused gitCommitShort provider from tree-sitter build
- Add TARGET_VERSION constant back to JreProvisioner - Forward lsp.logLevel from IntelliJ to LSP server process - Update logback.xml to read lsp.logLevel property - Accepts DEBUG, INFO, WARN, ERROR (case-insensitive) Usage: ./gradlew :lang:intellij-plugin:runIde -Dlsp.logLevel=DEBUG
- Rewrite XtcNewProjectWizardStep with idiomatic Kotlin (runCatching, when, apply) - Use Java record properties directly (result.success, result.message) - Fix KDoc references to use literal values instead of unresolvable links - Fix ktlint chain-method-continuation warning
JreProvisioner now uses a smarter resolution strategy: 1. Check IntelliJ's ProjectJdkTable for registered Java 25+ SDKs 2. Fall back to cached JRE in IDE's system directory 3. Download Temurin JRE 25 via Foojay API only if needed Key changes: - Add com.intellij.modules.java dependency for SDK APIs - Use JavaSdk.getVMExecutablePath() instead of hardcoded paths - Cache JRE in PathManager.getSystemPath() (IDE-managed location) - Add comprehensive KDoc explaining the provisioning strategy - Fix archive extraction to flatten nested directories - Add failure marker to prevent infinite retry loops - Make XtcIconProvider more idiomatic Kotlin (runCatching) - Update plans to reflect new architecture
…ation cache in Gradle, but we can add some boiler plate to force intellij to read the Gradle toolchain configuration, so we get rid that annoying 'stuff was changed in .idea, and this is a JDK 1.6 project now - sorry'.
…sitter task always run. Now has proper imports, which should be fine both for build or CI
These integration tests spawn separate Gradle processes for each generated project, downloading dependencies and the Gradle wrapper from scratch. With an empty cache, this adds several minutes to the build. Enable with: RUN_INTEGRATION_TESTS=true ./gradlew javatools:test
- Unify log level property to xtc.logLevel across all XTC tooling - Add file-based logging to ~/.xtc/logs/lsp-server.log with rolling policy - Log file path and PID in startup banner for easier debugging - Add extension functions for formatting LSP Position/Range types - Use import aliases to clean up verbose fully-qualified type names - Move companion objects to top of classes (Kotlin idiomatic) - Simplify hover info generation with Elvis operator and ?.let - Add explicit classes dependency to fatJar for proper rebuilds - Update lsp-processes.md documentation for xtc.logLevel
Add Lsp4jConversions.kt with extension functions for converting between model types and LSP4J types: - Location.toRange(), Location.toLsp(), Location.fromLsp() - Diagnostic.Severity.toLsp(), Diagnostic.Severity.fromLsp() - Diagnostic.toLsp(), Diagnostic.fromLsp() - SymbolInfo.SymbolKind.toLsp() - XtcCompilerAdapter inner types (HighlightKind, FoldingKind, etc.) This removes ~100 lines of scattered inline conversion code from XtcLanguageServer.kt and consolidates all LSP4J mappings in one place. Other improvements: - Add XtcLanguageConstants.kt for shared keyword/type data - Add XtcCompilerAdapterStub for compiler adapter placeholder - Add companion objects to Diagnostic.Severity and SymbolInfo.SymbolKind - Clean up unused imports and type aliases - Add tree-sitter feature matrix documentation
- Add AbstractXtcCompilerAdapter base class with shared: - Per-class logger (lazy initialized) - logPrefix property for consistent log formatting - getHoverInfo() default implementation - Location.contains() utility extension - Closeable with no-op close() - Add XtcLanguageConstants utilities: - SymbolInfo.toHoverMarkdown() extension - keywordCompletions() and builtInTypeCompletions() helpers - Simplify adapters: - MockXtcCompilerAdapter: use top-level camelCase regex vals, destructuring - TreeSitterAdapter: remove duplicate code, use shared utilities - XtcCompilerAdapterStub: minimal placeholder with @workinprogress - Delete unused XtcCompilerAdapterFull interface (was never implemented) - Add @workinprogress annotation in org.xvm.lsp.util - Add quietMode (-q flag) to XtcRunConfiguration for less verbose Gradle output - Add logging to XtcRunConfiguration - Update documentation to reflect new adapter hierarchy Net change: -600 lines (consolidation of duplicate code)
- Fix table formatting in functionality.md and tree-sitter README - Update Lsp4jConversions.kt formatting - Minor documentation improvements
Document what compiler phases are needed for each feature: - XtcCompilerAdapterStub: All methods need Phase 4-5 integration - TreeSitterAdapter: Note limitations of syntax-only approach
7333869 to
2dfb74b
Compare
- Make SCANNER_DEBUG configurable via generate(debug: Boolean = false) - CLI accepts --debug flag to enable scanner debug output - Temporarily disable tree-sitter validation step in CI (if: false) - Preserve original condition as comment for re-enabling later
583b74c to
94aef00
Compare
Add remaining changes that were not included in the initial LSP server PR: extended XtcLanguageServer implementation, additional unit tests, and editor setup documentation.
Summary
XTC language tooling infrastructure with IDE support and high-quality parsing.
Tree-sitter Grammar
$"text {expr}",$|multiline|) and TODO freeform textLSP Server
MockXtcCompilerAdapter(regex, for testing) →TreeSitterAdapter(syntax-level) → futureCompilerAdapter(semantic)-Plsp.adapter=treesitterIDE Plugins
--module,--method,--args), TextMate highlighting, LSP via lsp4ijOther
xtc initcommand: New launcher command for initializing XTC projects with--diroptionXtcLanguage.ktmodel--module,--method,--argsoptions torunXtctaskBuild Infrastructure
includeBuildLangflag controls lang build inclusion (disabled by default for CI stability)Test plan
includeBuildLang=false(master compatibility)runIntellijPlugindepends onpublishLocalfor proper sandbox IDE testing