diff --git a/README.md b/README.md index c524b9a..0ed2ddd 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,30 @@ JDTLS will automatically pick the appropriate runtime based on your project's so > > **Windows paths** typically look like `C:\Program Files\Java\jdk-17` +> **Important:** If your default runtime is below Java 17 and you're working with Gradle projects, the Gradle daemon will fail to start because modern Gradle requires JVM 17+. In this case, set `java.import.gradle.java.home` to a JDK 17+ path so that the Gradle daemon uses a compatible JVM independently of your project's compilation runtime. See the [Advanced Configuration](#advanced-configurationjdtls-initialization-options) section below for details. + +## Maven Configuration + +If your project uses custom or internal Maven repositories, you should point JDTLS at your Maven `settings.xml` so it can resolve dependencies: + +```jsonc +"initialization_options": { + "settings": { + "java": { + "configuration": { + "maven": { + "userSettings": "~/.m2/settings.xml", + // Optional: global settings for system-wide configuration + "globalSettings": "/path/to/global/settings.xml" + } + } + } + } +} +``` + +Without this, JDTLS's embedded Maven will only resolve artifacts from Maven Central, which will cause unresolved dependency errors for projects using internal or private repositories. + ## Advanced Configuration/JDTLS initialization Options JDTLS provides many configuration options that can be passed via the `initialize` LSP-request. The extension will pass the JSON-object from `lsp.jdtls.initialization_options` in your settings on to JDTLS. Please refer to the [JDTLS Configuration Wiki Page](https://github.com/eclipse-jdtls/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line#initialize-request) for the available options and values. @@ -244,7 +268,11 @@ Below is an opinionated example configuration for JDTLS with most options enable "java": { "configuration": { "updateBuildConfiguration": "automatic", - "runtimes": [] + "runtimes": [], + // Path to your Maven settings.xml (for custom/internal repositories) + "maven": { + "userSettings": "~/.m2/settings.xml" + } }, "saveActions": { "organizeImports": true @@ -308,6 +336,14 @@ Below is an opinionated example configuration for JDTLS with most options enable "enabled": true, "wrapper": { "enabled": true + }, + // JVM used by the Gradle daemon (must be JVM 17+ for modern Gradle). + // Set this if your default runtime is a lower version. + "java": { + "home": "/path/to/your/JDK17+" + }, + "annotationProcessing": { + "enabled": true } }, "maven": { diff --git a/languages/java/runnables.scm b/languages/java/runnables.scm index e4facbe..78590ea 100644 --- a/languages/java/runnables.scm +++ b/languages/java/runnables.scm @@ -1,6 +1,9 @@ ; Run the main function ((package_declaration - (scoped_identifier) @java_package_name)? + [ + (scoped_identifier) + (identifier) + ] @java_package_name)? (class_declaration (modifiers) @class-modifier (#match? @class-modifier "public") @@ -16,7 +19,10 @@ ; Run the main class ((package_declaration - (scoped_identifier) @java_package_name)? + [ + (scoped_identifier) + (identifier) + ] @java_package_name)? (class_declaration (modifiers) @class-modifier (#match? @class-modifier "public") @@ -31,8 +37,12 @@ (#set! tag java-main)) ; Run test function (marker annotation, e.g. @Test) -((package_declaration - (scoped_identifier) @java_package_name) +(program + (package_declaration + [ + (scoped_identifier) + (identifier) + ] @java_package_name)? (class_declaration name: (identifier) @java_class_name body: (class_body @@ -49,8 +59,12 @@ (#set! tag java-test-method)) ; Run nested test function -((package_declaration - (scoped_identifier) @java_package_name) +(program + (package_declaration + [ + (scoped_identifier) + (identifier) + ] @java_package_name)? (class_declaration name: (identifier) @java_outer_class_name body: (class_body @@ -74,8 +88,12 @@ (#set! tag java-test-method-nested)) ; Run test class -((package_declaration - (scoped_identifier) @java_package_name) +(program + (package_declaration + [ + (scoped_identifier) + (identifier) + ] @java_package_name)? (class_declaration name: (identifier) @java_class_name @run body: (class_body @@ -91,8 +109,12 @@ (#set! tag java-test-class)) ; Run nested test class -((package_declaration - (scoped_identifier) @java_package_name) +(program + (package_declaration + [ + (scoped_identifier) + (identifier) + ] @java_package_name)? (class_declaration name: (identifier) @java_outer_class_name body: (class_body diff --git a/languages/java/tasks.json b/languages/java/tasks.json index ac2bfe8..7969a9a 100644 --- a/languages/java/tasks.json +++ b/languages/java/tasks.json @@ -14,7 +14,7 @@ }, { "label": "$ZED_CUSTOM_java_class_name.${ZED_CUSTOM_java_outer_class_name:}.$ZED_CUSTOM_java_method_name", - "command": "package=\"$ZED_CUSTOM_java_package_name\"; outer=\"${ZED_CUSTOM_java_outer_class_name:}\"; inner=\"$ZED_CUSTOM_java_class_name\"; method=\"$ZED_CUSTOM_java_method_name\"; sep=\"$\"; if [ -n \"$outer\" ]; then c=\"$outer$sep$inner\"; else c=\"$inner\"; fi; if [ -f pom.xml ]; then [ -f ./mvnw ] && CMD=\"./mvnw\" || CMD=\"mvn\"; $CMD clean test -Dtest=\"$package.$c#$method\"; elif [ -f build.gradle ] || [ -f build.gradle.kts ]; then [ -f ./gradlew ] && CMD=\"./gradlew\" || CMD=\"gradle\"; $CMD test --tests \"$package.$c.$method\"; else >&2 echo 'No build tool found'; exit 1; fi;", + "command": "package=\"${ZED_CUSTOM_java_package_name:}\"; outer=\"${ZED_CUSTOM_java_outer_class_name:}\"; inner=\"$ZED_CUSTOM_java_class_name\"; method=\"$ZED_CUSTOM_java_method_name\"; sep=\"$\"; if [ -n \"$outer\" ]; then c=\"$outer$sep$inner\"; else c=\"$inner\"; fi; if [ -n \"$package\" ]; then fqc=\"$package.$c\"; else fqc=\"$c\"; fi; if [ -f pom.xml ]; then [ -f ./mvnw ] && CMD=\"./mvnw\" || CMD=\"mvn\"; $CMD clean test -Dtest=\"$fqc#$method\"; elif [ -f build.gradle ] || [ -f build.gradle.kts ]; then [ -f ./gradlew ] && CMD=\"./gradlew\" || CMD=\"gradle\"; $CMD test --tests \"$fqc.$method\"; else >&2 echo 'No build tool found'; exit 1; fi;", "use_new_terminal": false, "reveal": "always", "tags": ["java-test-method", "java-test-method-nested"], @@ -27,7 +27,7 @@ }, { "label": "Test class $ZED_CUSTOM_java_class_name", - "command": "package=\"$ZED_CUSTOM_java_package_name\"; outer=\"${ZED_CUSTOM_java_outer_class_name:}\"; inner=\"$ZED_CUSTOM_java_class_name\"; sep=\"$\"; if [ -n \"$outer\" ]; then c=\"$outer$sep$inner\"; else c=\"$inner\"; fi; if [ -f pom.xml ]; then [ -f ./mvnw ] && CMD=\"./mvnw\" || CMD=\"mvn\"; $CMD clean test -Dtest=\"$package.$c\"; elif [ -f build.gradle ] || [ -f build.gradle.kts ]; then [ -f ./gradlew ] && CMD=\"./gradlew\" || CMD=\"gradle\"; $CMD test --tests \"$package.$c\"; else >&2 echo 'No build tool found'; exit 1; fi;", + "command": "package=\"${ZED_CUSTOM_java_package_name:}\"; outer=\"${ZED_CUSTOM_java_outer_class_name:}\"; inner=\"$ZED_CUSTOM_java_class_name\"; sep=\"$\"; if [ -n \"$outer\" ]; then c=\"$outer$sep$inner\"; else c=\"$inner\"; fi; if [ -n \"$package\" ]; then fqc=\"$package.$c\"; else fqc=\"$c\"; fi; if [ -f pom.xml ]; then [ -f ./mvnw ] && CMD=\"./mvnw\" || CMD=\"mvn\"; $CMD clean test -Dtest=\"$fqc\"; elif [ -f build.gradle ] || [ -f build.gradle.kts ]; then [ -f ./gradlew ] && CMD=\"./gradlew\" || CMD=\"gradle\"; $CMD test --tests \"$fqc\"; else >&2 echo 'No build tool found'; exit 1; fi;", "use_new_terminal": false, "reveal": "always", "tags": ["java-test-class", "java-test-class-nested"], diff --git a/src/jdtls.rs b/src/jdtls.rs index 5bcb23a..aa7b221 100644 --- a/src/jdtls.rs +++ b/src/jdtls.rs @@ -6,7 +6,7 @@ use std::{ use sha1::{Digest, Sha1}; use zed_extension_api::{ - self as zed, DownloadedFileType, LanguageServerId, LanguageServerInstallationStatus, Os, + self as zed, Architecture, DownloadedFileType, LanguageServerId, LanguageServerInstallationStatus, Os, Worktree, current_platform, download_file, http_client::{HttpMethod, HttpRequest, fetch}, make_file_executable, @@ -425,12 +425,12 @@ fn get_sha1_hex(input: &str) -> String { } fn get_shared_config_path(jdtls_base_directory: &Path) -> PathBuf { - // Note: JDTLS also provides config_linux_arm and config_mac_arm (and others), - // but does not use them in their own launch script. It may be worth investigating if we should use them when appropriate. - let config_to_use = match current_platform().0 { - Os::Linux => "config_linux", - Os::Mac => "config_mac", - Os::Windows => "config_win", + let config_to_use = match current_platform() { + (Os::Mac, Architecture::Aarch64) => "config_mac_arm", + (Os::Mac, _) => "config_mac", + (Os::Linux, Architecture::Aarch64) => "config_linux_arm", + (Os::Linux, _) => "config_linux", + (Os::Windows, _) => "config_win", }; jdtls_base_directory.join(config_to_use) }