8134562: jjs history object should have methods to save/load history to/from given file and also allow reexecution of commands by a call

Reviewed-by: hannesw, attila
This commit is contained in:
Athijegannathan Sundararajan 2015-08-27 14:35:06 +05:30
parent d883302b01
commit 35b2990d38
3 changed files with 106 additions and 23 deletions
nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs

@ -45,16 +45,16 @@ final class EditObject extends AbstractJSObject {
props = Collections.unmodifiableSet(s);
}
private final Console console;
private final Consumer<String> errorHandler;
private final Consumer<String> evaluator;
private final Console console;
private String editor;
EditObject(final Consumer<String> errorHandler, final Consumer<String> evaluator,
final Console console) {
EditObject(final Console console, final Consumer<String> errorHandler,
final Consumer<String> evaluator) {
this.console = console;
this.errorHandler = errorHandler;
this.evaluator = evaluator;
this.console = console;
}
@Override

@ -25,10 +25,15 @@
package jdk.nashorn.tools.jjs;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import jdk.internal.jline.console.history.FileHistory;
@ -36,6 +41,7 @@ import jdk.internal.jline.console.history.History;
import jdk.nashorn.api.scripting.AbstractJSObject;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.runtime.JSType;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
/*
@ -47,16 +53,51 @@ final class HistoryObject extends AbstractJSObject {
final HashSet<String> s = new HashSet<>();
s.add("clear");
s.add("forEach");
s.add("load");
s.add("print");
s.add("save");
s.add("size");
s.add("toString");
props = Collections.unmodifiableSet(s);
}
private final FileHistory hist;
private final PrintWriter err;
private final Consumer<String> evaluator;
HistoryObject(final FileHistory hist) {
HistoryObject(final FileHistory hist, final PrintWriter err,
final Consumer<String> evaluator) {
this.hist = hist;
this.err = err;
this.evaluator = evaluator;
}
@Override
public boolean isFunction() {
return true;
}
@Override
public Object call(final Object thiz, final Object... args) {
if (args.length > 0) {
int index = JSType.toInteger(args[0]);
if (index < 0) {
index += (hist.size() - 1);
} else {
index--;
}
if (index >= 0 && index < (hist.size() - 1)) {
final CharSequence src = hist.get(index);
hist.replace(src);
err.println(src);
evaluator.accept(src.toString());
} else {
hist.removeLast();
err.println("no history entry @ " + (index + 1));
}
}
return UNDEFINED;
}
@Override
@ -66,8 +107,12 @@ final class HistoryObject extends AbstractJSObject {
return (Runnable)hist::clear;
case "forEach":
return (Function<JSObject, Object>)this::iterate;
case "load":
return (Consumer<Object>)this::load;
case "print":
return (Runnable)this::print;
case "save":
return (Consumer<Object>)this::save;
case "size":
return hist.size();
case "toString":
@ -98,9 +143,32 @@ final class HistoryObject extends AbstractJSObject {
return props;
}
private void save(final Object obj) {
final File file = getFile(obj);
try (final PrintWriter pw = new PrintWriter(file)) {
for (History.Entry e : hist) {
pw.println(e.value());
}
} catch (final IOException exp) {
throw new RuntimeException(exp);
}
}
private void load(final Object obj) {
final File file = getFile(obj);
String item = null;
try (final BufferedReader r = new BufferedReader(new FileReader(file))) {
while ((item = r.readLine()) != null) {
hist.add(item);
}
} catch (final IOException exp) {
throw new RuntimeException(exp);
}
}
private void print() {
for (History.Entry e : hist) {
System.out.println(e.value());
System.out.printf("%3d %s\n", e.index() + 1, e.value());
}
}
@ -112,4 +180,17 @@ final class HistoryObject extends AbstractJSObject {
}
return UNDEFINED;
}
private static File getFile(final Object obj) {
File file = null;
if (obj instanceof String) {
file = new File((String)obj);
} else if (obj instanceof File) {
file = (File)obj;
} else {
throw typeError("not.a.file", JSType.toString(obj));
}
return file;
}
}

@ -33,6 +33,7 @@ import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.function.Consumer;
import jdk.internal.jline.console.completer.Completer;
import jdk.internal.jline.console.UserInterruptException;
import jdk.nashorn.api.scripting.NashornException;
@ -116,26 +117,27 @@ public final class Main extends Shell {
global.addShellBuiltins();
if (System.getSecurityManager() == null) {
final Consumer<String> evaluator = str -> {
// could be called from different thread (GUI), we need to handle Context set/reset
final Global _oldGlobal = Context.getGlobal();
final boolean _globalChanged = (oldGlobal != global);
if (_globalChanged) {
Context.setGlobal(global);
}
try {
evalImpl(context, global, str, err, env._dump_on_error);
} finally {
if (_globalChanged) {
Context.setGlobal(_oldGlobal);
}
}
};
// expose history object for reflecting on command line history
global.addOwnProperty("history", Property.NOT_ENUMERABLE, new HistoryObject(in.getHistory()));
global.addOwnProperty("history", Property.NOT_ENUMERABLE, new HistoryObject(in.getHistory(), err, evaluator));
// 'edit' command
global.addOwnProperty("edit", Property.NOT_ENUMERABLE, new EditObject(err::println,
str -> {
// could be called from different thread (GUI), we need to handle Context set/reset
final Global _oldGlobal = Context.getGlobal();
final boolean _globalChanged = (oldGlobal != global);
if (_globalChanged) {
Context.setGlobal(global);
}
try {
evalImpl(context, global, str, err, env._dump_on_error);
} finally {
if (_globalChanged) {
Context.setGlobal(_oldGlobal);
}
}
}, in));
global.addOwnProperty("edit", Property.NOT_ENUMERABLE, new EditObject(in, err::println, evaluator));
}
while (true) {