diff --git a/.gitignore b/.gitignore
index e54b558..1802d1e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
build
.gradle
out/
+.idea
diff --git a/RSTALanguageSupport/src/main/java/org/fife/rsta/ac/java/buildpath/Jdk9LibraryInfo.java b/RSTALanguageSupport/src/main/java/org/fife/rsta/ac/java/buildpath/Jdk9LibraryInfo.java
new file mode 100644
index 0000000..74e3455
--- /dev/null
+++ b/RSTALanguageSupport/src/main/java/org/fife/rsta/ac/java/buildpath/Jdk9LibraryInfo.java
@@ -0,0 +1,232 @@
+/*
+ * 04/21/2012
+ *
+ * Copyright (C) 2010 Robert Futrell
+ * robert_futrell at users.sourceforge.net
+ * http://fifesoft.com/rsyntaxtextarea
+ *
+ * This library is distributed under a modified BSD license. See the included
+ * RSTALanguageSupport.License.txt file for details.
+ */
+package org.fife.rsta.ac.java.buildpath;
+
+import org.fife.rsta.ac.java.PackageMapNode;
+import org.fife.rsta.ac.java.classreader.ClassFile;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+
+/**
+ * Information about the JDK 9+ runtime classes to add to the "build path".
+ *
+ * Note: this introspects the modules delivered as prt of the JDJ, in jmods.
+ * A more complete implementation could look into the ct.sym file and rely on
+ * a JDK version to find the proper signatures:
+ * https://www.morling.dev/blog/the-anatomy-of-ct-sym-how-javac-ensures-backwards-compatibility/
+ *
+ *
+ * @author Robert Futrell
+ * @author Philippe Riand
+ * @version 1.0
+ * @see DirLibraryInfo
+ * @see ClasspathLibraryInfo
+ * @see JarLibraryInfo
+ */
+public class Jdk9LibraryInfo extends LibraryInfo {
+
+ private File[] jmodFiles;
+ private JarFile[] bulkCreateJmods;
+
+ public Jdk9LibraryInfo(File[] jmodFiles) {
+ this(jmodFiles, null);
+ }
+
+
+ public Jdk9LibraryInfo(File[] jmodFiles, SourceLocation sourceLoc) {
+ setJmodFiles(jmodFiles);
+ setSourceLocation(sourceLoc);
+ }
+
+
+ @Override
+ public void bulkClassFileCreationEnd() {
+ for( JarFile bulkCreateJar: bulkCreateJmods) {
+ try {
+ bulkCreateJar.close();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+ bulkCreateJmods = null;
+ }
+
+
+ @Override
+ public void bulkClassFileCreationStart() {
+ bulkCreateJmods = new JarFile[jmodFiles.length];
+ for(int i = 0; i< jmodFiles.length; i++) {
+ File jarFile = jmodFiles[i];
+ try {
+ bulkCreateJmods[i] = new JarFile(jarFile);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+ }
+
+
+ /**
+ * Compares this LibraryInfo
to another one. Two instances of
+ * this class are only considered equal if they represent the same class
+ * file location. Source attachment is irrelevant.
+ *
+ * @return The sort order of these two library infos.
+ */
+ @Override
+ public int compareTo(LibraryInfo info) {
+ if (info==this) {
+ return 0;
+ }
+ int result = -1;
+ if (info instanceof Jdk9LibraryInfo) {
+ // Only compare the object refs
+ result = this==info ? 0 : -1;
+ }
+ return result;
+ }
+
+
+ @Override
+ public ClassFile createClassFile(String entryName) throws IOException {
+ for(File jarFile: jmodFiles) {
+ try (JarFile jar = new JarFile(jarFile)) {
+ ClassFile c = createClassFileImpl(jar, entryName);
+ if(c!=null) {
+ return c;
+ }
+ }
+ }
+ System.err.println("ERROR: Invalid entry: " + entryName);
+ return null;
+ }
+
+
+ @Override
+ public ClassFile createClassFileBulk(String entryName) throws IOException {
+ for( JarFile bulkCreateJar: bulkCreateJmods) {
+ ClassFile c = createClassFileImpl(bulkCreateJar, entryName);
+ if(c!=null) {
+ return c;
+ }
+ }
+ System.err.println("ERROR: Invalid entry: " + entryName);
+ return null;
+ }
+
+
+ private static ClassFile createClassFileImpl(JarFile jar,
+ String entryName) throws IOException {
+ JarEntry entry = (JarEntry)jar.getEntry("classes/"+entryName);
+ if (entry==null) {
+ return null;
+ }
+ DataInputStream in = new DataInputStream(
+ new BufferedInputStream(jar.getInputStream(entry)));
+ ClassFile cf;
+ try {
+ cf = new ClassFile(in);
+ } finally {
+ in.close();
+ }
+ return cf;
+ }
+
+
+ @Override
+ public PackageMapNode createPackageMap() throws IOException {
+ PackageMapNode root = new PackageMapNode();
+
+ for( File jarFile: jmodFiles) {
+ try (JarFile jar = new JarFile(jarFile)) {
+
+ Enumeration e = jar.entries();
+ while (e.hasMoreElements()) {
+ ZipEntry entry = e.nextElement();
+ String entryName = entry.getName();
+ if(entryName.startsWith("classes/")) {
+ entryName = entryName.substring(8);
+ if (entryName.endsWith(".class")) {
+ root.add(entryName);
+ }
+ }
+ }
+
+ }
+ }
+
+ return root;
+
+ }
+
+
+ @Override
+ public long getLastModified() {
+ return 0; //jarFile.lastModified();
+ }
+
+
+ @Override
+ public String getLocationAsString() {
+ return ""; //jarFile.getAbsolutePath();
+ }
+
+
+ @Override
+ public int hashCodeImpl() {
+ int h = 0;
+ for( File jarFile: jmodFiles) {
+ h += jarFile.hashCode();
+ }
+ return h;
+ }
+
+
+ /**
+ * Sets the jar file location.
+ *
+ * @param jmodFiles The jar files location. This cannot be null
.
+ */
+ private void setJmodFiles(File[] jmodFiles) {
+ for( File jarFile: jmodFiles) {
+ if (jarFile==null || !jarFile.exists()) {
+ String name = jarFile==null ? "null" : jarFile.getAbsolutePath();
+ throw new IllegalArgumentException("Jar does not exist: " + name);
+ }
+ }
+ this.jmodFiles = jmodFiles;
+ }
+
+
+ /**
+ * Returns a string representation of this jar information. Useful for
+ * debugging.
+ *
+ * @return A string representation of this object.
+ */
+ @Override
+ public String toString() {
+ return "[JarLibraryInfo: " +
+ "jars=" + jmodFiles.toString() +
+ "; source=" + getSourceLocation() +
+ "]";
+ }
+
+
+}
diff --git a/RSTALanguageSupport/src/main/java/org/fife/rsta/ac/java/buildpath/LibraryInfo.java b/RSTALanguageSupport/src/main/java/org/fife/rsta/ac/java/buildpath/LibraryInfo.java
index 5a6130d..8698ecb 100644
--- a/RSTALanguageSupport/src/main/java/org/fife/rsta/ac/java/buildpath/LibraryInfo.java
+++ b/RSTALanguageSupport/src/main/java/org/fife/rsta/ac/java/buildpath/LibraryInfo.java
@@ -11,6 +11,7 @@
package org.fife.rsta.ac.java.buildpath;
import java.io.File;
+import java.io.FileFilter;
import java.io.IOException;
import org.fife.rsta.ac.java.JarManager;
@@ -171,6 +172,28 @@ public boolean equals(Object o) {
* @see #getMainJreJarInfo()
*/
public static LibraryInfo getJreJarInfo(File jreHome) {
+ // Check if the Jre is made of modules
+ File mods = new File(jreHome,"jmods");
+ if(mods.isDirectory()) {
+ File[] files = mods.listFiles( new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ if(pathname.isFile()) {
+ String name = pathname.getName();
+ return name.endsWith(".jmod") && (name.startsWith("java.") || name.startsWith("jdk."));
+ }
+ return false;
+ }
+ });
+
+ LibraryInfo info = new Jdk9LibraryInfo(files);
+ File sourceZip = new File(jreHome,"lib"+File.separator+"src.zip");
+ if (sourceZip.isFile()) { // Make sure our last guess actually exists
+ info.setSourceLocation(new ZipSourceLocation(sourceZip));
+ }
+
+ return info;
+ }
LibraryInfo info = null;