PEAT Online Course -
Test-Driven Development
using Kotlin (DELUXE EDITION)

  • Theory 'n' practice
  • Test-driven method
  • Acceptance criteria
  • Learn to code mastery
  • Ace that job interview
  • Free updates
AVAILABLE NOW
VIMEO ON-DEMAND

Swing Scala REPL: What Is Wrong Here?

22 March 2011 4 comments

3 minutes

550

 

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?

package swingrepl

import java.io._
import scala.swing._
import scala.swing.event._

import javax.swing.SwingUtilities
import scala.tools.nsc._
import scala.tools.nsc.interpreter._

/**
 * Swing version of the REPL
 * User: Peter
 * Date: 22/03/11
 * Time: 14:34
 */
object SwingRepl extends SimpleSwingApplication {

  def outputPane  = new TextArea {
    editable = false
    text = "Text output"
  }

  def replInvoker = new ReplInvoker( outputPane )
  replInvoker.start()

  def inputPane: TextArea = new TextArea {
    text = "List(1,2,3,4,5) map ( n => n * n )"
    editable = true
    listenTo(keys)

    reactions += {
      case e: KeyPressed => {
        // println("keyCode =" +e.peer.getKeyCode+", keyChar = "+e.peer.getKeyChar)
        if ( e.peer.isControlDown && e.key == Key.Enter ) {
          replInvoker.interpret( text )
        }
      }

      case _ =>
    }
  }


  def scrollInputPane = new ScrollPane( inputPane )
  def scrollOutputPane = new ScrollPane( outputPane )

  def splitPane = new SplitPane( Orientation.Horizontal, scrollInputPane, scrollOutputPane )  {
    dividerLocation =  100
  }

  def top = new MainFrame {
    title = "Swing REPL"
    preferredSize = new Dimension(900, 900 )
    contents = splitPane
  }


  /**
   * Programmatically launching the Scala REPL
   */
  class ReplInvoker( val outputPane: TextComponent ) {
    private val swriter = new StringWriter()
    private val pwriter = new PrintWriter( swriter ) {
      override def println( line: String ) {
        super.println( line )
        System.out.println("println line="+line)
        outputPane.text = swriter.toString()
      }
      override def print( line: String ) {
        super.print( line )
        System.out.println("print line="+line)
        System.out.println("swriter.toString="+swriter.toString )

        SwingUtilities.invokeLater( new Runnable() {
          override def run(): Unit = {
            outputPane.text = outputPane.text +"\n"+ line +"\n"
            outputPane.peer.validate()
          }
        })
      }
    }

    private val cmd = new InterpreterCommand(Nil, println )
    println("cmd="+cmd)
    private val settings = cmd.settings
    println("settings="+settings)

    settings.usejavacp.value = true

    private val interpreter = new Interpreter(settings, pwriter ) {
      override def reset() = { super.reset; unleash() }
      override def unleash() = { super.unleash;  }
    }
    println("interpreter="+interpreter)
    private val completion = new Completion(interpreter)

    def start() {
       println("ReplInvoker.start")
    }

    def interpret(cmd: String): Unit = {
      println("replInvoker.interpret "+cmd )
      interpreter.interpret(cmd)
    }
  }
}

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.

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?

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?

Oh yes in case you are wondering, JavaFX 2.0 early access does not yet have a multi-line equivalent of JTextComponent.

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

4 Comments

  1. Peter, I believe the problem is that line 19 creates a new outputPane each time it is called. Switch that to a “val outputPane = …” to assign a value to outputPane instead.

    Comment by jherber — 23 March 2011 @ 2:09 pm

  2. […] the issue is my lack of brain cells on Scala’s Uniform Access Principle. If you noticed in yesterday’s program, the editor panes were created like […]

    Pingback by Peter Pilgrim :: Java Champion :: Enterprise Blog » Scala Swing REPL: Resolved — 23 March 2011 @ 2:13 pm

  3. I think it’s a combination of what jherber said, and also the fact that ‘replInvoker’ is a def, too, and not a val. thus whenever you hit Ctrl+Enter, a new instance of ReplInvoker, and thus (due to line 19) also a new instance of the outputPane is created.

    You may take a look at my attempt : https://github.com/Sciss/ScalaInterpreterPane/blob/master/src/main/scala/de/sciss/scalainterpreter/ScalaInterpreterPane.scala that uses JSyntaxPane instead, and also threads the interpreter initialization (so the system doesn’t hang when it’s booting up)

    Comment by itemState — 23 March 2011 @ 3:21 pm

  4. itemState, you are correct. It was Scala’s uniform access principle that threw me for a while. I had no idea about the JSyntaxPane component. Thanks for that link. It will be worth investigation. Threading the interpreter initialisation is also a good idea. Thanks

    Comment by admin — 25 March 2011 @ 1:43 pm

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Hey all! Thanks for visiting. I provide fringe benefits to interested readers: checkout consultancy, training or mentorship Please make enquiries by email or
call +44 (0)7397 067 658.

Due to the Off-Payroll Working plan for the UK government, I am enforcing stricter measures on contracts. All potential public sector GOV.UK contracts engagements must be approved by QDOS and/or SJD Accounting. Please enquire for further information.