![JAR search and dependency download from the Maven repository](/logo.png)
com.github.houbie.mozilla.javascript.tools.shell.ShellLine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhino-mod Show documentation
Show all versions of rhino-mod Show documentation
Mozilla Rhino, repackaged in package com.github.houbie.mozilla
The newest version!
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package com.github.houbie.mozilla.javascript.tools.shell;
import java.io.InputStream;
import java.util.List;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationTargetException;
import com.github.houbie.mozilla.javascript.Kit;
import com.github.houbie.mozilla.javascript.Scriptable;
import com.github.houbie.mozilla.javascript.ScriptableObject;
import com.github.houbie.mozilla.javascript.Function;
/**
* Provides a specialized input stream for consoles to handle line
* editing, history and completion. Relies on the JLine library (see
* ).
*/
public class ShellLine {
public static InputStream getStream(Scriptable scope) {
// We don't want a compile-time dependency on the JLine jar, so use
// reflection to load and reference the JLine classes.
ClassLoader classLoader = ShellLine.class.getClassLoader();
if (classLoader == null) {
// If the attempt to get a class specific class loader above failed
// then fallback to the system class loader.
classLoader = ClassLoader.getSystemClassLoader();
}
if (classLoader == null) {
// If for some reason we still don't have a handle to a class
// loader then give up (avoid a NullPointerException).
return null;
}
Class> readerClass = Kit.classOrNull(classLoader, "jline.ConsoleReader");
if (readerClass == null)
return null;
try {
// ConsoleReader reader = new ConsoleReader();
Constructor> c = readerClass.getConstructor();
Object reader = c.newInstance();
// reader.setBellEnabled(false);
Method m = readerClass.getMethod("setBellEnabled", Boolean.TYPE);
m.invoke(reader, Boolean.FALSE);
// reader.addCompletor(new FlexibleCompletor(prefixes));
Class> completorClass = Kit.classOrNull(classLoader,
"jline.Completor");
m = readerClass.getMethod("addCompletor", completorClass);
Object completor = Proxy.newProxyInstance(classLoader,
new Class[] { completorClass },
new FlexibleCompletor(completorClass, scope));
m.invoke(reader, completor);
// return new ConsoleReaderInputStream(reader);
Class> inputStreamClass = Kit.classOrNull(classLoader,
"jline.ConsoleReaderInputStream");
c = inputStreamClass.getConstructor(readerClass);
return (InputStream) c.newInstance(reader);
} catch (NoSuchMethodException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
return null;
}
}
/**
* The completors provided with JLine are pretty uptight, they only
* complete on a line that it can fully recognize (only composed of
* completed strings). This one completes whatever came before.
*/
class FlexibleCompletor implements java.lang.reflect.InvocationHandler {
private Method completeMethod;
private Scriptable global;
FlexibleCompletor(Class> completorClass, Scriptable global)
throws NoSuchMethodException
{
this.global = global;
this.completeMethod = completorClass.getMethod("complete", String.class,
Integer.TYPE, List.class);
}
@SuppressWarnings({"unchecked"})
public Object invoke(Object proxy, Method method, Object[] args) {
if (method.equals(this.completeMethod)) {
int result = complete((String)args[0], ((Integer) args[1]).intValue(),
(List) args[2]);
return Integer.valueOf(result);
}
throw new NoSuchMethodError(method.toString());
}
public int complete(String buffer, int cursor, List candidates) {
// Starting from "cursor" at the end of the buffer, look backward
// and collect a list of identifiers separated by (possibly zero)
// dots. Then look up each identifier in turn until getting to the
// last, presumably incomplete fragment. Then enumerate all the
// properties of the last object and find any that have the
// fragment as a prefix and return those for autocompletion.
int m = cursor - 1;
while (m >= 0) {
char c = buffer.charAt(m);
if (!Character.isJavaIdentifierPart(c) && c != '.')
break;
m--;
}
String namesAndDots = buffer.substring(m+1, cursor);
String[] names = namesAndDots.split("\\.", -1);
Scriptable obj = this.global;
for (int i=0; i < names.length - 1; i++) {
Object val = obj.get(names[i], global);
if (val instanceof Scriptable)
obj = (Scriptable) val;
else {
return buffer.length(); // no matches
}
}
Object[] ids = (obj instanceof ScriptableObject)
? ((ScriptableObject)obj).getAllIds()
: obj.getIds();
String lastPart = names[names.length-1];
for (int i=0; i < ids.length; i++) {
if (!(ids[i] instanceof String))
continue;
String id = (String)ids[i];
if (id.startsWith(lastPart)) {
if (obj.get(id, obj) instanceof Function)
id += "(";
candidates.add(id);
}
}
return buffer.length() - lastPart.length();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy