Skip to content

Commit

Permalink
Allow setting JDK path via a java.home JSON setting.
Browse files Browse the repository at this point in the history
Update the documentation.
  • Loading branch information
brown committed Jan 21, 2023
1 parent 4911c80 commit e803ded
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 31 deletions.
42 changes: 32 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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`
Expand Down
24 changes: 16 additions & 8 deletions src/main/java/org/javacs/Docs.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path> docPath) {
var srcZipPath = srcZip();
Docs(Set<Path> docPath, Path javaHome) {
var srcZipPath = srcZip(javaHome);
// Path to source .jars + src.zip
var sourcePath = new ArrayList<Path>(docPath);
if (srcZipPath != NOT_FOUND) {
Expand All @@ -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;
Expand All @@ -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;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/javacs/JavaCompilerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path> classPath, Set<Path> docPath, Set<String> addExports) {
JavaCompilerService(Set<Path> classPath, Set<Path> docPath, Set<String> addExports, Path javaHome) {
System.err.println("Class path:");
for (var p : classPath) {
System.err.println(" " + p);
Expand All @@ -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();
}
Expand Down
31 changes: 20 additions & 11 deletions src/main/java/org/javacs/JavaLanguageServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> externalDependencies() {
Expand Down Expand Up @@ -142,6 +143,7 @@ private Set<Path> docPath() {
}
return paths;
}

private Set<String> addExports() {
if (!settings.has("addExports")) return Set.of();
var array = settings.getAsJsonArray("addExports");
Expand All @@ -152,6 +154,13 @@ private Set<String> 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);
Expand Down

0 comments on commit e803ded

Please sign in to comment.