jline.ClassNameCompletor Maven / Gradle / Ivy
/*
* Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
*
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*/
package jline;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* A Completor implementation that completes java class names. By default,
* it scans the java class path to locate all the classes.
*
* @author Marc Prud'hommeaux
*/
public class ClassNameCompletor extends SimpleCompletor {
/**
* Complete candidates using all the classes available in the
* java CLASSPATH.
*/
public ClassNameCompletor() throws IOException {
this(null);
}
public ClassNameCompletor(final SimpleCompletorFilter filter)
throws IOException {
super(getClassNames(), filter);
setDelimiter(".");
}
public static String[] getClassNames() throws IOException {
Set urls = new HashSet();
for (ClassLoader loader = ClassNameCompletor.class
.getClassLoader(); loader != null;
loader = loader.getParent()) {
if (!(loader instanceof URLClassLoader)) {
continue;
}
urls.addAll(Arrays.asList(((URLClassLoader) loader).getURLs()));
}
// Now add the URL that holds java.lang.String. This is because
// some JVMs do not report the core classes jar in the list of
// class loaders.
Class[] systemClasses = new Class[] {
String.class, javax.swing.JFrame.class
};
for (int i = 0; i < systemClasses.length; i++) {
URL classURL = systemClasses[i].getResource("/"
+ systemClasses[i].getName() .replace('.', '/') + ".class");
if (classURL != null) {
URLConnection uc = (URLConnection) classURL.openConnection();
if (uc instanceof JarURLConnection) {
urls.add(((JarURLConnection) uc).getJarFileURL());
}
}
}
Set classes = new HashSet();
for (Iterator i = urls.iterator(); i.hasNext();) {
URL url = (URL) i.next();
File file = new File(url.getFile());
if (file.isDirectory()) {
Set files = getClassFiles(file.getAbsolutePath(),
new HashSet(), file, new int[] { 200 });
classes.addAll(files);
continue;
}
if ((file == null) || !file.isFile()) // TODO: handle directories
{
continue;
}
JarFile jf = new JarFile(file);
for (Enumeration e = jf.entries(); e.hasMoreElements();) {
JarEntry entry = (JarEntry) e.nextElement();
if (entry == null) {
continue;
}
String name = entry.getName();
if (!name.endsWith(".class")) // only use class files
{
continue;
}
classes.add(name);
}
}
// now filter classes by changing "/" to "." and trimming the
// trailing ".class"
Set classNames = new TreeSet();
for (Iterator i = classes.iterator(); i.hasNext();) {
String name = (String) i.next();
classNames.add(name.replace('/', '.').
substring(0, name.length() - 6));
}
return (String[]) classNames.toArray(new String[classNames.size()]);
}
private static Set getClassFiles(String root, Set holder, File directory,
int[] maxDirectories) {
// we have passed the maximum number of directories to scan
if (maxDirectories[0]-- < 0) {
return holder;
}
File[] files = directory.listFiles();
for (int i = 0; (files != null) && (i < files.length); i++) {
String name = files[i].getAbsolutePath();
if (!(name.startsWith(root))) {
continue;
} else if (files[i].isDirectory()) {
getClassFiles(root, holder, files[i], maxDirectories);
} else if (files[i].getName().endsWith(".class")) {
holder.add(files[i].getAbsolutePath().
substring(root.length() + 1));
}
}
return holder;
}
}