mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8190698: jjs tool of jdk.scripting.nashorn.shell module should not statically depend on java.desktop
Reviewed-by: jlaskey, hannesw
This commit is contained in:
parent
6510faa150
commit
10c8d3a9f1
6 changed files with 107 additions and 48 deletions
|
@ -25,7 +25,6 @@
|
|||
|
||||
package jdk.nashorn.tools.jjs;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -69,7 +68,7 @@ class Console implements AutoCloseable {
|
|||
});
|
||||
in.addCompleter(completer);
|
||||
Runtime.getRuntime().addShutdownHook(new Thread((Runnable)this::saveHistory));
|
||||
bind(DOCUMENTATION_SHORTCUT, (ActionListener)evt -> showDocumentation(docHelper));
|
||||
bind(DOCUMENTATION_SHORTCUT, (Runnable) ()->showDocumentation(docHelper));
|
||||
try {
|
||||
Signal.handle(new Signal("CONT"), new Handler() {
|
||||
@Override public void handle(Signal sig) {
|
||||
|
|
|
@ -117,7 +117,7 @@ final class EditObject extends AbstractJSObject {
|
|||
final SaveHandler saveHandler = new SaveHandler(initText);
|
||||
if (editor != null && !editor.isEmpty()) {
|
||||
ExternalEditor.edit(editor, errorHandler, initText, saveHandler, console);
|
||||
} else if (! Main.HEADLESS) {
|
||||
} else {
|
||||
try {
|
||||
ServiceLoader<BuildInEditorProvider> sl
|
||||
= ServiceLoader.load(BuildInEditorProvider.class);
|
||||
|
@ -136,8 +136,6 @@ final class EditObject extends AbstractJSObject {
|
|||
} catch (RuntimeException ex) {
|
||||
errorHandler.accept(Main.getMessage("jjs.err.cant.launch.editor"));
|
||||
}
|
||||
} else {
|
||||
errorHandler.accept(Main.getMessage("no.editor"));
|
||||
}
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@ package jdk.nashorn.tools.jjs;
|
|||
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
@ -65,7 +63,6 @@ public final class Main extends Shell {
|
|||
private static final String DOC_PROPERTY_NAME = "__doc__";
|
||||
|
||||
static final boolean DEBUG = Boolean.getBoolean("nashorn.jjs.debug");
|
||||
static final boolean HEADLESS = GraphicsEnvironment.isHeadless();
|
||||
|
||||
// file where history is persisted.
|
||||
private static final File HIST_FILE = new File(new File(System.getProperty("user.home")), ".jjs.history");
|
||||
|
@ -120,7 +117,49 @@ public final class Main extends Shell {
|
|||
final Global oldGlobal = Context.getGlobal();
|
||||
final boolean globalChanged = (oldGlobal != global);
|
||||
final PropertiesHelper propsHelper = new PropertiesHelper(context);
|
||||
final NashornCompleter completer = new NashornCompleter(context, global, this, propsHelper);
|
||||
|
||||
if (globalChanged) {
|
||||
Context.setGlobal(global);
|
||||
}
|
||||
|
||||
// Check if java.desktop module is available and we're running in non-headless mode.
|
||||
// We access AWT via script to avoid direct dependency on java.desktop module.
|
||||
final boolean isHeadless = (boolean) context.eval(global,
|
||||
"(function() { \n" +
|
||||
" var env = java.awt.GraphicsEnvironment; \n" +
|
||||
" return env && typeof env.isHeadless == 'function'? \n" +
|
||||
" env.isHeadless() : true; \n" +
|
||||
"})()",
|
||||
global, "<headless-check>");
|
||||
|
||||
// Function that shows a JFileChooser dialog and returns the file name chosen (if chosen).
|
||||
// We access swing from script to avoid direct dependency on java.desktop module.
|
||||
final ScriptFunction fileChooserFunc = isHeadless? null : (ScriptFunction) context.eval(global,
|
||||
"(function() { \n" +
|
||||
" var ExtensionFilter = javax.swing.filechooser.FileNameExtensionFilter; \n" +
|
||||
" var JFileChooser = javax.swing.JFileChooser; \n" +
|
||||
" function run() { \n" +
|
||||
" var chooser = new JFileChooser(); \n" +
|
||||
" chooser.fileFilter = new ExtensionFilter('JavaScript Files', 'js'); \n" +
|
||||
" var retVal = chooser.showOpenDialog(null); \n" +
|
||||
" return retVal == JFileChooser.APPROVE_OPTION ? \n" +
|
||||
" chooser.selectedFile.absolutePath : null; \n" +
|
||||
" }; \n" +
|
||||
" var fileChooserTask = new java.util.concurrent.FutureTask(run); \n" +
|
||||
" javax.swing.SwingUtilities.invokeLater(fileChooserTask); \n" +
|
||||
" return fileChooserTask.get(); \n" +
|
||||
"})",
|
||||
global, "<file-chooser>");
|
||||
|
||||
final NashornCompleter completer = new NashornCompleter(context, global, this, propsHelper, fileChooserFunc);
|
||||
|
||||
// Function that opens up the desktop browser application with the given URI.
|
||||
// We access AWT from script to avoid direct dependency on java.desktop module.
|
||||
final ScriptFunction browseFunc = isHeadless? null : (ScriptFunction) context.eval(global,
|
||||
"(function(uri) { \n" +
|
||||
" java.awt.Desktop.desktop.browse(uri); \n" +
|
||||
"})",
|
||||
global, "<browse>");
|
||||
|
||||
try (final Console in = new Console(System.in, System.out, HIST_FILE, completer,
|
||||
str -> {
|
||||
|
@ -128,14 +167,14 @@ public final class Main extends Shell {
|
|||
final Object res = context.eval(global, str, global, "<shell>");
|
||||
if (res != null && res != UNDEFINED) {
|
||||
// Special case Java types: show the javadoc for the class.
|
||||
if (NativeJava.isType(UNDEFINED, res)) {
|
||||
if (!isHeadless && NativeJava.isType(UNDEFINED, res)) {
|
||||
final String typeName = NativeJava.typeName(UNDEFINED, res).toString();
|
||||
final String url = typeName.replace('.', '/').replace('$', '.') + ".html";
|
||||
openBrowserForJavadoc(url);
|
||||
} else if (res instanceof NativeJavaPackage) {
|
||||
openBrowserForJavadoc(browseFunc, url);
|
||||
} else if (!isHeadless && res instanceof NativeJavaPackage) {
|
||||
final String pkgName = ((NativeJavaPackage)res).getName();
|
||||
final String url = pkgName.replace('.', '/') + "/package-summary.html";
|
||||
openBrowserForJavadoc(url);
|
||||
openBrowserForJavadoc(browseFunc, url);
|
||||
} else if (res instanceof ScriptObject) {
|
||||
final ScriptObject sobj = (ScriptObject)res;
|
||||
if (sobj.has(DOC_PROPERTY_NAME)) {
|
||||
|
@ -153,10 +192,6 @@ public final class Main extends Shell {
|
|||
return null;
|
||||
})) {
|
||||
|
||||
if (globalChanged) {
|
||||
Context.setGlobal(global);
|
||||
}
|
||||
|
||||
global.addShellBuiltins();
|
||||
|
||||
// redefine readLine to use jline Console's readLine!
|
||||
|
@ -282,11 +317,10 @@ public final class Main extends Shell {
|
|||
}
|
||||
|
||||
private static String JAVADOC_BASE = "https://docs.oracle.com/javase/9/docs/api/";
|
||||
|
||||
private static void openBrowserForJavadoc(String relativeUrl) {
|
||||
private static void openBrowserForJavadoc(ScriptFunction browse, String relativeUrl) {
|
||||
try {
|
||||
final URI uri = new URI(JAVADOC_BASE + relativeUrl);
|
||||
Desktop.getDesktop().browse(uri);
|
||||
ScriptRuntime.apply(browse, null, uri);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,12 +29,8 @@ import java.io.File;
|
|||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.SwingUtilities;
|
||||
import jdk.internal.jline.console.completer.Completer;
|
||||
import jdk.internal.jline.console.UserInterruptException;
|
||||
import jdk.nashorn.api.tree.AssignmentTree;
|
||||
|
@ -60,6 +56,7 @@ import jdk.nashorn.internal.objects.Global;
|
|||
import jdk.nashorn.internal.runtime.ECMAException;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ScriptEnvironment;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
|
||||
/**
|
||||
|
@ -72,16 +69,19 @@ final class NashornCompleter implements Completer {
|
|||
private final ScriptEnvironment env;
|
||||
private final PartialParser partialParser;
|
||||
private final PropertiesHelper propsHelper;
|
||||
private final ScriptFunction fileChooserFunc;
|
||||
private final Parser parser;
|
||||
private static final boolean BACKSLASH_FILE_SEPARATOR = File.separatorChar == '\\';
|
||||
|
||||
NashornCompleter(final Context context, final Global global,
|
||||
final PartialParser partialParser, final PropertiesHelper propsHelper) {
|
||||
final PartialParser partialParser, final PropertiesHelper propsHelper,
|
||||
final ScriptFunction fileChooserFunc) {
|
||||
this.context = context;
|
||||
this.global = global;
|
||||
this.env = context.getEnv();
|
||||
this.partialParser = partialParser;
|
||||
this.propsHelper = propsHelper;
|
||||
this.fileChooserFunc = fileChooserFunc;
|
||||
this.parser = createParser(env);
|
||||
}
|
||||
|
||||
|
@ -236,8 +236,9 @@ final class NashornCompleter implements Completer {
|
|||
|
||||
final ExpressionTree topExpr = getTopLevelExpression(parser, completeExpr);
|
||||
if (topExpr == null) {
|
||||
// special case for load call that looks like "load(" with optional whitespaces
|
||||
if (LOAD_CALL.matcher(test).matches()) {
|
||||
// Special case for load call that looks like "load(" with optional whitespaces.
|
||||
// If we have a fileChooserFunc then call it, so that the user can select a file.
|
||||
if (fileChooserFunc != null && LOAD_CALL.matcher(test).matches()) {
|
||||
String name = readFileName(context.getErr());
|
||||
if (name != null) {
|
||||
// handle '\' file separator
|
||||
|
@ -269,26 +270,11 @@ final class NashornCompleter implements Completer {
|
|||
// Internals only below this point
|
||||
|
||||
// read file name from the user using by showing a swing file chooser diablog
|
||||
private static String readFileName(final PrintWriter err) {
|
||||
// if running on AWT Headless mode, don't attempt swing dialog box!
|
||||
if (Main.HEADLESS) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final FutureTask<String> fileChooserTask = new FutureTask<String>(() -> {
|
||||
// show a file chooser dialog box
|
||||
final JFileChooser chooser = new JFileChooser();
|
||||
chooser.setFileFilter(new FileNameExtensionFilter("JavaScript Files", "js"));
|
||||
final int retVal = chooser.showOpenDialog(null);
|
||||
return retVal == JFileChooser.APPROVE_OPTION ?
|
||||
chooser.getSelectedFile().getAbsolutePath() : null;
|
||||
});
|
||||
|
||||
SwingUtilities.invokeLater(fileChooserTask);
|
||||
|
||||
private String readFileName(final PrintWriter err) {
|
||||
try {
|
||||
return fileChooserTask.get();
|
||||
} catch (final ExecutionException | InterruptedException e) {
|
||||
final Object res = ScriptRuntime.apply(fileChooserFunc, null);
|
||||
return res instanceof String? (String)res : null;
|
||||
} catch (final Exception e) {
|
||||
err.println(e);
|
||||
if (Main.DEBUG) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
*/
|
||||
module jdk.scripting.nashorn.shell {
|
||||
requires java.compiler;
|
||||
requires java.desktop;
|
||||
requires jdk.internal.le;
|
||||
requires jdk.scripting.nashorn;
|
||||
requires jdk.internal.ed;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue