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:
parent
d883302b01
commit
35b2990d38
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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user