lib/jedit/plugin/isabelle/IsabellePlugin.scala
author wenzelm
Sat, 23 Aug 2008 23:07:30 +0200
changeset 27966 825286a7a3a4
parent 25948 aa65ada6f095
child 27985 fb774d10ea4c
permissions -rw-r--r--
adapted to new IsabelleProcess from Pure.jar; IsabellePlugin.result_content decodes symbols;

/*  Title:      jedit/plugin/IsabellePlugin.scala
    ID:         $Id$
    Author:     Makarius

Isabelle/jEdit plugin -- main setup.
*/

package isabelle

import org.gjt.sp.jedit.EditPlugin
import org.gjt.sp.util.Log

import errorlist.DefaultErrorSource
import errorlist.ErrorSource

import java.util.Properties
import java.lang.NumberFormatException

import scala.collection.mutable.ListBuffer
import scala.io.Source


/* Global state */

object IsabellePlugin {
  // unique ids
  @volatile
  private var idCount = 0

  def id() : String = synchronized { idCount += 1; "jedit:" + idCount }

  def idProperties(value: String) : Properties = {
     val props = new Properties
     props.setProperty(Markup.ID, value)
     props
  }

  def idProperties() : Properties = { idProperties(id()) }


  // the error source
  @volatile
  var errors: DefaultErrorSource = null

  // the Isabelle process
  @volatile
  var isabelle: IsabelleProcess = null


  // result content
  def result_content(result: IsabelleProcess.Result) =
    XML.content(isabelle.result_tree(result)).mkString("")


  // result consumers
  type consumer = IsabelleProcess.Result => Boolean
  private var consumers = new ListBuffer[consumer]

  def addConsumer(consumer: consumer) = synchronized { consumers += consumer }

  def addPermanentConsumer(consumer: IsabelleProcess.Result => Unit) = {
    addConsumer(result => { consumer(result); false })
  }

  def delConsumer(consumer: consumer) = synchronized { consumers -= consumer }

  def consume(result: IsabelleProcess.Result) : Unit = {
    synchronized { consumers.elements.toList } foreach (consumer =>
      {
        val finished =
          try { consumer(result) }
          catch { case e: Throwable => Log.log(Log.ERROR, this, e); true }
        if (finished || result == null)
          delConsumer(consumer)
      })
  }
}


/* Main plugin setup */

class IsabellePlugin extends EditPlugin {
  private var thread: Thread = null

  override def start = {
    // error source
    IsabellePlugin.errors = new DefaultErrorSource("isabelle")
    ErrorSource.registerErrorSource(IsabellePlugin.errors)

    IsabellePlugin.addPermanentConsumer (result =>
      if (result != null && result.props != null &&
          (result.kind == IsabelleProcess.Kind.WARNING ||
           result.kind == IsabelleProcess.Kind.ERROR)) {
        val typ =
          if (result.kind == IsabelleProcess.Kind.WARNING) ErrorSource.WARNING
          else ErrorSource.ERROR
        (Position.line_of(result.props), Position.file_of(result.props)) match {
          case (Some(line), Some(file)) =>
            val content = IsabellePlugin.result_content(result)
            if (content.length > 0) {
              val lines = Source.fromString(content).getLines
              val err = new DefaultErrorSource.DefaultError(IsabellePlugin.errors,
                  typ, file, line - 1, 0, 0, lines.next)
              for (msg <- lines) err.addExtraMessage(msg)
              IsabellePlugin.errors.addError(err)
            }
          case _ =>
        }
      })


    // Isabelle process
    IsabellePlugin.isabelle =
      new IsabelleProcess("-mno_brackets", "-mno_type_brackets", "-mxsymbols")
    thread = new Thread (new Runnable {
      def run = {
        var result: IsabelleProcess.Result = null
        do {
          try {
            result = IsabellePlugin.isabelle.results.take
          }
          catch {
            case _: NullPointerException => result = null
            case _: InterruptedException => result = null
          }
          if (result != null) {
            System.err.println(result)   // FIXME
            IsabellePlugin.consume(result)
          }
          if (result.kind == IsabelleProcess.Kind.EXIT) {
            result = null
            IsabellePlugin.consume(null)
          }
        } while (result != null)
      }
    })
    thread.start
  }

  override def stop = {
    IsabellePlugin.isabelle.kill
    thread.interrupt; thread.join; thread = null
    IsabellePlugin.isabelle = null

    ErrorSource.unregisterErrorSource(IsabellePlugin.errors)
    IsabellePlugin.errors = null
  }
}