From 7f92e45cd83ca5f02e5a25a3fbb8d04c1a834941 Mon Sep 17 00:00:00 2001 From: Robert Brown Date: Thu, 19 Jan 2023 21:25:41 -0500 Subject: [PATCH] Allow setting JDK path via a java.home JSON setting. Update the documentation. --- README.md | 42 ++++++++++++++----- src/main/java/org/javacs/Docs.java | 24 +++++++---- .../java/org/javacs/JavaCompilerService.java | 4 +- .../java/org/javacs/JavaLanguageServer.java | 31 +++++++++----- .../org/javacs/JavaCompilerServiceTest.java | 3 +- 5 files changed, 72 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index c2aff2d6..c651e605 100644 --- a/README.md +++ b/README.md @@ -125,26 +125,37 @@ Note: This tool is not compatible with [vim-lsp](https://github.com/prabirshrest ## Usage -The language server will provide autocomplete and other features using: -* .java files anywhere in your workspace +The language server provides autocomplete and other features using: +* Java source files anywhere in your workspace * Java platform classes -* External dependencies specified using `pom.xml`, Bazel, or [settings](#Settings) +* External dependencies specified using `pom.xml`, Bazel, or via explicit [settings](#Settings) ## Settings -If the language server doesn't detect your external dependencies automatically, you can specify them using [.vscode/settings.json](https://code.visualstudio.com/docs/getstarted/settings) +Generally, the language server infers the location of the JDK and external +dependency jar files. If this process does not work correctly, you can specify +them explicitly +using [.vscode/settings.json](https://code.visualstudio.com/docs/getstarted/settings). + +### Location of the JDK + +The location of the JDK is determined by reading the JAVA_HOME environment +variable. If JAVA_HOME is unset, then the language server searches operating +system specific locations for a JDK. The JDK location can be explicitly set +with: ```json { - "java.externalDependencies": [ - "junit:junit:jar:4.12:test", // Maven format - "junit:junit:4.12" // Gradle-style format is also allowed - ] + "java.home": "/file/path/of/the/jdk" } ``` -If all else fails, you can specify the Java class path and the locations of -source jars manually: +### External dependency jar files + +By default the language server infers the Java classpath and finds source code +jars for external dependencies by running Maven or Bazel. The inference +process can be diabled by explicitly specifying classpath. Both paths may be +set explicitly with: ```json { @@ -157,6 +168,17 @@ source jars manually: } ``` +External dependencies can also be specified in Maven or Gradle format with: + +```json +{ + "java.externalDependencies": [ + "junit:junit:jar:4.12:test", // Maven format + "junit:junit:4.12" // Gradle-style format is also allowed + ] +} +``` + You can generate a list of external dependencies using your build tool: * Maven: `mvn dependency:list` * Gradle: `gradle dependencies` diff --git a/src/main/java/org/javacs/Docs.java b/src/main/java/org/javacs/Docs.java index 43c5ed79..f63baf57 100644 --- a/src/main/java/org/javacs/Docs.java +++ b/src/main/java/org/javacs/Docs.java @@ -14,8 +14,8 @@ public class Docs { /** File manager with source-path + platform sources, which we will use to look up individual source files */ final SourceFileManager fileManager = new SourceFileManager(); - Docs(Set docPath) { - var srcZipPath = srcZip(); + Docs(Set docPath, Path javaHome) { + var srcZipPath = srcZip(javaHome); // Path to source .jars + src.zip var sourcePath = new ArrayList(docPath); if (srcZipPath != NOT_FOUND) { @@ -31,12 +31,12 @@ public class Docs { } } - private static final Path NOT_FOUND = Paths.get(""); + static final Path NOT_FOUND = Paths.get(""); private static Path cacheSrcZip; - private static Path srcZip() { + private static Path srcZip(Path javaHome) { if (cacheSrcZip == null) { - cacheSrcZip = findSrcZip(); + cacheSrcZip = findSrcZip(javaHome); } if (cacheSrcZip == NOT_FOUND) { return NOT_FOUND; @@ -49,15 +49,23 @@ private static Path srcZip() { } } - private static Path findSrcZip() { - var javaHome = JavaHomeHelper.javaHome(); + private static Path findSrcZip(Path javaHome) { + if (javaHome == NOT_FOUND) { + javaHome = JavaHomeHelper.javaHome(); + } + + if (javaHome == NOT_FOUND) { + LOG.warning("Couldn't find Java home."); + return NOT_FOUND; + } + String[] locations = { "lib/src.zip", "src.zip", }; for (var rel : locations) { var abs = javaHome.resolve(rel); if (Files.exists(abs)) { - LOG.info("Found " + abs); + LOG.info("Found src.zip " + abs); return abs; } } diff --git a/src/main/java/org/javacs/JavaCompilerService.java b/src/main/java/org/javacs/JavaCompilerService.java index cfe72783..d726e4be 100644 --- a/src/main/java/org/javacs/JavaCompilerService.java +++ b/src/main/java/org/javacs/JavaCompilerService.java @@ -21,7 +21,7 @@ class JavaCompilerService implements CompilerProvider { // TODO intercept files that aren't in the batch and erase method bodies so compilation is faster final SourceFileManager fileManager; - JavaCompilerService(Set classPath, Set docPath, Set addExports) { + JavaCompilerService(Set classPath, Set docPath, Set addExports, Path javaHome) { System.err.println("Class path:"); for (var p : classPath) { System.err.println(" " + p); @@ -34,7 +34,7 @@ class JavaCompilerService implements CompilerProvider { this.classPath = Collections.unmodifiableSet(classPath); this.docPath = Collections.unmodifiableSet(docPath); this.addExports = Collections.unmodifiableSet(addExports); - this.docs = new Docs(docPath); + this.docs = new Docs(docPath, javaHome); this.classPathClasses = ScanClassPath.classPathTopLevelClasses(classPath); this.fileManager = new SourceFileManager(); } diff --git a/src/main/java/org/javacs/JavaLanguageServer.java b/src/main/java/org/javacs/JavaLanguageServer.java index aa96ebd0..e8b6e016 100644 --- a/src/main/java/org/javacs/JavaLanguageServer.java +++ b/src/main/java/org/javacs/JavaLanguageServer.java @@ -93,24 +93,25 @@ private JavaCompilerService createCompiler() { var externalDependencies = externalDependencies(); var classPath = classPath(); var addExports = addExports(); + var javaHome = javaHome(); + // If classpath is specified by the user, don't infer anything if (!classPath.isEmpty()) { javaEndProgress(); - return new JavaCompilerService(classPath, docPath(), addExports); + return new JavaCompilerService(classPath, docPath(), addExports, javaHome); } - // Otherwise, combine inference with user-specified external dependencies - else { - var infer = new InferConfig(workspaceRoot, externalDependencies); - javaReportProgress(new JavaReportProgressParams("Inferring class path")); - classPath = infer.classPath(); + // Otherwise, combine inference with user-specified external dependencies. + var infer = new InferConfig(workspaceRoot, externalDependencies); - javaReportProgress(new JavaReportProgressParams("Inferring doc path")); - var docPath = infer.buildDocPath(); + javaReportProgress(new JavaReportProgressParams("Inferring class path")); + classPath = infer.classPath(); - javaEndProgress(); - return new JavaCompilerService(classPath, docPath, addExports); - } + javaReportProgress(new JavaReportProgressParams("Inferring doc path")); + var docPath = infer.buildDocPath(); + + javaEndProgress(); + return new JavaCompilerService(classPath, docPath, addExports, javaHome); } private Set externalDependencies() { @@ -142,6 +143,7 @@ private Set docPath() { } return paths; } + private Set addExports() { if (!settings.has("addExports")) return Set.of(); var array = settings.getAsJsonArray("addExports"); @@ -152,6 +154,13 @@ private Set addExports() { return strings; } + private Path javaHome() { + if (settings.has("home")) { + return Paths.get(settings.get("home").getAsString()); + } + return Docs.NOT_FOUND; + } + @Override public InitializeResult initialize(InitializeParams params) { this.workspaceRoot = Paths.get(params.rootUri); diff --git a/src/test/java/org/javacs/JavaCompilerServiceTest.java b/src/test/java/org/javacs/JavaCompilerServiceTest.java index 8b6cfbd9..9a2a998b 100644 --- a/src/test/java/org/javacs/JavaCompilerServiceTest.java +++ b/src/test/java/org/javacs/JavaCompilerServiceTest.java @@ -13,7 +13,8 @@ public class JavaCompilerServiceTest { } private JavaCompilerService compiler = - new JavaCompilerService(Collections.emptySet(), Collections.emptySet(), Collections.emptySet()); + new JavaCompilerService( + Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Docs.NOT_FOUND); static Path simpleProjectSrc() { return Paths.get("src/test/examples/simple-project").normalize();