You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2015/10/25 19:35:46 UTC

incubator-groovy git commit: GROOVY-4888 - groovy console script execution output appears in all output windows (closes #160)

Repository: incubator-groovy
Updated Branches:
  refs/heads/master 0a1d8b469 -> 5c556c06c


GROOVY-4888 - groovy console script execution output appears in all output windows (closes #160)


Project: http://git-wip-us.apache.org/repos/asf/incubator-groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-groovy/commit/5c556c06
Tree: http://git-wip-us.apache.org/repos/asf/incubator-groovy/tree/5c556c06
Diff: http://git-wip-us.apache.org/repos/asf/incubator-groovy/diff/5c556c06

Branch: refs/heads/master
Commit: 5c556c06ca2f5be367415a66f6af4e6dd531767f
Parents: 0a1d8b4
Author: John Wagenleitner <jo...@gmail.com>
Authored: Sat Oct 24 23:30:34 2015 -0700
Committer: pascalschumacher <pa...@gmx.net>
Committed: Sun Oct 25 19:28:02 2015 +0100

----------------------------------------------------------------------
 .../src/main/groovy/groovy/ui/Console.groovy    | 44 ++++++++++++----
 .../groovy/ui/SystemOutputInterceptor.java      | 39 ++++++++++++--
 .../groovy/swing/SwingBuilderConsoleTest.groovy | 53 ++++++++++++++++++++
 3 files changed, 121 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/5c556c06/subprojects/groovy-console/src/main/groovy/groovy/ui/Console.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/ui/Console.groovy b/subprojects/groovy-console/src/main/groovy/groovy/ui/Console.groovy
index 6324bef..0746803 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/ui/Console.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/ui/Console.groovy
@@ -887,42 +887,64 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
         updateFontSize(inputArea.font.size + 2)
     }
 
-    static boolean notifySystemOut(String str) {
+    static boolean notifySystemOut(int consoleId, String str) {
         if (!captureStdOut) {
             // Output as normal
             return true
         }
 
+        Closure doAppend = {
+            Console console = findConsoleById(consoleId)
+            if (console) {
+                console.appendOutputLines(str, console.outputStyle)
+            } else {
+                consoleControllers.each {it.appendOutputLines(str, it.outputStyle)}
+            }
+        }
+
         // Put onto GUI
         if (EventQueue.isDispatchThread()) {
-            consoleControllers.each {it.appendOutputLines(str, it.outputStyle)}
+            doAppend.call()
         }
         else {
-            SwingUtilities.invokeLater {
-                consoleControllers.each {it.appendOutputLines(str, it.outputStyle)}
-            }
+            SwingUtilities.invokeLater doAppend
         }
         return false
     }
 
-    static boolean notifySystemErr(String str) {
+    static boolean notifySystemErr(int consoleId, String str) {
         if (!captureStdErr) {
             // Output as normal
             return true
         }
 
+        Closure doAppend = {
+            Console console = findConsoleById(consoleId)
+            if (console) {
+                console.appendStacktrace(str)
+            } else {
+                consoleControllers.each {it.appendStacktrace(str)}
+            }
+        }
+
         // Put onto GUI
         if (EventQueue.isDispatchThread()) {
-            consoleControllers.each {it.appendStacktrace(str)}
+            doAppend.call()
         }
         else {
-            SwingUtilities.invokeLater {
-                consoleControllers.each {it.appendStacktrace(str)}
-            }
+            SwingUtilities.invokeLater doAppend
         }
         return false
     }
 
+    int getConsoleId() {
+        return System.identityHashCode(this)
+    }
+
+    private static Console findConsoleById(int consoleId) {
+        return consoleControllers.find { it.consoleId == consoleId }
+    }
+
     // actually run the script
 
     void runScript(EventObject evt = null) {
@@ -1003,6 +1025,7 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
         // Run in a thread outside of EDT, this method is usually called inside the EDT
         runThread = Thread.start {
             try {
+                systemOutInterceptor.setConsoleId(this.getConsoleId())
                 SwingUtilities.invokeLater { showExecutingMessage() }
                 String name = scriptFile?.name ?: (DEFAULT_SCRIPT_NAME_START + scriptNameCounter++)
                 if(beforeExecution) {
@@ -1037,6 +1060,7 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo
                 runThread = null
                 scriptRunning = false
                 interruptAction.enabled = false
+                systemOutInterceptor.removeConsoleId()
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/5c556c06/subprojects/groovy-console/src/main/groovy/groovy/ui/SystemOutputInterceptor.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/ui/SystemOutputInterceptor.java b/subprojects/groovy-console/src/main/groovy/groovy/ui/SystemOutputInterceptor.java
index 0df242b..7f47d8e 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/ui/SystemOutputInterceptor.java
+++ b/subprojects/groovy-console/src/main/groovy/groovy/ui/SystemOutputInterceptor.java
@@ -32,10 +32,18 @@ public class SystemOutputInterceptor extends FilterOutputStream {
     private Closure callback;
     private boolean output;
 
+    private static final ThreadLocal<Integer> consoleId = new ThreadLocal<Integer>() {
+        @Override
+        protected Integer initialValue() {
+            return Integer.valueOf(0);
+        }
+    };
+
     /**
      * Constructor
      *
-     * @param callback accepts a string to be sent to std out and returns a Boolean.
+     * @param callback accepts the id of the target Console instance and a
+     *                 string to be sent to std out and returns a Boolean.
      *                 If the return value is true, output will be sent to
      *                 System.out, otherwise it will not.
      */
@@ -46,7 +54,8 @@ public class SystemOutputInterceptor extends FilterOutputStream {
     /**
      * Constructor
      *
-     * @param callback accepts a string to be sent to std out and returns a Boolean.
+     * @param callback accepts the id of the target Console instance and a
+     *                 string to be sent to std out and returns a Boolean.
      *                 If the return value is true, output will be sent to
      *                 System.out/System.err, otherwise it will not.
      * @param output   flag that tells whether System.out needs capturing ot System.err
@@ -84,10 +93,10 @@ public class SystemOutputInterceptor extends FilterOutputStream {
     }
 
     /**
-     * Intercepts output - moret common case of byte[]
+     * Intercepts output - more common case of byte[]
      */
     public void write(byte[] b, int off, int len) throws IOException {
-        Boolean result = (Boolean) callback.call(new String(b, off, len));
+        Boolean result = (Boolean) callback.call(consoleId.get().intValue(), new String(b, off, len));
         if (result) {
             out.write(b, off, len);
         }
@@ -97,9 +106,29 @@ public class SystemOutputInterceptor extends FilterOutputStream {
      * Intercepts output - single characters
      */
     public void write(int b) throws IOException {
-        Boolean result = (Boolean) callback.call(String.valueOf((char) b));
+        Boolean result = (Boolean) callback.call(consoleId.get().intValue(), String.valueOf((char) b));
         if (result) {
             out.write(b);
         }
     }
+
+    /**
+     * Threads executing a script should call this method at the start of execution
+     * in order to set the id of the console that is hosting the thread of execution.  This
+     * should be called prior to any output that is generated.  The consoleId will
+     * be passed to the callback.
+     *
+     * @param consoleId id of the Console instance executing the script
+     */
+    public void setConsoleId(int consoleId) {
+        this.consoleId.set(Integer.valueOf(consoleId));
+    }
+
+    /**
+     * Threads executing a script should call this method after
+     * execution completes in order to unregister the consoleId.
+     */
+    public void removeConsoleId() {
+        this.consoleId.remove();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/5c556c06/subprojects/groovy-console/src/test/groovy/groovy/swing/SwingBuilderConsoleTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-console/src/test/groovy/groovy/swing/SwingBuilderConsoleTest.groovy b/subprojects/groovy-console/src/test/groovy/groovy/swing/SwingBuilderConsoleTest.groovy
index 7705409..9aca8a4 100644
--- a/subprojects/groovy-console/src/test/groovy/groovy/swing/SwingBuilderConsoleTest.groovy
+++ b/subprojects/groovy-console/src/test/groovy/groovy/swing/SwingBuilderConsoleTest.groovy
@@ -512,4 +512,57 @@ class SwingBuilderConsoleTest extends GroovySwingTestCase {
         }
     }
 
+    void testSystemOutputAndErrorRedirectedToCorrectConsole() {
+        testInEDT {
+            SwingUtilities.metaClass.static.invokeLater = { Runnable runnable ->
+                runnable.run()
+            }
+            Thread.metaClass.static.start = { Runnable runnable ->
+                runnable.run()
+            }
+
+            Console.prefs = testPreferences
+
+            try {
+                def swing = new SwingBuilder()
+                final Console console = new Console()
+                swing.controller = console
+                swing.build(new ConsoleActions())
+                console.run()
+                console.fileNewWindow()
+                final Console console2 = Console.consoleControllers.last()
+
+                console.showScriptInOutput = false
+                console2.showScriptInOutput = false
+
+                def doc = console.outputArea.document
+                def doc2 = console2.outputArea.document
+
+                assert console.consoleId != console2.consoleId
+
+                console.inputArea.text = 'println "test1"'
+                console.runScript()
+
+                assert 'test1' == doc.getText(0, doc.length).trim()
+                assert '' == doc2.getText(0, doc2.length).trim()
+
+                console2.inputArea.text = 'println "test2"'
+                console2.runScript()
+
+                assert 'test1' == doc.getText(0, doc.length).trim()
+                assert 'test2' == doc2.getText(0, doc2.length).trim()
+
+                console2.inputArea.text = 'System.err.println "error2"'
+                console2.runScript()
+
+                assert 'test1' == doc.getText(0, doc.length).trim()
+                assert doc2.getText(0, doc2.length) ==~ /(?s)(test2)[^\w].*(error2).*/
+            } finally {
+                GroovySystem.metaClassRegistry.removeMetaClass(Thread)
+                GroovySystem.metaClassRegistry.removeMetaClass(SwingUtilities)
+                GroovySystem.metaClassRegistry.removeMetaClass(Preferences)
+            }
+        }
+    }
+
 }