lib/jedit/plugin/isabelle_plugin.scala
changeset 33683 8d43e5e0588d
parent 33682 0c5d1485dea7
child 33684 29d8aaeb56e5
equal deleted inserted replaced
33682:0c5d1485dea7 33683:8d43e5e0588d
     1 /*  Title:      lib/jedit/plugin/isabelle_plugin.scala
       
     2     ID:         $Id$
       
     3     Author:     Makarius
       
     4 
       
     5 Isabelle/jEdit plugin -- main setup.
       
     6 */
       
     7 
       
     8 package isabelle.jedit
       
     9 
       
    10 import java.util.Properties
       
    11 import java.lang.NumberFormatException
       
    12 
       
    13 import scala.collection.mutable.ListBuffer
       
    14 import scala.io.Source
       
    15 
       
    16 import org.gjt.sp.util.Log
       
    17 import org.gjt.sp.jedit.{jEdit, EBPlugin, EBMessage}
       
    18 import org.gjt.sp.jedit.msg.DockableWindowUpdate
       
    19 
       
    20 import errorlist.DefaultErrorSource
       
    21 import errorlist.ErrorSource
       
    22 
       
    23 
       
    24 
       
    25 /** global state **/
       
    26 
       
    27 object IsabellePlugin {
       
    28 
       
    29   /* Isabelle symbols */
       
    30 
       
    31   val symbols = new Symbol.Interpretation
       
    32 
       
    33   def result_content(result: IsabelleProcess.Result) =
       
    34     XML.content(YXML.parse_failsafe(symbols.decode(result.result))).mkString("")
       
    35 
       
    36 
       
    37   /* Isabelle process */
       
    38 
       
    39   var isabelle: IsabelleProcess = null
       
    40 
       
    41 
       
    42   /* unique ids */
       
    43 
       
    44   private var id_count: BigInt = 0
       
    45 
       
    46   def id() : String = synchronized { id_count += 1; "jedit:" + id_count }
       
    47 
       
    48   def id_properties(value: String) : Properties = {
       
    49      val props = new Properties
       
    50      props.setProperty(Markup.ID, value)
       
    51      props
       
    52   }
       
    53 
       
    54   def id_properties() : Properties = { id_properties(id()) }
       
    55 
       
    56 
       
    57   /* result consumers */
       
    58 
       
    59   type Consumer = IsabelleProcess.Result => Boolean
       
    60   private var consumers = new ListBuffer[Consumer]
       
    61 
       
    62   def add_consumer(consumer: Consumer) = synchronized { consumers += consumer }
       
    63 
       
    64   def add_permanent_consumer(consumer: IsabelleProcess.Result => Unit) = {
       
    65     add_consumer(result => { consumer(result); false })
       
    66   }
       
    67 
       
    68   def del_consumer(consumer: Consumer) = synchronized { consumers -= consumer }
       
    69 
       
    70   private def consume(result: IsabelleProcess.Result) = {
       
    71     synchronized { consumers.elements.toList } foreach (consumer =>
       
    72       {
       
    73         if (result != null && result.is_control) Log.log(Log.DEBUG, result, null)
       
    74         val finished =
       
    75           try { consumer(result) }
       
    76           catch { case e: Throwable => Log.log(Log.ERROR, result, e); true }
       
    77         if (finished || result == null) del_consumer(consumer)
       
    78       })
       
    79   }
       
    80 
       
    81   class ConsumerThread extends Thread {
       
    82     override def run = {
       
    83       var finished = false
       
    84       while (!finished) {
       
    85         val result =
       
    86           try { IsabellePlugin.isabelle.get_result() }
       
    87           catch { case _: NullPointerException => null }
       
    88 
       
    89         if (result != null) {
       
    90           consume(result)
       
    91           if (result.kind == IsabelleProcess.Kind.EXIT) {
       
    92             consume(null)
       
    93             finished = true
       
    94           }
       
    95         }
       
    96         else finished = true
       
    97       }
       
    98     }
       
    99   }
       
   100 
       
   101 }
       
   102 
       
   103 
       
   104 /* Main plugin setup */
       
   105 
       
   106 class IsabellePlugin extends EBPlugin {
       
   107 
       
   108   import IsabellePlugin._
       
   109 
       
   110   val errors = new DefaultErrorSource("isabelle")
       
   111   val consumer_thread = new ConsumerThread
       
   112 
       
   113 
       
   114   override def start = {
       
   115 
       
   116     /* error source */
       
   117 
       
   118     ErrorSource.registerErrorSource(errors)
       
   119 
       
   120     add_permanent_consumer (result =>
       
   121       if (result != null &&
       
   122           (result.kind == IsabelleProcess.Kind.WARNING ||
       
   123            result.kind == IsabelleProcess.Kind.ERROR)) {
       
   124         (Position.line_of(result.props), Position.file_of(result.props)) match {
       
   125           case (Some(line), Some(file)) =>
       
   126             val typ =
       
   127               if (result.kind == IsabelleProcess.Kind.WARNING) ErrorSource.WARNING
       
   128               else ErrorSource.ERROR
       
   129             val content = result_content(result)
       
   130             if (content.length > 0) {
       
   131               val lines = Source.fromString(content).getLines
       
   132               val err = new DefaultErrorSource.DefaultError(errors,
       
   133                   typ, file, line - 1, 0, 0, lines.next)
       
   134               for (msg <- lines) err.addExtraMessage(msg)
       
   135               errors.addError(err)
       
   136             }
       
   137           case _ =>
       
   138         }
       
   139       })
       
   140 
       
   141 
       
   142     /* Isabelle process */
       
   143 
       
   144     val options =
       
   145       (for (mode <- jEdit.getProperty("isabelle.print-modes").split("\\s+") if mode != "")
       
   146         yield "-m" + mode)
       
   147     val args = {
       
   148       val logic = jEdit.getProperty("isabelle.logic")
       
   149       if (logic != "") List(logic) else Nil
       
   150     }
       
   151     isabelle = new IsabelleProcess((options ++ args): _*)
       
   152 
       
   153     consumer_thread.start
       
   154 
       
   155   }
       
   156 
       
   157 
       
   158   override def stop = {
       
   159     isabelle.kill
       
   160     consumer_thread.join
       
   161     ErrorSource.unregisterErrorSource(errors)
       
   162   }
       
   163 
       
   164 
       
   165   override def handleMessage(message: EBMessage) = message match {
       
   166     case _: DockableWindowUpdate =>   // FIXME check isabelle process
       
   167     case _ =>
       
   168   }
       
   169 
       
   170 }