You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/03/14 18:45:41 UTC

[groovy] branch GROOVY-9468 updated (c1b4008 -> 3b406c0)

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a change to branch GROOVY-9468
in repository https://gitbox.apache.org/repos/asf/groovy.git.


 discard c1b4008  GROOVY-9468: Support running as Java code in the Groovy console
     new 3b406c0  GROOVY-9468: Support running as Java code in the Groovy console

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (c1b4008)
            \
             N -- N -- N   refs/heads/GROOVY-9468 (3b406c0)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/org/apache/groovy/util/JavaShell.java     |  5 ++--
 .../main/groovy/groovy/console/ui/Console.groovy   | 29 ++++++++++++++--------
 2 files changed, 22 insertions(+), 12 deletions(-)


[groovy] 01/01: GROOVY-9468: Support running as Java code in the Groovy console

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY-9468
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 3b406c00d4fe14e8f018a548544aa89000c322d8
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Mar 15 02:45:24 2020 +0800

    GROOVY-9468: Support running as Java code in the Groovy console
---
 .../java/org/apache/groovy/util/JavaShell.java     |  5 +-
 subprojects/groovy-console/build.gradle            |  1 +
 .../main/groovy/groovy/console/ui/Console.groovy   | 86 +++++++++++++++++++---
 .../groovy/groovy/console/ui/ConsoleActions.groovy | 13 ++++
 .../groovy/console/ui/view/BasicMenuBar.groovy     |  2 +
 .../groovy/console/ui/view/MacOSXMenuBar.groovy    |  2 +
 6 files changed, 98 insertions(+), 11 deletions(-)

diff --git a/src/main/java/org/apache/groovy/util/JavaShell.java b/src/main/java/org/apache/groovy/util/JavaShell.java
index c797cb7..94b41b0 100644
--- a/src/main/java/org/apache/groovy/util/JavaShell.java
+++ b/src/main/java/org/apache/groovy/util/JavaShell.java
@@ -88,12 +88,13 @@ public class JavaShell {
      * @param className the main class name
      * @param src the source code
      * @param args arguments for main method
+     * @return the result
      * @throws Throwable
      */
-    public void run(String className, String src, String... args) throws Throwable {
+    public Object run(String className, String src, String... args) throws Throwable {
         Class<?> c = compile(className, src);
         Method mainMethod = c.getMethod(MAIN_METHOD_NAME, String[].class);
-        mainMethod.invoke(null, (Object) args);
+        return mainMethod.invoke(null, (Object) args);
     }
 
     /**
diff --git a/subprojects/groovy-console/build.gradle b/subprojects/groovy-console/build.gradle
index 4b48627..e29322e 100644
--- a/subprojects/groovy-console/build.gradle
+++ b/subprojects/groovy-console/build.gradle
@@ -20,6 +20,7 @@ evaluationDependsOn(':groovy-swing')
 
 dependencies {
     api rootProject // AstBrowser has methods with Closure params...
+    implementation "com.github.javaparser:javaparser-core:$javaParserVersion"
     implementation project(':groovy-swing')
     implementation project(':groovy-templates')
     testImplementation project(':groovy-test')
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Console.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Console.groovy
index 6117100..23c8f35 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Console.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Console.groovy
@@ -18,6 +18,11 @@
  */
 package groovy.console.ui
 
+
+import com.github.javaparser.StaticJavaParser
+import com.github.javaparser.ast.CompilationUnit
+import com.github.javaparser.ast.Modifier
+import com.github.javaparser.ast.body.TypeDeclaration
 import groovy.cli.internal.CliBuilderInternal
 import groovy.cli.internal.OptionAccessor
 import groovy.console.ui.text.FindReplaceUtility
@@ -35,6 +40,7 @@ import org.apache.groovy.antlr.LexerFrame
 import org.apache.groovy.io.StringBuilderWriter
 import org.apache.groovy.parser.antlr4.GroovyLangLexer
 import org.apache.groovy.parser.antlr4.GroovyLangParser
+import org.apache.groovy.util.JavaShell
 import org.apache.groovy.util.SystemUtil
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.ErrorCollector
@@ -1136,13 +1142,25 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
         return consoleControllers.find { it.consoleId == consoleId }
     }
 
+    private enum SourceType {
+        GROOVY, JAVA
+    }
+
+    void runJava(EventObject evt = null) {
+        doRun(evt, SourceType.JAVA)
+    }
+
     // actually run the script
     void runScript(EventObject evt = null) {
+        doRun(evt, SourceType.GROOVY)
+    }
+
+    private doRun(EventObject evt = null, SourceType st) {
         saveInputAreaContentHash()
         if (saveOnRun && scriptFile != null) {
-            if (fileSave(evt)) runScriptImpl(false)
+            if (fileSave(evt)) runScriptImpl(false, st)
         } else {
-            runScriptImpl(false)
+            runScriptImpl(false, st)
         }
     }
 
@@ -1180,11 +1198,20 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
         cc.getOptimizationOptions().get(CompilerConfiguration.INVOKEDYNAMIC)
     }
 
+    void runSelectedJava(EventObject evt = null) {
+        doRunSelected(evt, SourceType.JAVA)
+    }
+
     void runSelectedScript(EventObject evt = null) {
+        doRunSelected(evt, SourceType.GROOVY)
+    }
+
+    private void doRunSelected(EventObject evt = null, SourceType st) {
         saveInputAreaContentHash()
-        runScriptImpl(true)
+        runScriptImpl(true, st)
     }
 
+
     void addClasspathJar(EventObject evt = null) {
         def fc = new JFileChooser(currentClasspathJarDir)
         fc.fileSelectionMode = JFileChooser.FILES_ONLY
@@ -1251,7 +1278,7 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
         inputAreaContentHash = inputArea.getText().hashCode()
     }
 
-    private void runScriptImpl(boolean selected) {
+    private void runScriptImpl(boolean selected, SourceType st = SourceType.GROOVY) {
         if (scriptRunning) {
             statusLabel.text = 'Cannot run script now as a script is already running. Please wait or use "Interrupt Script" option.'
             return
@@ -1269,8 +1296,9 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
 
         // Print the input text
         if (showScriptInOutput) {
+            final promptPrfix = SourceType.JAVA === st ? 'java> ' : 'groovy> '
             for (line in record.getTextToRun(selected).tokenize('\n')) {
-                appendOutputNl('groovy> ', promptStyle)
+                appendOutputNl(promptPrfix, promptStyle)
                 appendOutput(line, commandStyle)
             }
             appendOutputNl(' \n', promptStyle)
@@ -1282,7 +1310,6 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
             try {
                 systemOutInterceptor.setConsoleId(this.getConsoleId())
                 SwingUtilities.invokeLater { showExecutingMessage() }
-                String name = scriptFile?.name ?: (DEFAULT_SCRIPT_NAME_START + scriptNameCounter++)
                 if (beforeExecution) {
                     beforeExecution()
                 }
@@ -1291,13 +1318,13 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
                     ClassLoader savedThreadContextClassLoader = Thread.currentThread().contextClassLoader
                     try {
                         Thread.currentThread().contextClassLoader = shell.classLoader
-                        result = shell.run(record.getTextToRun(selected), name, [])
+                        result = doRun(selected, st, record)
                     }
                     finally {
                         Thread.currentThread().contextClassLoader = savedThreadContextClassLoader
                     }
                 } else {
-                    result = shell.run(record.getTextToRun(selected), name, [])
+                    result = doRun(selected, st, record)
                 }
                 if (afterExecution) {
                     afterExecution()
@@ -1319,7 +1346,7 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
                     int delay = prefs.getInt('loopModeDelay', ConsolePreferences.DEFAULT_LOOP_MODE_DELAY_MILLIS)
                     Timer timer = new Timer(delay, {
                         if( inputAreaContentHash == inputArea.getText().hashCode() ) {
-                            runScriptImpl(selected)
+                            runScriptImpl(selected, st)
                         }
                     })
                     timer.repeats = false
@@ -1329,6 +1356,47 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
         }
     }
 
+    @CompileStatic
+    private Object doRun(boolean selected, SourceType st, HistoryRecord record) {
+        def result
+        def src = record.getTextToRun(selected)
+        if (SourceType.JAVA === st) {
+            Optional<String> optionalPrimaryClassName = findPrimaryClassName(src)
+            if (optionalPrimaryClassName.isPresent()) {
+                def js = new JavaShell(Thread.currentThread().contextClassLoader)
+                result = js.run(optionalPrimaryClassName.get(), src)
+            }
+        } else {
+            String name = ((File) scriptFile)?.name ?: (DEFAULT_SCRIPT_NAME_START + scriptNameCounter++)
+            result = shell.run(src, name, [])
+        }
+        return result
+    }
+
+    @CompileStatic
+    private static Optional<String> findPrimaryClassName(String javaSrc) {
+        List<TypeDeclaration<?>> result = new LinkedList<>()
+        CompilationUnit compilationUnit = StaticJavaParser.parse(javaSrc)
+
+        for (TypeDeclaration<?> td : compilationUnit.getTypes()) {
+            if (!(td.isTopLevelType() && td.isClassOrInterfaceDeclaration() && td.getModifiers().contains(Modifier.publicModifier()))) continue
+
+            if (td.fullyQualifiedName.isPresent()) {
+                result << td
+            }
+        }
+
+        String className = null
+        if (!result.isEmpty()) {
+            Optional<String> optionalClassName = result.get(0).getFullyQualifiedName()
+            if (optionalClassName.isPresent()) {
+                className = optionalClassName.get()
+            }
+        }
+
+        return Optional.ofNullable(className)
+    }
+
     void compileScript(EventObject evt = null) {
         if (scriptRunning) {
             statusLabel.text = 'Cannot compile script now as a script is already running. Please wait or use "Interrupt Script" option.'
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleActions.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleActions.groovy
index 57a3f19..fb05c2c 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleActions.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleActions.groovy
@@ -204,6 +204,14 @@ runAction = action(
         shortDescription: 'Execute Groovy Script'
 )
 
+runJavaAction = action(
+        name: 'Run as Java',
+        closure: controller.&runJava,
+        mnemonic: 'J',
+        accelerator: shortcut('alt R'),
+        shortDescription: 'Execute Java Code'
+)
+
 loopModeAction = action(
         name: 'Loop Mode',
         closure: controller.&loopMode,
@@ -219,6 +227,11 @@ runSelectionAction = action(
         accelerator: shortcut('shift R')
 )
 
+runJavaSelectionAction = action(
+        name: 'Run Java Selection',
+        closure: controller.&runSelectedJava
+)
+
 addClasspathJar = action(
         name: 'Add Jar(s) to ClassPath',
         closure: controller.&addClasspathJar,
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/BasicMenuBar.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/BasicMenuBar.groovy
index 4760c66..8252e33 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/BasicMenuBar.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/BasicMenuBar.groovy
@@ -78,9 +78,11 @@ menuBar {
 
     menu(text: 'Script', mnemonic: 'S') {
         menuItem(runAction)
+        menuItem(runJavaAction)
         checkBoxMenuItem(loopModeAction, selected: controller.loopMode)
         checkBoxMenuItem(saveOnRunAction, selected: controller.saveOnRun)
         menuItem(runSelectionAction)
+        menuItem(runJavaSelectionAction)
         checkBoxMenuItem(threadInterruptAction, selected: controller.threadInterrupt)
         menuItem(interruptAction)
         menuItem(compileAction)
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/MacOSXMenuBar.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/MacOSXMenuBar.groovy
index 58a78a7..20a2cd9 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/MacOSXMenuBar.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/view/MacOSXMenuBar.groovy
@@ -130,9 +130,11 @@ menuBar {
 
     menu(text: 'Script', mnemonic: 'S') {
         menuItem(runAction, icon:null)
+        menuItem(runJavaAction, icon:null)
         checkBoxMenuItem(loopModeAction, selected: controller.loopMode)
         checkBoxMenuItem(saveOnRunAction, selected: controller.saveOnRun)
         menuItem(runSelectionAction, icon:null)
+        menuItem(runJavaSelectionAction, icon:null)
         checkBoxMenuItem(threadInterruptAction, selected: controller.threadInterrupt)
         menuItem(interruptAction, icon:null)
         menuItem(compileAction, icon:null)