{"id":258,"date":"2011-03-22T19:49:53","date_gmt":"2011-03-22T18:49:53","guid":{"rendered":"http:\/\/www.xenonique.co.uk\/blog\/?p=258"},"modified":"2011-03-22T20:09:23","modified_gmt":"2011-03-22T19:09:23","slug":"swing-scala-repl","status":"publish","type":"post","link":"https:\/\/www.xenonique.co.uk\/blog\/2011\/03\/22\/swing-scala-repl\/","title":{"rendered":"Swing Scala REPL: What Is Wrong Here?"},"content":{"rendered":"<p>&#160;<\/p>\n<p>I just spent the best part of two hours attempting figure out an interactive REPL for Scala, a la the <b> Groovy Console<\/b>, but a very basic version. My progress has not been lightning fast. Why?<\/p>\n<pre class=\"brush: scala; title: ; notranslate\" title=\"\">\r\npackage swingrepl\r\n\r\nimport java.io._\r\nimport scala.swing._\r\nimport scala.swing.event._\r\n\r\nimport javax.swing.SwingUtilities\r\nimport scala.tools.nsc._\r\nimport scala.tools.nsc.interpreter._\r\n\r\n\/**\r\n * Swing version of the REPL\r\n * User: Peter\r\n * Date: 22\/03\/11\r\n * Time: 14:34\r\n *\/\r\nobject SwingRepl extends SimpleSwingApplication {\r\n\r\n  def outputPane  = new TextArea {\r\n    editable = false\r\n    text = &quot;Text output&quot;\r\n  }\r\n\r\n  def replInvoker = new ReplInvoker( outputPane )\r\n  replInvoker.start()\r\n\r\n  def inputPane: TextArea = new TextArea {\r\n    text = &quot;List(1,2,3,4,5) map ( n =&gt; n * n )&quot;\r\n    editable = true\r\n    listenTo(keys)\r\n\r\n    reactions += {\r\n      case e: KeyPressed =&gt; {\r\n        \/\/ println(&quot;keyCode =&quot; +e.peer.getKeyCode+&quot;, keyChar = &quot;+e.peer.getKeyChar)\r\n        if ( e.peer.isControlDown &amp;&amp; e.key == Key.Enter ) {\r\n          replInvoker.interpret( text )\r\n        }\r\n      }\r\n\r\n      case _ =&gt;\r\n    }\r\n  }\r\n\r\n\r\n  def scrollInputPane = new ScrollPane( inputPane )\r\n  def scrollOutputPane = new ScrollPane( outputPane )\r\n\r\n  def splitPane = new SplitPane( Orientation.Horizontal, scrollInputPane, scrollOutputPane )  {\r\n    dividerLocation =  100\r\n  }\r\n\r\n  def top = new MainFrame {\r\n    title = &quot;Swing REPL&quot;\r\n    preferredSize = new Dimension(900, 900 )\r\n    contents = splitPane\r\n  }\r\n\r\n\r\n  \/**\r\n   * Programmatically launching the Scala REPL\r\n   *\/\r\n  class ReplInvoker( val outputPane: TextComponent ) {\r\n    private val swriter = new StringWriter()\r\n    private val pwriter = new PrintWriter( swriter ) {\r\n      override def println( line: String ) {\r\n        super.println( line )\r\n        System.out.println(&quot;println line=&quot;+line)\r\n        outputPane.text = swriter.toString()\r\n      }\r\n      override def print( line: String ) {\r\n        super.print( line )\r\n        System.out.println(&quot;print line=&quot;+line)\r\n        System.out.println(&quot;swriter.toString=&quot;+swriter.toString )\r\n\r\n        SwingUtilities.invokeLater( new Runnable() {\r\n          override def run(): Unit = {\r\n            outputPane.text = outputPane.text +&quot;\\n&quot;+ line +&quot;\\n&quot;\r\n            outputPane.peer.validate()\r\n          }\r\n        })\r\n      }\r\n    }\r\n\r\n    private val cmd = new InterpreterCommand(Nil, println )\r\n    println(&quot;cmd=&quot;+cmd)\r\n    private val settings = cmd.settings\r\n    println(&quot;settings=&quot;+settings)\r\n\r\n    settings.usejavacp.value = true\r\n\r\n    private val interpreter = new Interpreter(settings, pwriter ) {\r\n      override def reset() = { super.reset; unleash() }\r\n      override def unleash() = { super.unleash;  }\r\n    }\r\n    println(&quot;interpreter=&quot;+interpreter)\r\n    private val completion = new Completion(interpreter)\r\n\r\n    def start() {\r\n       println(&quot;ReplInvoker.start&quot;)\r\n    }\r\n\r\n    def interpret(cmd: String): Unit = {\r\n      println(&quot;replInvoker.interpret &quot;+cmd )\r\n      interpreter.interpret(cmd)\r\n    }\r\n  }\r\n}\r\n<\/pre>\n<p>I really do not understand why this code is not working at all. It is a Swing application to programmatically invokes Scala NSC REPL. I have two JEditorPanes in set horizontally in a JSplitPane. The upper editor pane is a reserved for text entry. The lower editor pane is not editable is reserved for capturing the output of the Scala.<\/p>\n<p>To fire the REPL interactively in the upper pane, hold the CTRL key and pressed the RETURN\/ENTER key. Invoking the REPL works fine. However it is the update to the lower pane that causes concern. I can see the interactive REPL returning a result, yet the JEditorPane is not being updated. Is this a Swing Scala bug? Or does Java Swing bug?<\/p>\n<p> I suspected the cause was a Swing multithreading problem hence I used SwingUtilites.invokeLater to make sure the update was on the Event Dispatch Thread, however to no avail. JComponent.repaint() nada, JComponent.validate() nada. What gives?<\/p>\n<p>Oh yes in case you are wondering, JavaFX 2.0 early access does not yet have a multi-line equivalent of JTextComponent. <\/p>\n<p>I will be very interested in finding out what is wrong with this picture? If you know the answer, then a pint of Staropramen is on me. Thanks<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#160; I just spent the best part of two hours attempting figure out an interactive REPL for Scala, a la the Groovy Console, but a very basic version. My progress has not been lightning fast. Why? I really do not understand why this code is not working at all. It is a Swing application to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[8,6,73],"tags":[],"_links":{"self":[{"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/posts\/258"}],"collection":[{"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=258"}],"version-history":[{"count":8,"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/posts\/258\/revisions"}],"predecessor-version":[{"id":267,"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/posts\/258\/revisions\/267"}],"wp:attachment":[{"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=258"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=258"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xenonique.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=258"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}