src/Tools/jEdit/src/scala_console.scala
changeset 43282 5d294220ca43
parent 37175 be764a7adb10
child 43520 cec9b95fa35d
equal deleted inserted replaced
43281:8d8b6ed0588c 43282:5d294220ca43
       
     1 /*  Title:      Tools/jEdit/src/scala_console.scala
       
     2     Author:     Makarius
       
     3 
       
     4 Scala instance of Console plugin.
       
     5 */
       
     6 
       
     7 package isabelle.jedit
       
     8 
       
     9 
       
    10 import isabelle._
       
    11 
       
    12 import console.{Console, ConsolePane, Shell, Output}
       
    13 
       
    14 import org.gjt.sp.jedit.{jEdit, JARClassLoader}
       
    15 import org.gjt.sp.jedit.MiscUtilities
       
    16 
       
    17 import java.io.{File, OutputStream, Writer, PrintWriter}
       
    18 
       
    19 import scala.tools.nsc.{Interpreter, GenericRunnerSettings, NewLinePrintWriter, ConsoleWriter}
       
    20 import scala.collection.mutable
       
    21 
       
    22 
       
    23 class Scala_Console extends Shell("Scala")
       
    24 {
       
    25   /* reconstructed jEdit/plugin classpath */
       
    26 
       
    27   private def reconstruct_classpath(): String =
       
    28   {
       
    29     def find_jars(start: String): List[String] =
       
    30       if (start != null)
       
    31         Standard_System.find_files(new File(start),
       
    32           entry => entry.isFile && entry.getName.endsWith(".jar")).map(_.getAbsolutePath)
       
    33       else Nil
       
    34     val path = find_jars(jEdit.getSettingsDirectory) ::: find_jars(jEdit.getJEditHome)
       
    35     path.mkString(File.pathSeparator)
       
    36   }
       
    37 
       
    38 
       
    39   /* global state -- owned by Swing thread */
       
    40 
       
    41   private var interpreters = Map[Console, Interpreter]()
       
    42 
       
    43   private var global_console: Console = null
       
    44   private var global_out: Output = null
       
    45   private var global_err: Output = null
       
    46 
       
    47   private val console_stream = new OutputStream
       
    48   {
       
    49     val buf = new StringBuilder
       
    50     override def flush()
       
    51     {
       
    52       val str = Standard_System.decode_permissive_utf8(buf.toString)
       
    53       buf.clear
       
    54       if (global_out == null) System.out.print(str)
       
    55       else Swing_Thread.now { global_out.writeAttrs(null, str) }
       
    56     }
       
    57     override def close() { flush () }
       
    58     def write(byte: Int) { buf.append(byte.toChar) }
       
    59   }
       
    60 
       
    61   private val console_writer = new Writer
       
    62   {
       
    63     def flush() {}
       
    64     def close() {}
       
    65 
       
    66     def write(cbuf: Array[Char], off: Int, len: Int)
       
    67     {
       
    68       if (len > 0) write(new String(cbuf.slice(off, off + len)))
       
    69     }
       
    70 
       
    71     override def write(str: String)
       
    72     {
       
    73       if (global_out == null) System.out.println(str)
       
    74       else global_out.print(null, str)
       
    75     }
       
    76   }
       
    77 
       
    78   private def with_console[A](console: Console, out: Output, err: Output)(e: => A): A =
       
    79   {
       
    80     global_console = console
       
    81     global_out = out
       
    82     global_err = if (err == null) out else err
       
    83     val res = Exn.capture { scala.Console.withOut(console_stream)(e) }
       
    84     console_stream.flush
       
    85     global_console = null
       
    86     global_out = null
       
    87     global_err = null
       
    88     Exn.release(res)
       
    89   }
       
    90 
       
    91   private def report_error(str: String)
       
    92   {
       
    93     if (global_console == null || global_err == null) System.err.println(str)
       
    94     else Swing_Thread.now { global_err.print(global_console.getErrorColor, str) }
       
    95   }
       
    96 
       
    97 
       
    98   /* jEdit console methods */
       
    99 
       
   100   override def openConsole(console: Console)
       
   101   {
       
   102     val settings = new GenericRunnerSettings(report_error)
       
   103     settings.classpath.value = reconstruct_classpath()
       
   104 
       
   105     val interp = new Interpreter(settings, new PrintWriter(console_writer, true))
       
   106     {
       
   107       override def parentClassLoader = new JARClassLoader
       
   108     }
       
   109     interp.setContextClassLoader
       
   110     interp.bind("view", "org.gjt.sp.jedit.View", console.getView)
       
   111     interp.bind("console", "console.Console", console)
       
   112     interp.interpret("import isabelle.jedit.Isabelle")
       
   113 
       
   114     interpreters += (console -> interp)
       
   115   }
       
   116 
       
   117   override def closeConsole(console: Console)
       
   118   {
       
   119     interpreters -= console
       
   120   }
       
   121 
       
   122   override def printInfoMessage(out: Output)
       
   123   {
       
   124     out.print(null,
       
   125      "This shell evaluates Isabelle/Scala expressions.\n\n" +
       
   126      "The following special toplevel bindings are provided:\n" +
       
   127      "  view      -- current jEdit/Swing view (e.g. view.getBuffer, view.getTextArea)\n" +
       
   128      "  console   -- jEdit Console plugin instance\n" +
       
   129      "  Isabelle  -- Isabelle plugin instance (e.g. Isabelle.system, Isabelle.session)\n")
       
   130   }
       
   131 
       
   132   override def printPrompt(console: Console, out: Output)
       
   133   {
       
   134     out.writeAttrs(ConsolePane.colorAttributes(console.getInfoColor), "scala>")
       
   135     out.writeAttrs(ConsolePane.colorAttributes(console.getPlainColor), " ")
       
   136   }
       
   137 
       
   138   override def execute(console: Console, input: String, out: Output, err: Output, command: String)
       
   139   {
       
   140     val interp = interpreters(console)
       
   141     with_console(console, out, err) { interp.interpret(command) }
       
   142     if (err != null) err.commandDone()
       
   143     out.commandDone()
       
   144   }
       
   145 
       
   146   override def stop(console: Console)
       
   147   {
       
   148     closeConsole(console)
       
   149     console.clear
       
   150     openConsole(console)
       
   151     val out = console.getOutput
       
   152     out.commandDone
       
   153     printPrompt(console, out)
       
   154   }
       
   155 }