lib/jedit/plugin/isabelle/IsabellePlugin.scala
author wenzelm
Sun, 24 Aug 2008 18:11:20 +0200
changeset 27985 fb774d10ea4c
parent 27966 825286a7a3a4
permissions -rw-r--r--
repackaged as isabelle.jedit;
wenzelm@25851
     1
/*  Title:      jedit/plugin/IsabellePlugin.scala
wenzelm@25851
     2
    ID:         $Id$
wenzelm@25851
     3
    Author:     Makarius
wenzelm@25851
     4
wenzelm@25851
     5
Isabelle/jEdit plugin -- main setup.
wenzelm@25851
     6
*/
wenzelm@25851
     7
wenzelm@27985
     8
package isabelle.jedit
wenzelm@25851
     9
wenzelm@25851
    10
import org.gjt.sp.jedit.EditPlugin
wenzelm@25851
    11
import org.gjt.sp.util.Log
wenzelm@25851
    12
wenzelm@25851
    13
import errorlist.DefaultErrorSource
wenzelm@25851
    14
import errorlist.ErrorSource
wenzelm@25851
    15
wenzelm@25851
    16
import java.util.Properties
wenzelm@25851
    17
import java.lang.NumberFormatException
wenzelm@25851
    18
wenzelm@27966
    19
import scala.collection.mutable.ListBuffer
wenzelm@27966
    20
import scala.io.Source
wenzelm@27966
    21
wenzelm@25851
    22
wenzelm@25851
    23
/* Global state */
wenzelm@25851
    24
wenzelm@25851
    25
object IsabellePlugin {
wenzelm@25851
    26
  // unique ids
wenzelm@25851
    27
  @volatile
wenzelm@25851
    28
  private var idCount = 0
wenzelm@25851
    29
wenzelm@25851
    30
  def id() : String = synchronized { idCount += 1; "jedit:" + idCount }
wenzelm@25851
    31
wenzelm@25851
    32
  def idProperties(value: String) : Properties = {
wenzelm@25851
    33
     val props = new Properties
wenzelm@27966
    34
     props.setProperty(Markup.ID, value)
wenzelm@25851
    35
     props
wenzelm@25851
    36
  }
wenzelm@25851
    37
wenzelm@25851
    38
  def idProperties() : Properties = { idProperties(id()) }
wenzelm@25851
    39
wenzelm@25851
    40
wenzelm@25851
    41
  // the error source
wenzelm@25851
    42
  @volatile
wenzelm@25851
    43
  var errors: DefaultErrorSource = null
wenzelm@25851
    44
wenzelm@25851
    45
  // the Isabelle process
wenzelm@25851
    46
  @volatile
wenzelm@25851
    47
  var isabelle: IsabelleProcess = null
wenzelm@25851
    48
wenzelm@25851
    49
wenzelm@27966
    50
  // result content
wenzelm@27966
    51
  def result_content(result: IsabelleProcess.Result) =
wenzelm@27966
    52
    XML.content(isabelle.result_tree(result)).mkString("")
wenzelm@27966
    53
wenzelm@27966
    54
wenzelm@25851
    55
  // result consumers
wenzelm@25851
    56
  type consumer = IsabelleProcess.Result => Boolean
wenzelm@25851
    57
  private var consumers = new ListBuffer[consumer]
wenzelm@25851
    58
wenzelm@25851
    59
  def addConsumer(consumer: consumer) = synchronized { consumers += consumer }
wenzelm@25851
    60
wenzelm@25851
    61
  def addPermanentConsumer(consumer: IsabelleProcess.Result => Unit) = {
wenzelm@25851
    62
    addConsumer(result => { consumer(result); false })
wenzelm@25851
    63
  }
wenzelm@25851
    64
wenzelm@25851
    65
  def delConsumer(consumer: consumer) = synchronized { consumers -= consumer }
wenzelm@25851
    66
wenzelm@25851
    67
  def consume(result: IsabelleProcess.Result) : Unit = {
wenzelm@25851
    68
    synchronized { consumers.elements.toList } foreach (consumer =>
wenzelm@25851
    69
      {
wenzelm@25851
    70
        val finished =
wenzelm@25851
    71
          try { consumer(result) }
wenzelm@25851
    72
          catch { case e: Throwable => Log.log(Log.ERROR, this, e); true }
wenzelm@25851
    73
        if (finished || result == null)
wenzelm@25851
    74
          delConsumer(consumer)
wenzelm@25851
    75
      })
wenzelm@25851
    76
  }
wenzelm@25851
    77
}
wenzelm@25851
    78
wenzelm@25851
    79
wenzelm@25851
    80
/* Main plugin setup */
wenzelm@25851
    81
wenzelm@25851
    82
class IsabellePlugin extends EditPlugin {
wenzelm@25851
    83
  private var thread: Thread = null
wenzelm@25851
    84
wenzelm@25851
    85
  override def start = {
wenzelm@25851
    86
    // error source
wenzelm@25851
    87
    IsabellePlugin.errors = new DefaultErrorSource("isabelle")
wenzelm@25851
    88
    ErrorSource.registerErrorSource(IsabellePlugin.errors)
wenzelm@25851
    89
wenzelm@25851
    90
    IsabellePlugin.addPermanentConsumer (result =>
wenzelm@25851
    91
      if (result != null && result.props != null &&
wenzelm@27966
    92
          (result.kind == IsabelleProcess.Kind.WARNING ||
wenzelm@27966
    93
           result.kind == IsabelleProcess.Kind.ERROR)) {
wenzelm@25851
    94
        val typ =
wenzelm@27966
    95
          if (result.kind == IsabelleProcess.Kind.WARNING) ErrorSource.WARNING
wenzelm@25851
    96
          else ErrorSource.ERROR
wenzelm@27966
    97
        (Position.line_of(result.props), Position.file_of(result.props)) match {
wenzelm@27966
    98
          case (Some(line), Some(file)) =>
wenzelm@27966
    99
            val content = IsabellePlugin.result_content(result)
wenzelm@27966
   100
            if (content.length > 0) {
wenzelm@27966
   101
              val lines = Source.fromString(content).getLines
wenzelm@27966
   102
              val err = new DefaultErrorSource.DefaultError(IsabellePlugin.errors,
wenzelm@27966
   103
                  typ, file, line - 1, 0, 0, lines.next)
wenzelm@27966
   104
              for (msg <- lines) err.addExtraMessage(msg)
wenzelm@27966
   105
              IsabellePlugin.errors.addError(err)
wenzelm@27966
   106
            }
wenzelm@27966
   107
          case _ =>
wenzelm@25851
   108
        }
wenzelm@25851
   109
      })
wenzelm@25851
   110
wenzelm@27966
   111
wenzelm@25851
   112
    // Isabelle process
wenzelm@27966
   113
    IsabellePlugin.isabelle =
wenzelm@27966
   114
      new IsabelleProcess("-mno_brackets", "-mno_type_brackets", "-mxsymbols")
wenzelm@25851
   115
    thread = new Thread (new Runnable {
wenzelm@25851
   116
      def run = {
wenzelm@25851
   117
        var result: IsabelleProcess.Result = null
wenzelm@25851
   118
        do {
wenzelm@25851
   119
          try {
wenzelm@27966
   120
            result = IsabellePlugin.isabelle.results.take
wenzelm@27966
   121
          }
wenzelm@27966
   122
          catch {
wenzelm@25948
   123
            case _: NullPointerException => result = null
wenzelm@25948
   124
            case _: InterruptedException => result = null
wenzelm@25851
   125
          }
wenzelm@25851
   126
          if (result != null) {
wenzelm@25851
   127
            System.err.println(result)   // FIXME
wenzelm@25851
   128
            IsabellePlugin.consume(result)
wenzelm@25851
   129
          }
wenzelm@27966
   130
          if (result.kind == IsabelleProcess.Kind.EXIT) {
wenzelm@25851
   131
            result = null
wenzelm@25851
   132
            IsabellePlugin.consume(null)
wenzelm@25851
   133
          }
wenzelm@25851
   134
        } while (result != null)
wenzelm@25851
   135
      }
wenzelm@25851
   136
    })
wenzelm@25851
   137
    thread.start
wenzelm@25851
   138
  }
wenzelm@25851
   139
wenzelm@25851
   140
  override def stop = {
wenzelm@25851
   141
    IsabellePlugin.isabelle.kill
wenzelm@25851
   142
    thread.interrupt; thread.join; thread = null
wenzelm@25851
   143
    IsabellePlugin.isabelle = null
wenzelm@25851
   144
wenzelm@25851
   145
    ErrorSource.unregisterErrorSource(IsabellePlugin.errors)
wenzelm@25851
   146
    IsabellePlugin.errors = null
wenzelm@25851
   147
  }
wenzelm@25851
   148
}