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