mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8190795: jjs should show javadoc for java methods on shift-tab
Reviewed-by: hannesw, jlaskey
This commit is contained in:
parent
7a77a63845
commit
2060b8fc57
4 changed files with 186 additions and 34 deletions
|
@ -393,6 +393,10 @@ jdk.jartool_ADD_JAVAC_FLAGS += -XDstringConcat=inline
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
jdk.scripting.nashorn.shell_COPY += .js .properties
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
jdk.rmic_SETUP := GENERATE_JDKBYTECODE_NOWARNINGS
|
jdk.rmic_SETUP := GENERATE_JDKBYTECODE_NOWARNINGS
|
||||||
jdk.rmic_CLEAN += .properties
|
jdk.rmic_CLEAN += .properties
|
||||||
|
|
||||||
|
|
|
@ -227,6 +227,9 @@
|
||||||
</copy>
|
</copy>
|
||||||
<copy file="${dynalink.module.src.dir}/jdk/dynalink/support/messages.properties" todir="${dynalink.module.classes.dir}/jdk/dynalink/support"/>
|
<copy file="${dynalink.module.src.dir}/jdk/dynalink/support/messages.properties" todir="${dynalink.module.classes.dir}/jdk/dynalink/support"/>
|
||||||
<copy file="${nashorn.module.src.dir}/jdk/nashorn/internal/codegen/anchor.properties" todir="${nashorn.module.classes.dir}/jdk/nashorn/internal/codegen"/>
|
<copy file="${nashorn.module.src.dir}/jdk/nashorn/internal/codegen/anchor.properties" todir="${nashorn.module.classes.dir}/jdk/nashorn/internal/codegen"/>
|
||||||
|
<copy todir="${nashorn.shell.module.classes.dir}/jdk/nashorn/tools/jjs/resources">
|
||||||
|
<fileset dir="${nashorn.shell.module.src.dir}/jdk/nashorn/tools/jjs/resources/"/>
|
||||||
|
</copy>
|
||||||
|
|
||||||
<echo message="version_string=${nashorn.fullversion}" file="${nashorn.module.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties"/>
|
<echo message="version_string=${nashorn.fullversion}" file="${nashorn.module.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties"/>
|
||||||
<echo file="${nashorn.module.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties" append="true">${line.separator}</echo>
|
<echo file="${nashorn.module.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties" append="true">${line.separator}</echo>
|
||||||
|
|
|
@ -36,6 +36,8 @@ import java.io.UncheckedIOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
@ -52,6 +54,7 @@ import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||||
import jdk.nashorn.internal.runtime.ScriptingFunctions;
|
import jdk.nashorn.internal.runtime.ScriptingFunctions;
|
||||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||||
|
import jdk.nashorn.internal.runtime.Source;
|
||||||
import jdk.nashorn.tools.Shell;
|
import jdk.nashorn.tools.Shell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,44 +125,18 @@ public final class Main extends Shell {
|
||||||
Context.setGlobal(global);
|
Context.setGlobal(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if java.desktop module is available and we're running in non-headless mode.
|
// jjs.js is read and evaluated. The result of the evaluation is an "exports" object. This is done
|
||||||
// We access AWT via script to avoid direct dependency on java.desktop module.
|
// to avoid polluting javascript global scope. These are internal funtions are retrieved from the
|
||||||
final boolean isHeadless = (boolean) context.eval(global,
|
// 'exports' object and used from here.
|
||||||
"(function() { \n" +
|
final ScriptObject jjsObj = (ScriptObject)context.eval(global, readJJSScript(), global, "<jjs.js>");
|
||||||
" 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).
|
final boolean isHeadless = (boolean) ScriptRuntime.apply((ScriptFunction) jjsObj.get("isHeadless"), null);
|
||||||
// We access swing from script to avoid direct dependency on java.desktop module.
|
final ScriptFunction fileChooserFunc = isHeadless? null : (ScriptFunction) jjsObj.get("chooseFile");
|
||||||
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);
|
final NashornCompleter completer = new NashornCompleter(context, global, this, propsHelper, fileChooserFunc);
|
||||||
|
final ScriptFunction browseFunc = isHeadless? null : (ScriptFunction) jjsObj.get("browse");
|
||||||
|
|
||||||
// Function that opens up the desktop browser application with the given URI.
|
final ScriptFunction javadoc = (ScriptFunction) jjsObj.get("javadoc");
|
||||||
// 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,
|
try (final Console in = new Console(System.in, System.out, HIST_FILE, completer,
|
||||||
str -> {
|
str -> {
|
||||||
|
@ -175,6 +152,9 @@ public final class Main extends Shell {
|
||||||
final String pkgName = ((NativeJavaPackage)res).getName();
|
final String pkgName = ((NativeJavaPackage)res).getName();
|
||||||
final String url = pkgName.replace('.', '/') + "/package-summary.html";
|
final String url = pkgName.replace('.', '/') + "/package-summary.html";
|
||||||
openBrowserForJavadoc(browseFunc, url);
|
openBrowserForJavadoc(browseFunc, url);
|
||||||
|
} else if (NativeJava.isJavaMethod(UNDEFINED, res)) {
|
||||||
|
ScriptRuntime.apply(javadoc, UNDEFINED, res);
|
||||||
|
return ""; // javadoc function already prints javadoc
|
||||||
} else if (res instanceof ScriptObject) {
|
} else if (res instanceof ScriptObject) {
|
||||||
final ScriptObject sobj = (ScriptObject)res;
|
final ScriptObject sobj = (ScriptObject)res;
|
||||||
if (sobj.has(DOC_PROPERTY_NAME)) {
|
if (sobj.has(DOC_PROPERTY_NAME)) {
|
||||||
|
@ -324,4 +304,22 @@ public final class Main extends Shell {
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String readJJSScript() {
|
||||||
|
return AccessController.doPrivileged(
|
||||||
|
new PrivilegedAction<String>() {
|
||||||
|
@Override
|
||||||
|
public String run() {
|
||||||
|
try {
|
||||||
|
final InputStream resStream = Main.class.getResourceAsStream("resources/jjs.js");
|
||||||
|
if (resStream == null) {
|
||||||
|
throw new RuntimeException("resources/jjs.js is missing!");
|
||||||
|
}
|
||||||
|
return new String(Source.readFully(resStream));
|
||||||
|
} catch (final IOException exp) {
|
||||||
|
throw new RuntimeException(exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
function isHeadless() {
|
||||||
|
var GraphicsEnvironment = java.awt.GraphicsEnvironment;
|
||||||
|
return Java.isType(GraphicsEnvironment)? GraphicsEnvironment.isHeadless() : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
function chooseFile() {
|
||||||
|
var JFileChooser = javax.swing.JFileChooser;
|
||||||
|
if (!Java.isType(JFileChooser)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ExtensionFilter = javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
|
function run() {
|
||||||
|
var chooser = new JFileChooser();
|
||||||
|
chooser.fileFilter = new ExtensionFilter('JavaScript Files', 'js');
|
||||||
|
var retVal = chooser.showOpenDialog(null);
|
||||||
|
return retVal == JFileChooser.APPROVE_OPTION ?
|
||||||
|
chooser.selectedFile.absolutePath : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var FutureTask = java.util.concurrent.FutureTask;
|
||||||
|
var fileChooserTask = new FutureTask(run);
|
||||||
|
javax.swing.SwingUtilities.invokeLater(fileChooserTask);
|
||||||
|
|
||||||
|
return fileChooserTask.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
function browse(uri) {
|
||||||
|
var Desktop = java.awt.Desktop;
|
||||||
|
if (Java.isType(Desktop)) {
|
||||||
|
Desktop.desktop.browse(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function printDoc(list) {
|
||||||
|
list.forEach(function(doc) {
|
||||||
|
print();
|
||||||
|
print(doc.signature());
|
||||||
|
print();
|
||||||
|
print(doc.javadoc());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var JShell = null;
|
||||||
|
var jshell = null;
|
||||||
|
|
||||||
|
function javadoc(obj) {
|
||||||
|
var str = String(obj);
|
||||||
|
if (!JShell) {
|
||||||
|
// first time - resolve JShell class
|
||||||
|
JShell = Packages.jdk.jshell.JShell;
|
||||||
|
// if JShell class is available, create an instance
|
||||||
|
jshell = Java.isType(JShell)? JShell.create() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jshell) {
|
||||||
|
// we don't have jshell. Just print the default!
|
||||||
|
return print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A java method object's String representation looks something like this:
|
||||||
|
*
|
||||||
|
* For an overloaded method:
|
||||||
|
*
|
||||||
|
* [jdk.dynalink.beans.OverloadedDynamicMethod
|
||||||
|
* String java.lang.System.getProperty(String,String)
|
||||||
|
* String java.lang.System.getProperty(String)
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* For a non-overloaded method:
|
||||||
|
*
|
||||||
|
* [jdk.dynalink.beans.SimpleDynamicMethod void java.lang.System.exit(int)]
|
||||||
|
*
|
||||||
|
* jshell expects "java.lang.System.getProperty(" or "java.lang.System.exit("
|
||||||
|
* to retrieve the javadoc comment(s) for the method.
|
||||||
|
*/
|
||||||
|
var javaCode = str.split(" ")[2]; // stuff after second whitespace char
|
||||||
|
javaCode = javaCode.substring(0, javaCode.indexOf('(') + 1); // strip argument types
|
||||||
|
|
||||||
|
try {
|
||||||
|
var analysis = jshell.sourceCodeAnalysis();
|
||||||
|
var docList = analysis.documentation(javaCode, javaCode.length, true);
|
||||||
|
if (!docList.isEmpty()) {
|
||||||
|
return printDoc(docList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* May be the method is a Java instance method. In such a case, jshell expects
|
||||||
|
* a valid starting portion of an instance method call expression. We cast null
|
||||||
|
* to Java object and call method on it. i.e., We pass something like this:
|
||||||
|
*
|
||||||
|
* "((java.io.PrintStream)null).println("
|
||||||
|
*/
|
||||||
|
var javaType = javaCode.substring(0, javaCode.lastIndexOf('.'));
|
||||||
|
javaCode = "((" + javaType + ")null)" + javaCode.substring(javaCode.lastIndexOf('.'));
|
||||||
|
docList = analysis.documentation(javaCode, javaCode.length, true);
|
||||||
|
if (!docList.isEmpty()) {
|
||||||
|
return printDoc(docList);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isHeadless: isHeadless,
|
||||||
|
chooseFile: chooseFile,
|
||||||
|
browse: browse,
|
||||||
|
javadoc: javadoc
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
Loading…
Add table
Add a link
Reference in a new issue