misc rearrangement of files;
authorwenzelm
Tue, 08 Dec 2009 14:49:01 +0100
changeset 34759 bfea7839d9e1
parent 34758 710e3a9a4c95
child 34760 dc7f5e0d9d27
misc rearrangement of files;
src/Tools/jEdit/src/jedit/BrowseVersionDockable.scala
src/Tools/jEdit/src/jedit/Document_Overview.scala
src/Tools/jEdit/src/jedit/DynamicTokenMarker.scala
src/Tools/jEdit/src/jedit/IsabelleHyperlinkSource.scala
src/Tools/jEdit/src/jedit/IsabelleSideKickParser.scala
src/Tools/jEdit/src/jedit/Isabelle_Encoding.scala
src/Tools/jEdit/src/jedit/OptionPane.scala
src/Tools/jEdit/src/jedit/OutputDockable.scala
src/Tools/jEdit/src/jedit/Plugin.scala
src/Tools/jEdit/src/jedit/ProverSetup.scala
src/Tools/jEdit/src/jedit/StateViewDockable.scala
src/Tools/jEdit/src/jedit/TheoryView.scala
src/Tools/jEdit/src/jedit/browse_version_dockable.scala
src/Tools/jEdit/src/jedit/document_overview.scala
src/Tools/jEdit/src/jedit/isabelle_encoding.scala
src/Tools/jEdit/src/jedit/isabelle_hyperlinks.scala
src/Tools/jEdit/src/jedit/isabelle_sidekick.scala
src/Tools/jEdit/src/jedit/option_pane.scala
src/Tools/jEdit/src/jedit/plugin.scala
src/Tools/jEdit/src/jedit/prover_setup.scala
src/Tools/jEdit/src/jedit/raw_output_dockable.scala
src/Tools/jEdit/src/jedit/results_dockable.scala
src/Tools/jEdit/src/jedit/token_marker.scala
src/Tools/jEdit/src/proofdocument/Change.scala
src/Tools/jEdit/src/proofdocument/ProofDocument.scala
src/Tools/jEdit/src/proofdocument/Token.scala
src/Tools/jEdit/src/proofdocument/change.scala
src/Tools/jEdit/src/proofdocument/command.scala
src/Tools/jEdit/src/proofdocument/markup_node.scala
src/Tools/jEdit/src/proofdocument/proof_document.scala
src/Tools/jEdit/src/proofdocument/prover.scala
src/Tools/jEdit/src/proofdocument/state.scala
src/Tools/jEdit/src/proofdocument/theory_view.scala
src/Tools/jEdit/src/proofdocument/token.scala
src/Tools/jEdit/src/prover/Command.scala
src/Tools/jEdit/src/prover/MarkupNode.scala
src/Tools/jEdit/src/prover/Prover.scala
src/Tools/jEdit/src/prover/State.scala
--- a/src/Tools/jEdit/src/jedit/BrowseVersionDockable.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Dockable window for navigating through the document-versions
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-import isabelle.proofdocument.Change
-
-import java.awt.Dimension
-import scala.swing.{ListView, FlowPanel}
-import scala.swing.event.ListSelectionChanged
-
-import org.gjt.sp.jedit.View
-import org.gjt.sp.jedit.gui.DockableWindowManager
-
-
-class BrowseVersionDockable(view: View, position: String) extends FlowPanel
-{
-  if (position == DockableWindowManager.FLOATING)
-    preferredSize = new Dimension(500, 250)
-
-  def prover_setup(): Option[ProverSetup] = Isabelle.prover_setup(view.getBuffer)
-  def get_versions() =
-    prover_setup() match {
-      case None => Nil
-      case Some(setup) => setup.theory_view.changes
-    }
-
-  val list = new ListView[Change]
-  list.fixedCellWidth = 500
-  list.listData = get_versions()
-  contents += list
-
-  listenTo(list.selection)
-  reactions += {
-    case ListSelectionChanged(source, range, false) =>
-        prover_setup().map(_.theory_view.set_version(list.listData(range.start)))
-    }
-
-  prover_setup.foreach(_.prover.document_change += (_ => list.listData = get_versions()))
-}
--- a/src/Tools/jEdit/src/jedit/Document_Overview.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Information on command status left of scrollbar (with panel)
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-import isabelle.prover.{Prover, Command}
-import isabelle.proofdocument.ProofDocument
-
-import javax.swing.{JPanel, ToolTipManager}
-import java.awt.event.{MouseAdapter, MouseEvent}
-import java.awt.{BorderLayout, Graphics, Dimension}
-
-import org.gjt.sp.jedit.gui.RolloverButton
-import org.gjt.sp.jedit.textarea.JEditTextArea
-import org.gjt.sp.jedit.buffer.JEditBuffer
-
-
-class Document_Overview(
-    prover: Prover,
-    text_area: JEditTextArea,
-    to_current: (ProofDocument, Int) => Int)
-  extends JPanel(new BorderLayout)
-{
-  private val WIDTH = 10
-  private val HEIGHT = 2
-
-  setRequestFocusEnabled(false)
-
-  addMouseListener(new MouseAdapter {
-    override def mousePressed(event: MouseEvent) {
-      val line = y_to_line(event.getY)
-      if (line >= 0 && line < text_area.getLineCount)
-        text_area.setCaretPosition(text_area.getLineStartOffset(line))
-    }
-  })
-
-  override def addNotify() {
-    super.addNotify()
-    ToolTipManager.sharedInstance.registerComponent(this)
-  }
-
-  override def removeNotify() {
-    super.removeNotify
-    ToolTipManager.sharedInstance.unregisterComponent(this)
-  }
-
-  override def getToolTipText(event: MouseEvent): String =
-  {
-    val buffer = text_area.getBuffer
-    val lineCount = buffer.getLineCount
-    val line = y_to_line(event.getY())
-    if (line >= 0 && line < text_area.getLineCount) "<html><b>TODO:</b><br>Tooltip</html>"
-    else ""
-  }
-
-  override def paintComponent(gfx: Graphics) {
-    super.paintComponent(gfx)
-    val buffer = text_area.getBuffer
-    val theory_view = Isabelle.prover_setup(buffer).get.theory_view
-    val doc = theory_view.current_document()
-
-    for (command <- doc.commands) {
-      val line1 = buffer.getLineOfOffset(to_current(doc, command.start(doc)))
-      val line2 = buffer.getLineOfOffset(to_current(doc, command.stop(doc))) + 1
-      val y = line_to_y(line1)
-      val height = HEIGHT * (line2 - line1)
-      gfx.setColor(TheoryView.choose_color(command, doc))
-      gfx.fillRect(0, y, getWidth - 1, height)
-    }
-  }
-
-  override def getPreferredSize = new Dimension(WIDTH, 0)
-
-  private def line_to_y(line: Int): Int =
-    (line * getHeight) / (text_area.getBuffer.getLineCount max text_area.getVisibleLines)
-
-  private def y_to_line(y: Int): Int =
-    (y * (text_area.getBuffer.getLineCount max text_area.getVisibleLines)) / getHeight
-}
\ No newline at end of file
--- a/src/Tools/jEdit/src/jedit/DynamicTokenMarker.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * include isabelle's command- and keyword-declarations
- * live in jEdits syntax-highlighting
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-
-import isabelle.prover.Prover
-import isabelle.Markup
-
-import org.gjt.sp.jedit.buffer.JEditBuffer
-import org.gjt.sp.jedit.syntax.{Token => JToken,
-  TokenMarker, TokenHandler, SyntaxStyle, ParserRuleSet}
-
-import java.awt.Color
-import java.awt.Font
-import javax.swing.text.Segment;
-
-
-object DynamicTokenMarker
-{
-  /* line context */
-
-  private val rule_set = new ParserRuleSet("isabelle", "MAIN")
-  private class LineContext(val line: Int, prev: LineContext)
-    extends TokenMarker.LineContext(rule_set, prev)
-
-
-  /* mapping to jEdit token types */
-  // TODO: as properties or CSS style sheet
-
-  private val choose_byte: Map[String, Byte] =
-  {
-    import JToken._
-    Map[String, Byte](
-      // logical entities
-      Markup.TCLASS -> LABEL,
-      Markup.TYCON -> LABEL,
-      Markup.FIXED_DECL -> LABEL,
-      Markup.FIXED -> LABEL,
-      Markup.CONST_DECL -> LABEL,
-      Markup.CONST -> LABEL,
-      Markup.FACT_DECL -> LABEL,
-      Markup.FACT -> LABEL,
-      Markup.DYNAMIC_FACT -> LABEL,
-      Markup.LOCAL_FACT_DECL -> LABEL,
-      Markup.LOCAL_FACT -> LABEL,
-      // inner syntax
-      Markup.TFREE -> LITERAL2,
-      Markup.FREE -> LITERAL2,
-      Markup.TVAR -> LITERAL3,
-      Markup.SKOLEM -> LITERAL3,
-      Markup.BOUND -> LITERAL3,
-      Markup.VAR -> LITERAL3,
-      Markup.NUM -> DIGIT,
-      Markup.FLOAT -> DIGIT,
-      Markup.XNUM -> DIGIT,
-      Markup.XSTR -> LITERAL4,
-      Markup.LITERAL -> LITERAL4,
-      Markup.INNER_COMMENT -> COMMENT1,
-      Markup.SORT -> FUNCTION,
-      Markup.TYP -> FUNCTION,
-      Markup.TERM -> FUNCTION,
-      Markup.PROP -> FUNCTION,
-      Markup.ATTRIBUTE -> FUNCTION,
-      Markup.METHOD -> FUNCTION,
-      // ML syntax
-      Markup.ML_KEYWORD -> KEYWORD2,
-      Markup.ML_IDENT -> NULL,
-      Markup.ML_TVAR -> LITERAL3,
-      Markup.ML_NUMERAL -> DIGIT,
-      Markup.ML_CHAR -> LITERAL1,
-      Markup.ML_STRING -> LITERAL1,
-      Markup.ML_COMMENT -> COMMENT1,
-      Markup.ML_MALFORMED -> INVALID,
-      // embedded source text
-      Markup.ML_SOURCE -> COMMENT4,
-      Markup.DOC_SOURCE -> COMMENT4,
-      Markup.ANTIQ -> COMMENT4,
-      Markup.ML_ANTIQ -> COMMENT4,
-      Markup.DOC_ANTIQ -> COMMENT4,
-      // outer syntax
-      Markup.IDENT -> NULL,
-      Markup.COMMAND -> OPERATOR,
-      Markup.KEYWORD -> KEYWORD4,
-      Markup.VERBATIM -> COMMENT3,
-      Markup.COMMENT -> COMMENT1,
-      Markup.CONTROL -> COMMENT3,
-      Markup.MALFORMED -> INVALID,
-      Markup.STRING -> LITERAL3,
-      Markup.ALTSTRING -> LITERAL1
-    ).withDefaultValue(NULL)
-  }
-
-  def choose_color(kind: String, styles: Array[SyntaxStyle]): Color =
-    styles(choose_byte(kind)).getForegroundColor
-}
-
-
-class DynamicTokenMarker(buffer: JEditBuffer, prover: Prover)
-  extends TokenMarker
-{
-  override def markTokens(prev: TokenMarker.LineContext,
-      handler: TokenHandler, line_segment: Segment): TokenMarker.LineContext =
-  {
-    val previous = prev.asInstanceOf[DynamicTokenMarker.LineContext]
-    val line = if (prev == null) 0 else previous.line + 1
-    val context = new DynamicTokenMarker.LineContext(line, previous)
-    val start = buffer.getLineStartOffset(line)
-    val stop = start + line_segment.count
-
-    val theory_view = Isabelle.prover_setup(buffer).get.theory_view
-    val document = theory_view.current_document()
-    def to: Int => Int = theory_view.to_current(document, _)
-    def from: Int => Int = theory_view.from_current(document, _)
-
-    var next_x = start
-    var cmd = document.command_at(from(start))
-    while (cmd.isDefined && cmd.get.start(document) < from(stop)) {
-      val command = cmd.get
-      for {
-        markup <- command.highlight(document).flatten
-        command_start = command.start(document)
-        abs_start = to(command_start + markup.start)
-        abs_stop = to(command_start + markup.stop)
-        if (abs_stop > start)
-        if (abs_start < stop)
-        byte = DynamicTokenMarker.choose_byte(markup.info.toString)
-        token_start = (abs_start - start) max 0
-        token_length =
-          (abs_stop - abs_start) -
-          ((start - abs_start) max 0) -
-          ((abs_stop - stop) max 0)
-      } {
-        if (start + token_start > next_x)
-          handler.handleToken(line_segment, 1,
-            next_x - start, start + token_start - next_x, context)
-        handler.handleToken(line_segment, byte,
-          token_start, token_length, context)
-        next_x = start + token_start + token_length
-      }
-      cmd = document.commands.next(command)
-    }
-    if (next_x < stop)
-      handler.handleToken(line_segment, 1, next_x - start, stop - next_x, context)
-
-    handler.handleToken(line_segment, JToken.END, line_segment.count, 0, context)
-    handler.setLineContext(context)
-    return context
-  }
-}
--- a/src/Tools/jEdit/src/jedit/IsabelleHyperlinkSource.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Hyperlink setup for Isabelle proof documents
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-import java.io.File
-
-import gatchan.jedit.hyperlinks.Hyperlink
-import gatchan.jedit.hyperlinks.HyperlinkSource
-import gatchan.jedit.hyperlinks.AbstractHyperlink
-
-import org.gjt.sp.jedit.View
-import org.gjt.sp.jedit.jEdit
-import org.gjt.sp.jedit.Buffer
-import org.gjt.sp.jedit.TextUtilities
-
-import isabelle.prover.Command
-
-
-class InternalHyperlink(start: Int, end: Int, line: Int, ref_offset: Int)
-  extends AbstractHyperlink(start, end, line, "")
-{
-  override def click(view: View) {
-    view.getTextArea.moveCaretPosition(ref_offset)
-  }
-}
-
-class ExternalHyperlink(start: Int, end: Int, line: Int, ref_file: String, ref_line: Int)
-  extends AbstractHyperlink(start, end, line, "")
-{
-  override def click(view: View) = {
-    Isabelle.system.source_file(ref_file) match {
-      case None => System.err.println("Could not find source file " + ref_file)
-      case Some(file) =>
-        jEdit.openFiles(view, file.getParent, Array(file.getName, "+line:" + ref_line))
-    }
-  }
-}
-
-class IsabelleHyperlinkSource extends HyperlinkSource
-{
-	def getHyperlink(buffer: Buffer, original_offset: Int): Hyperlink = {
-    val prover = Isabelle.prover_setup(buffer).map(_.prover)
-    val theory_view_opt = Isabelle.prover_setup(buffer).map(_.theory_view)
-    if (prover.isEmpty || theory_view_opt.isEmpty) null
-    else if (prover.get == null || theory_view_opt.get == null) null
-    else {
-      val theory_view = theory_view_opt.get
-      val document = theory_view.current_document()
-      val offset = theory_view.from_current(document, original_offset)
-      document.command_at(offset) match {
-        case Some(command) =>
-          command.ref_at(document, offset - command.start(document)) match {
-            case Some(ref) =>
-              val command_start = command.start(document)
-              val begin = theory_view.to_current(document, command_start + ref.start)
-              val line = buffer.getLineOfOffset(begin)
-              val end = theory_view.to_current(document, command_start + ref.stop)
-              ref.info match {
-                case Command.RefInfo(Some(ref_file), Some(ref_line), _, _) =>
-                  new ExternalHyperlink(begin, end, line, ref_file, ref_line)
-                case Command.RefInfo(_, _, Some(id), Some(offset)) =>
-                  prover.get.command(id) match {
-                    case Some(ref_cmd) =>
-                      new InternalHyperlink(begin, end, line,
-                        theory_view.to_current(document, ref_cmd.start(document) + offset - 1))
-                    case None => null
-                  }
-                case _ => null
-              }
-            case None => null
-          }
-        case None => null
-      }
-    }
-  }
-}
--- a/src/Tools/jEdit/src/jedit/IsabelleSideKickParser.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * SideKick parser for Isabelle proof documents
- *
- * @author Fabian Immler, TU Munich
- * @author Makarius
- */
-
-package isabelle.jedit
-
-import scala.collection.Set
-import scala.collection.immutable.TreeSet
-
-import javax.swing.tree.DefaultMutableTreeNode
-import javax.swing.text.Position
-import javax.swing.Icon
-
-import org.gjt.sp.jedit.{Buffer, EditPane, TextUtilities, View}
-import errorlist.DefaultErrorSource
-import sidekick.{SideKickParser, SideKickParsedData, SideKickCompletion, IAsset}
-
-import isabelle.prover.{Command, Markup_Node}
-import isabelle.proofdocument.ProofDocument
-
-
-class IsabelleSideKickParser extends SideKickParser("isabelle")
-{
-  /* parsing */
-
-  @volatile private var stopped = false
-  override def stop() = { stopped = true }
-
-  def parse(buffer: Buffer, error_source: DefaultErrorSource): SideKickParsedData =
-  {
-    implicit def int_to_pos(offset: Int): Position =
-      new Position { def getOffset = offset; override def toString = offset.toString }
-
-    stopped = false
-
-    val data = new SideKickParsedData(buffer.getName)
-    val root = data.root
-    data.getAsset(root).setEnd(buffer.getLength)
-
-    val prover_setup = Isabelle.prover_setup(buffer)
-    if (prover_setup.isDefined) {
-      val document = prover_setup.get.theory_view.current_document()
-      for (command <- document.commands if !stopped) {
-        root.add(command.markup_root(document).swing_tree((node: Markup_Node) =>
-            {
-              val content = command.content(node.start, node.stop)
-              val command_start = command.start(document)
-              val id = command.id
-
-              new DefaultMutableTreeNode(new IAsset {
-                override def getIcon: Icon = null
-                override def getShortString: String = content
-                override def getLongString: String = node.info.toString
-                override def getName: String = id
-                override def setName(name: String) = ()
-                override def setStart(start: Position) = ()
-                override def getStart: Position = command_start + node.start
-                override def setEnd(end: Position) = ()
-                override def getEnd: Position = command_start + node.stop
-                override def toString = id + ": " + content + "[" + getStart + " - " + getEnd + "]"
-              })
-            }))
-      }
-      if (stopped) root.add(new DefaultMutableTreeNode("<parser stopped>"))
-    }
-    else root.add(new DefaultMutableTreeNode("<buffer inactive>"))
-
-    data
-  }
-
-
-  /* completion */
-
-  override def supportsCompletion = true
-  override def canCompleteAnywhere = true
-
-  override def complete(pane: EditPane, caret: Int): SideKickCompletion =
-  {
-    val buffer = pane.getBuffer
-
-    val line = buffer.getLineOfOffset(caret)
-    val start = buffer.getLineStartOffset(line)
-    val text = buffer.getSegment(start, caret - start)
-
-    val completion =
-      Isabelle.prover_setup(buffer).map(_.prover.completion()).getOrElse(Isabelle.completion)
-
-    completion.complete(text) match {
-      case None => null
-      case Some((word, cs)) =>
-        val ds =
-          if (Isabelle_Encoding.is_active(buffer))
-            cs.map(Isabelle.system.symbols.decode(_)).sort(Completion.length_ord _)
-          else cs
-        new SideKickCompletion(pane.getView, word, ds.toArray.asInstanceOf[Array[Object]]) { }
-    }
-  }
-
-}
--- a/src/Tools/jEdit/src/jedit/Isabelle_Encoding.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Isabelle encoding -- based on utf-8
- *
- * @author Makarius
- */
-
-package isabelle.jedit
-
-import org.gjt.sp.jedit.io.Encoding
-import org.gjt.sp.jedit.buffer.JEditBuffer
-
-import java.nio.charset.{Charset, CharsetDecoder, CodingErrorAction}
-import java.io.{InputStream, OutputStream, Reader, Writer, InputStreamReader, OutputStreamWriter,
-  CharArrayReader, ByteArrayOutputStream}
-
-import scala.io.{Source, BufferedSource}
-
-
-object Isabelle_Encoding
-{
-  val NAME = "UTF-8-Isabelle"
-
-  def is_active(buffer: JEditBuffer): Boolean =
-    buffer.getProperty(JEditBuffer.ENCODING).asInstanceOf[String] == NAME
-}
-
-class Isabelle_Encoding extends Encoding
-{
-  private val charset = Charset.forName(Isabelle_System.charset)
-  private val BUFSIZE = 32768
-
-  private def text_reader(in: InputStream, decoder: CharsetDecoder): Reader =
-  {
-    def source(): Source =
-      BufferedSource.fromInputStream(in, decoder, BUFSIZE, { () => source() })
-    new CharArrayReader(Isabelle.symbols.decode(source.mkString).toArray)
-  }
-
-	override def getTextReader(in: InputStream): Reader =
-    text_reader(in, charset.newDecoder())
-
-	override def getPermissiveTextReader(in: InputStream): Reader =
-	{
-		val decoder = charset.newDecoder()
-		decoder.onMalformedInput(CodingErrorAction.REPLACE)
-		decoder.onUnmappableCharacter(CodingErrorAction.REPLACE)
-		text_reader(in, decoder)
-	}
-
-  override def getTextWriter(out: OutputStream): Writer =
-  {
-    val buffer = new ByteArrayOutputStream(BUFSIZE) {
-      override def flush()
-      {
-        val text = Isabelle.symbols.encode(toString(Isabelle_System.charset))
-        out.write(text.getBytes(Isabelle_System.charset))
-        out.flush()
-      }
-      override def close() { out.close() }
-    }
-		new OutputStreamWriter(buffer, charset.newEncoder())
-  }
-}
--- a/src/Tools/jEdit/src/jedit/OptionPane.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Editor pane for plugin options
- *
- * @author Johannes Hölzl, TU Munich
- */
-
-package isabelle.jedit
-
-import javax.swing.{JComboBox, JSpinner}
-
-import org.gjt.sp.jedit.AbstractOptionPane
-
-
-class OptionPane extends AbstractOptionPane("isabelle")
-{
-  private val logic_name = new JComboBox()
-  private val font_size = new JSpinner()
-
-  override def _init()
-  {
-    addComponent(Isabelle.Property("logic.title"), {
-      for (name <- Isabelle.system.find_logics()) {
-        logic_name.addItem(name)
-        if (name == Isabelle.Property("logic"))
-          logic_name.setSelectedItem(name)
-      }
-      logic_name
-    })
-    addComponent(Isabelle.Property("font-size.title"), {
-      font_size.setValue(Isabelle.Int_Property("font-size"))
-      font_size
-    })
-  }
-
-  override def _save()
-  {
-    val logic = logic_name.getSelectedItem.asInstanceOf[String]
-    Isabelle.Property("logic") = logic
-
-    val size = font_size.getValue().asInstanceOf[Int]
-    Isabelle.Int_Property("font-size") = size
-  }
-}
--- a/src/Tools/jEdit/src/jedit/OutputDockable.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * Dockable window for raw process output
- *
- * @author Fabian Immler, TU Munich
- * @author Johannes Hölzl, TU Munich
- */
-
-package isabelle.jedit
-
-
-import java.awt.{Dimension, Graphics, GridLayout}
-import javax.swing.{JPanel, JTextArea, JScrollPane}
-
-import org.gjt.sp.jedit.View
-import org.gjt.sp.jedit.gui.DockableWindowManager
-
-
-class OutputDockable(view : View, position : String) extends JPanel {
-
-  if (position == DockableWindowManager.FLOATING)
-    setPreferredSize(new Dimension(500, 250))
-
-  setLayout(new GridLayout(1, 1))
-  add(new JScrollPane(new JTextArea))
-
-  def set_text(output_text_view: JTextArea) {
-    removeAll()
-    add(new JScrollPane(output_text_view))
-    revalidate()
-  }
-}
--- a/src/Tools/jEdit/src/jedit/Plugin.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * Main Isabelle/jEdit plugin setup
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-
-import java.io.{FileInputStream, IOException}
-import java.awt.Font
-import javax.swing.JScrollPane
-
-import scala.collection.mutable
-
-import isabelle.prover.{Prover, Command}
-import isabelle.proofdocument.ProofDocument
-import isabelle.Isabelle_System
-
-import org.gjt.sp.jedit.{jEdit, EBMessage, EBPlugin, Buffer, EditPane, ServiceManager, View}
-import org.gjt.sp.jedit.buffer.JEditBuffer
-import org.gjt.sp.jedit.textarea.JEditTextArea
-import org.gjt.sp.jedit.msg.{EditPaneUpdate, PropertiesChanged}
-
-
-object Isabelle
-{
-  /* name */
-
-  val NAME = "Isabelle"
-
-
-  /* properties */
-
-  val OPTION_PREFIX = "options.isabelle."
-
-  object Property
-  {
-    def apply(name: String): String = jEdit.getProperty(OPTION_PREFIX + name)
-    def update(name: String, value: String) = jEdit.setProperty(OPTION_PREFIX + name, value)
-  }
-
-  object Boolean_Property
-  {
-    def apply(name: String): Boolean = jEdit.getBooleanProperty(OPTION_PREFIX + name)
-    def update(name: String, value: Boolean) = jEdit.setBooleanProperty(OPTION_PREFIX + name, value)
-  }
-
-  object Int_Property
-  {
-    def apply(name: String): Int = jEdit.getIntegerProperty(OPTION_PREFIX + name)
-    def update(name: String, value: Int) = jEdit.setIntegerProperty(OPTION_PREFIX + name, value)
-  }
-
-
-  /* Isabelle system instance */
-
-  var system: Isabelle_System = null
-  def symbols = system.symbols
-  lazy val completion = new Completion + symbols
-
-
-  /* settings */
-
-  def default_logic(): String =
-  {
-    val logic = Isabelle.Property("logic")
-    if (logic != null) logic
-    else system.getenv_strict("ISABELLE_LOGIC")
-  }
-
-
-  /* plugin instance */
-
-  var plugin: Plugin = null
-
-
-  /* running provers */
-
-  def prover_setup(buffer: JEditBuffer) = plugin.prover_setup(buffer)
-}
-
-
-class Plugin extends EBPlugin
-{
-  /* event buses */
-
-  val state_update = new Event_Bus[Command]
-
-
-  /* selected state */
-
-  private var _selected_state: Command = null
-  def selected_state = _selected_state
-  def selected_state_=(state: Command) { _selected_state = state; state_update.event(state) }
-
-
-  /* mapping buffer <-> prover */
-
-  private val mapping = new mutable.HashMap[JEditBuffer, ProverSetup]
-
-  private def install(view: View)
-  {
-    val buffer = view.getBuffer
-    val prover_setup = new ProverSetup(buffer)
-    mapping.update(buffer, prover_setup)
-    prover_setup.activate(view)
-  }
-
-  private def uninstall(view: View) =
-    mapping.removeKey(view.getBuffer).get.deactivate
-
-  def switch_active (view: View) =
-    if (mapping.isDefinedAt(view.getBuffer)) uninstall(view)
-    else install(view)
-
-  def prover_setup(buffer: JEditBuffer): Option[ProverSetup] = mapping.get(buffer)
-  def is_active (buffer: JEditBuffer) = mapping.isDefinedAt(buffer)
-
-
-  /* main plugin plumbing */
-
-  override def handleMessage(msg: EBMessage)
-  {
-    msg match {
-      case epu: EditPaneUpdate =>
-        val buffer = epu.getEditPane.getBuffer
-        epu.getWhat match {
-          case EditPaneUpdate.BUFFER_CHANGED =>
-            (mapping get buffer) map (_.theory_view.activate)
-          case EditPaneUpdate.BUFFER_CHANGING =>
-            if (buffer != null)
-              (mapping get buffer) map (_.theory_view.deactivate)
-          case _ =>
-        }
-      case _ =>
-    }
-  }
-
-  override def start()
-  {
-    Isabelle.plugin = this
-    Isabelle.system = new Isabelle_System
-    if (!Isabelle.system.register_fonts())
-      System.err.println("Failed to register Isabelle fonts")
-  }
-
-  override def stop()
-  {
-    // TODO: proper cleanup
-    Isabelle.system = null
-    Isabelle.plugin = null
-  }
-}
--- a/src/Tools/jEdit/src/jedit/ProverSetup.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Independent prover sessions for each buffer
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-
-import org.gjt.sp.jedit.{Buffer, View}
-
-import isabelle.prover.Prover
-
-
-class ProverSetup(buffer: Buffer)
-{
-  var prover: Prover = null
-  var theory_view: TheoryView = null
-
-  def activate(view: View)
-  {
-    // TheoryView starts prover
-    theory_view = new TheoryView(view.getTextArea)
-    prover = theory_view.prover
-
-    theory_view.activate()
-    prover.begin_document(buffer.getName)
-  }
-
-  def deactivate()
-  {
-    theory_view.deactivate
-    prover.stop
-  }
-}
--- a/src/Tools/jEdit/src/jedit/StateViewDockable.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * Dockable window with rendered state output
- *
- * @author Fabian Immler, TU Munich
- * @author Johannes Hölzl, TU Munich
- */
-
-package isabelle.jedit
-
-import isabelle.XML
-
-import java.io.StringReader
-import java.awt.{BorderLayout, Dimension}
-
-import javax.swing.{JButton, JPanel, JScrollPane}
-
-import java.util.logging.{Logger, Level}
-
-import org.lobobrowser.html.parser._
-import org.lobobrowser.html.test._
-import org.lobobrowser.html.gui._
-import org.lobobrowser.html._
-import org.lobobrowser.html.style.CSSUtilities
-import org.lobobrowser.html.domimpl.{HTMLDocumentImpl, HTMLStyleElementImpl, NodeImpl}
-
-import org.gjt.sp.jedit.jEdit
-import org.gjt.sp.jedit.View
-import org.gjt.sp.jedit.gui.DockableWindowManager
-import org.gjt.sp.jedit.textarea.AntiAlias
-
-import scala.io.Source
-
-
-class StateViewDockable(view : View, position : String) extends JPanel {
-
-  // outer panel
-  if (position == DockableWindowManager.FLOATING)
-    setPreferredSize(new Dimension(500, 250))
-  setLayout(new BorderLayout)
-
-
-  // global logging
-  
-  Logger.getLogger("org.lobobrowser").setLevel(Level.WARNING)
-
-
-  // document template with styles
-
-  private def try_file(name: String): String =
-  {
-    val file = Isabelle.system.platform_file(name)
-    if (file.exists) Source.fromFile(file).mkString else ""
-  }
-
-
-  // HTML panel
-
-  val panel = new HtmlPanel
-  val ucontext = new SimpleUserAgentContext
-  val rcontext = new SimpleHtmlRendererContext(panel, ucontext)
-  val doc = {
-    val builder = new DocumentBuilderImpl(ucontext, rcontext)
-    builder.parse(new InputSourceImpl(new StringReader(
-      """<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<style media="all" type="text/css">
-""" +
-  try_file("$ISABELLE_HOME/lib/html/isabelle.css") + "\n" +
-"""
-body {
-  font-family: IsabelleText;
-  font-size: 14pt;
-}
-""" +
-  try_file("$ISABELLE_HOME_USER/etc/isabelle.css") + "\n" +
-"""
-</style>
-</head>
-</html>
-""")))
-  }
-
-  val empty_body = XML.document_node(doc, XML.elem(HTML.BODY))
-  doc.appendChild(empty_body)
-
-  panel.setDocument(doc, rcontext)
-  add(panel, BorderLayout.CENTER)
-
-  
-  // register for state-view
-  Isabelle.plugin.state_update += (cmd => {
-    val theory_view = Isabelle.prover_setup(view.getBuffer).get.theory_view
-
-    Swing_Thread.later {
-      val node =
-        if (cmd == null) empty_body
-        else {
-          val xml = XML.elem(HTML.BODY,
-            cmd.results(theory_view.current_document).
-              map((t: XML.Tree) => XML.elem(HTML.PRE, HTML.spans(t))))
-          XML.document_node(doc, xml)
-        }
-      doc.removeChild(doc.getLastChild())
-      doc.appendChild(node)
-      panel.delayedRelayout(node.asInstanceOf[NodeImpl])
-    }
-  })
-}
--- a/src/Tools/jEdit/src/jedit/TheoryView.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,327 +0,0 @@
-/*
- * jEdit text area as document text source
- *
- * @author Fabian Immler, TU Munich
- * @author Johannes Hölzl, TU Munich
- * @author Makarius
- */
-
-package isabelle.jedit
-
-import scala.actors.Actor, Actor._
-import scala.collection.mutable
-
-import isabelle.proofdocument.{ProofDocument, Change, Edit, Insert, Remove}
-import isabelle.prover.{Prover, Command}
-
-import java.awt.{Color, Graphics2D}
-import javax.swing.event.{CaretListener, CaretEvent}
-
-import org.gjt.sp.jedit.buffer.{BufferListener, JEditBuffer}
-import org.gjt.sp.jedit.textarea.{JEditTextArea, TextAreaExtension, TextAreaPainter}
-import org.gjt.sp.jedit.syntax.{ModeProvider, SyntaxStyle}
-
-
-object TheoryView
-{
-  def choose_color(command: Command, doc: ProofDocument): Color =
-  {
-    command.status(doc) match {
-      case Command.Status.UNPROCESSED => new Color(255, 228, 225)
-      case Command.Status.FINISHED => new Color(234, 248, 255)
-      case Command.Status.FAILED => new Color(255, 106, 106)
-      case _ => Color.red
-    }
-  }
-}
-
-
-class TheoryView(text_area: JEditTextArea)
-{
-  private val buffer = text_area.getBuffer
-
-
-  /* prover setup */
-
-  val prover: Prover = new Prover(Isabelle.system, Isabelle.default_logic())
-
-  prover.command_change += ((command: Command) =>
-    if (current_document().commands.contains(command))
-      Swing_Thread.later {
-        // FIXME proper handling of buffer vs. text areas
-        // repaint if buffer is active
-        if (text_area.getBuffer == buffer) {
-          update_syntax(command)
-          invalidate_line(command)
-          overview.repaint()
-        }
-      })
-
-
-  /* changes vs. edits */
-
-  private val change_0 = new Change(prover.document_0.id, None, Nil)
-  private var _changes = List(change_0)   // owned by Swing/AWT thread
-  def changes = _changes
-  private var current_change = change_0
-
-  private val edits = new mutable.ListBuffer[Edit]   // owned by Swing thread
-
-  private val edits_delay = Swing_Thread.delay_last(300) {
-    if (!edits.isEmpty) {
-      val change = new Change(Isabelle.system.id(), Some(current_change), edits.toList)
-      _changes ::= change
-      prover.input(change)
-      current_change = change
-      edits.clear
-    }
-  }
-
-
-  /* buffer_listener */
-
-  private val buffer_listener = new BufferListener {
-    override def preContentInserted(buffer: JEditBuffer,
-      start_line: Int, offset: Int, num_lines: Int, length: Int)
-    {
-      edits += Insert(offset, buffer.getText(offset, length))
-      edits_delay()
-    }
-
-    override def preContentRemoved(buffer: JEditBuffer,
-      start_line: Int, start: Int, num_lines: Int, removed_length: Int)
-    {
-      edits += Remove(start, buffer.getText(start, removed_length))
-      edits_delay()
-    }
-
-    override def contentInserted(buffer: JEditBuffer,
-      start_line: Int, offset: Int, num_lines: Int, length: Int) { }
-
-    override def contentRemoved(buffer: JEditBuffer,
-      start_line: Int, offset: Int, num_lines: Int, length: Int) { }
-
-    override def bufferLoaded(buffer: JEditBuffer) { }
-    override def foldHandlerChanged(buffer: JEditBuffer) { }
-    override def foldLevelChanged(buffer: JEditBuffer, start_line: Int, end_line: Int) { }
-    override def transactionComplete(buffer: JEditBuffer) { }
-  }
-
-
-  /* text_area_extension */
-
-  private val text_area_extension = new TextAreaExtension {
-    override def paintValidLine(gfx: Graphics2D,
-      screen_line: Int, physical_line: Int, start: Int, end: Int, y: Int)
-    {
-      val document = current_document()
-      def from_current(pos: Int) = TheoryView.this.from_current(document, pos)
-      def to_current(pos: Int) = TheoryView.this.to_current(document, pos)
-      val saved_color = gfx.getColor
-
-      val metrics = text_area.getPainter.getFontMetrics
-
-      // encolor phase
-      var cmd = document.command_at(from_current(start))
-      while (cmd.isDefined && cmd.get.start(document) < end) {
-        val e = cmd.get
-        val begin = start max to_current(e.start(document))
-        val finish = (end - 1) min to_current(e.stop(document))
-        encolor(gfx, y, metrics.getHeight, begin, finish,
-          TheoryView.choose_color(e, document), true)
-        cmd = document.commands.next(e)
-      }
-
-      gfx.setColor(saved_color)
-    }
-
-    override def getToolTipText(x: Int, y: Int): String =
-    {
-      val document = current_document()
-      val offset = from_current(document, text_area.xyToOffset(x, y))
-      document.command_at(offset) match {
-        case Some(cmd) =>
-          document.token_start(cmd.tokens.first)
-          cmd.type_at(document, offset - cmd.start(document)).getOrElse(null)
-        case None => null
-      }
-    }
-  }
-
-
-  /* activation */
-
-  private val overview = new Document_Overview(prover, text_area, to_current)
-
-  private val selected_state_controller = new CaretListener {
-    override def caretUpdate(e: CaretEvent) {
-      val doc = current_document()
-      doc.command_at(e.getDot) match {
-        case Some(cmd)
-          if (doc.token_start(cmd.tokens.first) <= e.getDot &&
-            Isabelle.plugin.selected_state != cmd) =>
-          Isabelle.plugin.selected_state = cmd
-        case _ =>
-      }
-    }
-  }
-
-  def activate() {
-    text_area.addCaretListener(selected_state_controller)
-    text_area.addLeftOfScrollBar(overview)
-    text_area.getPainter.
-      addExtension(TextAreaPainter.LINE_BACKGROUND_LAYER + 1, text_area_extension)
-    buffer.setTokenMarker(new DynamicTokenMarker(buffer, prover))
-    buffer.addBufferListener(buffer_listener)
-
-    val dockable =
-      text_area.getView.getDockableWindowManager.getDockable("isabelle-output")
-    if (dockable != null) {
-      val output_dockable = dockable.asInstanceOf[OutputDockable]
-      val output_text_view = prover.output_text_view
-      output_dockable.set_text(output_text_view)
-    }
-
-    buffer.propertiesChanged()
-  }
-
-  def deactivate() {
-    buffer.setTokenMarker(buffer.getMode.getTokenMarker)
-    buffer.removeBufferListener(buffer_listener)
-    text_area.getPainter.removeExtension(text_area_extension)
-    text_area.removeLeftOfScrollBar(overview)
-    text_area.removeCaretListener(selected_state_controller)
-  }
-
-
-  /* history of changes */
-
-  private def doc_or_pred(c: Change): ProofDocument =
-    prover.document(c.id).getOrElse(doc_or_pred(c.parent.get))
-
-  def current_document() = doc_or_pred(current_change)
-
-
-  /* update to desired version */
-
-  def set_version(goal: Change) {
-    // changes in buffer must be ignored
-    buffer.removeBufferListener(buffer_listener)
-
-    def apply(change: Change): Unit = change.edits.foreach {
-      case Insert(start, text) => buffer.insert(start, text)
-      case Remove(start, text) => buffer.remove(start, text.length)
-    }
-
-    def unapply(change: Change): Unit = change.edits.reverse.foreach {
-      case Insert(start, text) => buffer.remove(start, text.length)
-      case Remove(start, text) => buffer.insert(start, text)
-    }
-
-    // undo/redo changes
-    val ancs_current = current_change.ancestors
-    val ancs_goal = goal.ancestors
-    val paired = ancs_current.reverse zip ancs_goal.reverse
-    def last_common[A](xs: List[(A, A)]): Option[A] = {
-      xs match {
-        case (x, y) :: xs =>
-          if (x == y)
-            xs match {
-              case (a, b) :: ys =>
-                if (a == b) last_common(xs)
-                else Some(x)
-              case _ => Some(x)
-            }
-          else None
-        case _ => None
-      }
-    }
-    val common_anc = last_common(paired).get
-
-    ancs_current.takeWhile(_ != common_anc) map unapply
-    ancs_goal.takeWhile(_ != common_anc).reverse map apply
-
-    current_change = goal
-    // invoke repaint
-    buffer.propertiesChanged()
-    invalidate_all()
-    overview.repaint()
-
-    // track changes in buffer
-    buffer.addBufferListener(buffer_listener)
-  }
-
-
-  /* transforming offsets */
-
-  private def changes_from(doc: ProofDocument): List[Edit] =
-    List.flatten(current_change.ancestors(_.id == doc.id).reverse.map(_.edits)) :::
-      edits.toList
-
-  def from_current(doc: ProofDocument, offset: Int): Int =
-    (offset /: changes_from(doc).reverse) ((i, change) => change before i)
-
-  def to_current(doc: ProofDocument, offset: Int): Int =
-    (offset /: changes_from(doc)) ((i, change) => change after i)
-
-
-  private def lines_of_command(cmd: Command) =
-  {
-    val document = current_document()
-    (buffer.getLineOfOffset(to_current(document, cmd.start(document))),
-     buffer.getLineOfOffset(to_current(document, cmd.stop(document))))
-  }
-
-
-  /* (re)painting */
-
-  private val update_delay = Swing_Thread.delay_first(500) { buffer.propertiesChanged() }
-
-  private def update_syntax(cmd: Command) {
-    val (line1, line2) = lines_of_command(cmd)
-    if (line2 >= text_area.getFirstLine &&
-      line1 <= text_area.getFirstLine + text_area.getVisibleLines)
-        update_delay()
-  }
-
-  private def invalidate_line(cmd: Command) =
-  {
-    val (start, stop) = lines_of_command(cmd)
-    text_area.invalidateLineRange(start, stop)
-
-    if (Isabelle.plugin.selected_state == cmd)
-      Isabelle.plugin.selected_state = cmd  // update State view
-  }
-
-  private def invalidate_all() =
-    text_area.invalidateLineRange(text_area.getFirstPhysicalLine,
-      text_area.getLastPhysicalLine)
-
-  private def encolor(gfx: Graphics2D,
-    y: Int, height: Int, begin: Int, finish: Int, color: Color, fill: Boolean)
-  {
-    val start = text_area.offsetToXY(begin)
-    val stop =
-      if (finish < buffer.getLength) text_area.offsetToXY(finish)
-      else {
-        val p = text_area.offsetToXY(finish - 1)
-        val metrics = text_area.getPainter.getFontMetrics
-        p.x = p.x + (metrics.charWidth(' ') max metrics.getMaxAdvance)
-        p
-      }
-
-    if (start != null && stop != null) {
-      gfx.setColor(color)
-      if (fill) gfx.fillRect(start.x, y, stop.x - start.x, height)
-      else gfx.drawRect(start.x, y, stop.x - start.x, height)
-    }
-  }
-
-
-  /* init */
-
-  prover.start()
-
-  edits += Insert(0, buffer.getText(0, buffer.getLength))
-  edits_delay()
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/browse_version_dockable.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,43 @@
+/*
+ * Dockable window for navigating through the document-versions
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+import isabelle.proofdocument.Change
+
+import java.awt.Dimension
+import scala.swing.{ListView, FlowPanel}
+import scala.swing.event.ListSelectionChanged
+
+import org.gjt.sp.jedit.View
+import org.gjt.sp.jedit.gui.DockableWindowManager
+
+
+class BrowseVersionDockable(view: View, position: String) extends FlowPanel
+{
+  if (position == DockableWindowManager.FLOATING)
+    preferredSize = new Dimension(500, 250)
+
+  def prover_setup(): Option[ProverSetup] = Isabelle.prover_setup(view.getBuffer)
+  def get_versions() =
+    prover_setup() match {
+      case None => Nil
+      case Some(setup) => setup.theory_view.changes
+    }
+
+  val list = new ListView[Change]
+  list.fixedCellWidth = 500
+  list.listData = get_versions()
+  contents += list
+
+  listenTo(list.selection)
+  reactions += {
+    case ListSelectionChanged(source, range, false) =>
+        prover_setup().map(_.theory_view.set_version(list.listData(range.start)))
+    }
+
+  prover_setup.foreach(_.prover.document_change += (_ => list.listData = get_versions()))
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/document_overview.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,82 @@
+/*
+ * Information on command status left of scrollbar (with panel)
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+import isabelle.prover.{Prover, Command}
+import isabelle.proofdocument.ProofDocument
+
+import javax.swing.{JPanel, ToolTipManager}
+import java.awt.event.{MouseAdapter, MouseEvent}
+import java.awt.{BorderLayout, Graphics, Dimension}
+
+import org.gjt.sp.jedit.gui.RolloverButton
+import org.gjt.sp.jedit.textarea.JEditTextArea
+import org.gjt.sp.jedit.buffer.JEditBuffer
+
+
+class Document_Overview(
+    prover: Prover,
+    text_area: JEditTextArea,
+    to_current: (ProofDocument, Int) => Int)
+  extends JPanel(new BorderLayout)
+{
+  private val WIDTH = 10
+  private val HEIGHT = 2
+
+  setRequestFocusEnabled(false)
+
+  addMouseListener(new MouseAdapter {
+    override def mousePressed(event: MouseEvent) {
+      val line = y_to_line(event.getY)
+      if (line >= 0 && line < text_area.getLineCount)
+        text_area.setCaretPosition(text_area.getLineStartOffset(line))
+    }
+  })
+
+  override def addNotify() {
+    super.addNotify()
+    ToolTipManager.sharedInstance.registerComponent(this)
+  }
+
+  override def removeNotify() {
+    super.removeNotify
+    ToolTipManager.sharedInstance.unregisterComponent(this)
+  }
+
+  override def getToolTipText(event: MouseEvent): String =
+  {
+    val buffer = text_area.getBuffer
+    val lineCount = buffer.getLineCount
+    val line = y_to_line(event.getY())
+    if (line >= 0 && line < text_area.getLineCount) "<html><b>TODO:</b><br>Tooltip</html>"
+    else ""
+  }
+
+  override def paintComponent(gfx: Graphics) {
+    super.paintComponent(gfx)
+    val buffer = text_area.getBuffer
+    val theory_view = Isabelle.prover_setup(buffer).get.theory_view
+    val doc = theory_view.current_document()
+
+    for (command <- doc.commands) {
+      val line1 = buffer.getLineOfOffset(to_current(doc, command.start(doc)))
+      val line2 = buffer.getLineOfOffset(to_current(doc, command.stop(doc))) + 1
+      val y = line_to_y(line1)
+      val height = HEIGHT * (line2 - line1)
+      gfx.setColor(TheoryView.choose_color(command, doc))
+      gfx.fillRect(0, y, getWidth - 1, height)
+    }
+  }
+
+  override def getPreferredSize = new Dimension(WIDTH, 0)
+
+  private def line_to_y(line: Int): Int =
+    (line * getHeight) / (text_area.getBuffer.getLineCount max text_area.getVisibleLines)
+
+  private def y_to_line(y: Int): Int =
+    (y * (text_area.getBuffer.getLineCount max text_area.getVisibleLines)) / getHeight
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/isabelle_encoding.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,63 @@
+/*
+ * Isabelle encoding -- based on utf-8
+ *
+ * @author Makarius
+ */
+
+package isabelle.jedit
+
+import org.gjt.sp.jedit.io.Encoding
+import org.gjt.sp.jedit.buffer.JEditBuffer
+
+import java.nio.charset.{Charset, CharsetDecoder, CodingErrorAction}
+import java.io.{InputStream, OutputStream, Reader, Writer, InputStreamReader, OutputStreamWriter,
+  CharArrayReader, ByteArrayOutputStream}
+
+import scala.io.{Source, BufferedSource}
+
+
+object Isabelle_Encoding
+{
+  val NAME = "UTF-8-Isabelle"
+
+  def is_active(buffer: JEditBuffer): Boolean =
+    buffer.getProperty(JEditBuffer.ENCODING).asInstanceOf[String] == NAME
+}
+
+class Isabelle_Encoding extends Encoding
+{
+  private val charset = Charset.forName(Isabelle_System.charset)
+  private val BUFSIZE = 32768
+
+  private def text_reader(in: InputStream, decoder: CharsetDecoder): Reader =
+  {
+    def source(): Source =
+      BufferedSource.fromInputStream(in, decoder, BUFSIZE, { () => source() })
+    new CharArrayReader(Isabelle.symbols.decode(source.mkString).toArray)
+  }
+
+	override def getTextReader(in: InputStream): Reader =
+    text_reader(in, charset.newDecoder())
+
+	override def getPermissiveTextReader(in: InputStream): Reader =
+	{
+		val decoder = charset.newDecoder()
+		decoder.onMalformedInput(CodingErrorAction.REPLACE)
+		decoder.onUnmappableCharacter(CodingErrorAction.REPLACE)
+		text_reader(in, decoder)
+	}
+
+  override def getTextWriter(out: OutputStream): Writer =
+  {
+    val buffer = new ByteArrayOutputStream(BUFSIZE) {
+      override def flush()
+      {
+        val text = Isabelle.symbols.encode(toString(Isabelle_System.charset))
+        out.write(text.getBytes(Isabelle_System.charset))
+        out.flush()
+      }
+      override def close() { out.close() }
+    }
+		new OutputStreamWriter(buffer, charset.newEncoder())
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/isabelle_hyperlinks.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,80 @@
+/*
+ * Hyperlink setup for Isabelle proof documents
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+import java.io.File
+
+import gatchan.jedit.hyperlinks.Hyperlink
+import gatchan.jedit.hyperlinks.HyperlinkSource
+import gatchan.jedit.hyperlinks.AbstractHyperlink
+
+import org.gjt.sp.jedit.View
+import org.gjt.sp.jedit.jEdit
+import org.gjt.sp.jedit.Buffer
+import org.gjt.sp.jedit.TextUtilities
+
+import isabelle.prover.Command
+
+
+class InternalHyperlink(start: Int, end: Int, line: Int, ref_offset: Int)
+  extends AbstractHyperlink(start, end, line, "")
+{
+  override def click(view: View) {
+    view.getTextArea.moveCaretPosition(ref_offset)
+  }
+}
+
+class ExternalHyperlink(start: Int, end: Int, line: Int, ref_file: String, ref_line: Int)
+  extends AbstractHyperlink(start, end, line, "")
+{
+  override def click(view: View) = {
+    Isabelle.system.source_file(ref_file) match {
+      case None => System.err.println("Could not find source file " + ref_file)
+      case Some(file) =>
+        jEdit.openFiles(view, file.getParent, Array(file.getName, "+line:" + ref_line))
+    }
+  }
+}
+
+class IsabelleHyperlinkSource extends HyperlinkSource
+{
+	def getHyperlink(buffer: Buffer, original_offset: Int): Hyperlink = {
+    val prover = Isabelle.prover_setup(buffer).map(_.prover)
+    val theory_view_opt = Isabelle.prover_setup(buffer).map(_.theory_view)
+    if (prover.isEmpty || theory_view_opt.isEmpty) null
+    else if (prover.get == null || theory_view_opt.get == null) null
+    else {
+      val theory_view = theory_view_opt.get
+      val document = theory_view.current_document()
+      val offset = theory_view.from_current(document, original_offset)
+      document.command_at(offset) match {
+        case Some(command) =>
+          command.ref_at(document, offset - command.start(document)) match {
+            case Some(ref) =>
+              val command_start = command.start(document)
+              val begin = theory_view.to_current(document, command_start + ref.start)
+              val line = buffer.getLineOfOffset(begin)
+              val end = theory_view.to_current(document, command_start + ref.stop)
+              ref.info match {
+                case Command.RefInfo(Some(ref_file), Some(ref_line), _, _) =>
+                  new ExternalHyperlink(begin, end, line, ref_file, ref_line)
+                case Command.RefInfo(_, _, Some(id), Some(offset)) =>
+                  prover.get.command(id) match {
+                    case Some(ref_cmd) =>
+                      new InternalHyperlink(begin, end, line,
+                        theory_view.to_current(document, ref_cmd.start(document) + offset - 1))
+                    case None => null
+                  }
+                case _ => null
+              }
+            case None => null
+          }
+        case None => null
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/isabelle_sidekick.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,102 @@
+/*
+ * SideKick parser for Isabelle proof documents
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.jedit
+
+import scala.collection.Set
+import scala.collection.immutable.TreeSet
+
+import javax.swing.tree.DefaultMutableTreeNode
+import javax.swing.text.Position
+import javax.swing.Icon
+
+import org.gjt.sp.jedit.{Buffer, EditPane, TextUtilities, View}
+import errorlist.DefaultErrorSource
+import sidekick.{SideKickParser, SideKickParsedData, SideKickCompletion, IAsset}
+
+import isabelle.prover.{Command, Markup_Node}
+import isabelle.proofdocument.ProofDocument
+
+
+class IsabelleSideKickParser extends SideKickParser("isabelle")
+{
+  /* parsing */
+
+  @volatile private var stopped = false
+  override def stop() = { stopped = true }
+
+  def parse(buffer: Buffer, error_source: DefaultErrorSource): SideKickParsedData =
+  {
+    implicit def int_to_pos(offset: Int): Position =
+      new Position { def getOffset = offset; override def toString = offset.toString }
+
+    stopped = false
+
+    val data = new SideKickParsedData(buffer.getName)
+    val root = data.root
+    data.getAsset(root).setEnd(buffer.getLength)
+
+    val prover_setup = Isabelle.prover_setup(buffer)
+    if (prover_setup.isDefined) {
+      val document = prover_setup.get.theory_view.current_document()
+      for (command <- document.commands if !stopped) {
+        root.add(command.markup_root(document).swing_tree((node: Markup_Node) =>
+            {
+              val content = command.content(node.start, node.stop)
+              val command_start = command.start(document)
+              val id = command.id
+
+              new DefaultMutableTreeNode(new IAsset {
+                override def getIcon: Icon = null
+                override def getShortString: String = content
+                override def getLongString: String = node.info.toString
+                override def getName: String = id
+                override def setName(name: String) = ()
+                override def setStart(start: Position) = ()
+                override def getStart: Position = command_start + node.start
+                override def setEnd(end: Position) = ()
+                override def getEnd: Position = command_start + node.stop
+                override def toString = id + ": " + content + "[" + getStart + " - " + getEnd + "]"
+              })
+            }))
+      }
+      if (stopped) root.add(new DefaultMutableTreeNode("<parser stopped>"))
+    }
+    else root.add(new DefaultMutableTreeNode("<buffer inactive>"))
+
+    data
+  }
+
+
+  /* completion */
+
+  override def supportsCompletion = true
+  override def canCompleteAnywhere = true
+
+  override def complete(pane: EditPane, caret: Int): SideKickCompletion =
+  {
+    val buffer = pane.getBuffer
+
+    val line = buffer.getLineOfOffset(caret)
+    val start = buffer.getLineStartOffset(line)
+    val text = buffer.getSegment(start, caret - start)
+
+    val completion =
+      Isabelle.prover_setup(buffer).map(_.prover.completion()).getOrElse(Isabelle.completion)
+
+    completion.complete(text) match {
+      case None => null
+      case Some((word, cs)) =>
+        val ds =
+          if (Isabelle_Encoding.is_active(buffer))
+            cs.map(Isabelle.system.symbols.decode(_)).sort(Completion.length_ord _)
+          else cs
+        new SideKickCompletion(pane.getView, word, ds.toArray.asInstanceOf[Array[Object]]) { }
+    }
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/option_pane.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,43 @@
+/*
+ * Editor pane for plugin options
+ *
+ * @author Johannes Hölzl, TU Munich
+ */
+
+package isabelle.jedit
+
+import javax.swing.{JComboBox, JSpinner}
+
+import org.gjt.sp.jedit.AbstractOptionPane
+
+
+class OptionPane extends AbstractOptionPane("isabelle")
+{
+  private val logic_name = new JComboBox()
+  private val font_size = new JSpinner()
+
+  override def _init()
+  {
+    addComponent(Isabelle.Property("logic.title"), {
+      for (name <- Isabelle.system.find_logics()) {
+        logic_name.addItem(name)
+        if (name == Isabelle.Property("logic"))
+          logic_name.setSelectedItem(name)
+      }
+      logic_name
+    })
+    addComponent(Isabelle.Property("font-size.title"), {
+      font_size.setValue(Isabelle.Int_Property("font-size"))
+      font_size
+    })
+  }
+
+  override def _save()
+  {
+    val logic = logic_name.getSelectedItem.asInstanceOf[String]
+    Isabelle.Property("logic") = logic
+
+    val size = font_size.getValue().asInstanceOf[Int]
+    Isabelle.Int_Property("font-size") = size
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/plugin.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,155 @@
+/*
+ * Main Isabelle/jEdit plugin setup
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+
+import java.io.{FileInputStream, IOException}
+import java.awt.Font
+import javax.swing.JScrollPane
+
+import scala.collection.mutable
+
+import isabelle.prover.{Prover, Command}
+import isabelle.proofdocument.ProofDocument
+import isabelle.Isabelle_System
+
+import org.gjt.sp.jedit.{jEdit, EBMessage, EBPlugin, Buffer, EditPane, ServiceManager, View}
+import org.gjt.sp.jedit.buffer.JEditBuffer
+import org.gjt.sp.jedit.textarea.JEditTextArea
+import org.gjt.sp.jedit.msg.{EditPaneUpdate, PropertiesChanged}
+
+
+object Isabelle
+{
+  /* name */
+
+  val NAME = "Isabelle"
+
+
+  /* properties */
+
+  val OPTION_PREFIX = "options.isabelle."
+
+  object Property
+  {
+    def apply(name: String): String = jEdit.getProperty(OPTION_PREFIX + name)
+    def update(name: String, value: String) = jEdit.setProperty(OPTION_PREFIX + name, value)
+  }
+
+  object Boolean_Property
+  {
+    def apply(name: String): Boolean = jEdit.getBooleanProperty(OPTION_PREFIX + name)
+    def update(name: String, value: Boolean) = jEdit.setBooleanProperty(OPTION_PREFIX + name, value)
+  }
+
+  object Int_Property
+  {
+    def apply(name: String): Int = jEdit.getIntegerProperty(OPTION_PREFIX + name)
+    def update(name: String, value: Int) = jEdit.setIntegerProperty(OPTION_PREFIX + name, value)
+  }
+
+
+  /* Isabelle system instance */
+
+  var system: Isabelle_System = null
+  def symbols = system.symbols
+  lazy val completion = new Completion + symbols
+
+
+  /* settings */
+
+  def default_logic(): String =
+  {
+    val logic = Isabelle.Property("logic")
+    if (logic != null) logic
+    else system.getenv_strict("ISABELLE_LOGIC")
+  }
+
+
+  /* plugin instance */
+
+  var plugin: Plugin = null
+
+
+  /* running provers */
+
+  def prover_setup(buffer: JEditBuffer) = plugin.prover_setup(buffer)
+}
+
+
+class Plugin extends EBPlugin
+{
+  /* event buses */
+
+  val state_update = new Event_Bus[Command]
+
+
+  /* selected state */
+
+  private var _selected_state: Command = null
+  def selected_state = _selected_state
+  def selected_state_=(state: Command) { _selected_state = state; state_update.event(state) }
+
+
+  /* mapping buffer <-> prover */
+
+  private val mapping = new mutable.HashMap[JEditBuffer, ProverSetup]
+
+  private def install(view: View)
+  {
+    val buffer = view.getBuffer
+    val prover_setup = new ProverSetup(buffer)
+    mapping.update(buffer, prover_setup)
+    prover_setup.activate(view)
+  }
+
+  private def uninstall(view: View) =
+    mapping.removeKey(view.getBuffer).get.deactivate
+
+  def switch_active (view: View) =
+    if (mapping.isDefinedAt(view.getBuffer)) uninstall(view)
+    else install(view)
+
+  def prover_setup(buffer: JEditBuffer): Option[ProverSetup] = mapping.get(buffer)
+  def is_active (buffer: JEditBuffer) = mapping.isDefinedAt(buffer)
+
+
+  /* main plugin plumbing */
+
+  override def handleMessage(msg: EBMessage)
+  {
+    msg match {
+      case epu: EditPaneUpdate =>
+        val buffer = epu.getEditPane.getBuffer
+        epu.getWhat match {
+          case EditPaneUpdate.BUFFER_CHANGED =>
+            (mapping get buffer) map (_.theory_view.activate)
+          case EditPaneUpdate.BUFFER_CHANGING =>
+            if (buffer != null)
+              (mapping get buffer) map (_.theory_view.deactivate)
+          case _ =>
+        }
+      case _ =>
+    }
+  }
+
+  override def start()
+  {
+    Isabelle.plugin = this
+    Isabelle.system = new Isabelle_System
+    if (!Isabelle.system.register_fonts())
+      System.err.println("Failed to register Isabelle fonts")
+  }
+
+  override def stop()
+  {
+    // TODO: proper cleanup
+    Isabelle.system = null
+    Isabelle.plugin = null
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/prover_setup.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,35 @@
+/*
+ * Independent prover sessions for each buffer
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+
+import org.gjt.sp.jedit.{Buffer, View}
+
+import isabelle.prover.Prover
+
+
+class ProverSetup(buffer: Buffer)
+{
+  var prover: Prover = null
+  var theory_view: TheoryView = null
+
+  def activate(view: View)
+  {
+    // TheoryView starts prover
+    theory_view = new TheoryView(view.getTextArea)
+    prover = theory_view.prover
+
+    theory_view.activate()
+    prover.begin_document(buffer.getName)
+  }
+
+  def deactivate()
+  {
+    theory_view.deactivate
+    prover.stop
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/raw_output_dockable.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,31 @@
+/*
+ * Dockable window for raw process output
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Johannes Hölzl, TU Munich
+ */
+
+package isabelle.jedit
+
+
+import java.awt.{Dimension, Graphics, GridLayout}
+import javax.swing.{JPanel, JTextArea, JScrollPane}
+
+import org.gjt.sp.jedit.View
+import org.gjt.sp.jedit.gui.DockableWindowManager
+
+
+class OutputDockable(view : View, position : String) extends JPanel {
+
+  if (position == DockableWindowManager.FLOATING)
+    setPreferredSize(new Dimension(500, 250))
+
+  setLayout(new GridLayout(1, 1))
+  add(new JScrollPane(new JTextArea))
+
+  def set_text(output_text_view: JTextArea) {
+    removeAll()
+    add(new JScrollPane(output_text_view))
+    revalidate()
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/results_dockable.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,111 @@
+/*
+ * Dockable window with rendered state output
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Johannes Hölzl, TU Munich
+ */
+
+package isabelle.jedit
+
+import isabelle.XML
+
+import java.io.StringReader
+import java.awt.{BorderLayout, Dimension}
+
+import javax.swing.{JButton, JPanel, JScrollPane}
+
+import java.util.logging.{Logger, Level}
+
+import org.lobobrowser.html.parser._
+import org.lobobrowser.html.test._
+import org.lobobrowser.html.gui._
+import org.lobobrowser.html._
+import org.lobobrowser.html.style.CSSUtilities
+import org.lobobrowser.html.domimpl.{HTMLDocumentImpl, HTMLStyleElementImpl, NodeImpl}
+
+import org.gjt.sp.jedit.jEdit
+import org.gjt.sp.jedit.View
+import org.gjt.sp.jedit.gui.DockableWindowManager
+import org.gjt.sp.jedit.textarea.AntiAlias
+
+import scala.io.Source
+
+
+class StateViewDockable(view : View, position : String) extends JPanel {
+
+  // outer panel
+  if (position == DockableWindowManager.FLOATING)
+    setPreferredSize(new Dimension(500, 250))
+  setLayout(new BorderLayout)
+
+
+  // global logging
+  
+  Logger.getLogger("org.lobobrowser").setLevel(Level.WARNING)
+
+
+  // document template with styles
+
+  private def try_file(name: String): String =
+  {
+    val file = Isabelle.system.platform_file(name)
+    if (file.exists) Source.fromFile(file).mkString else ""
+  }
+
+
+  // HTML panel
+
+  val panel = new HtmlPanel
+  val ucontext = new SimpleUserAgentContext
+  val rcontext = new SimpleHtmlRendererContext(panel, ucontext)
+  val doc = {
+    val builder = new DocumentBuilderImpl(ucontext, rcontext)
+    builder.parse(new InputSourceImpl(new StringReader(
+      """<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<style media="all" type="text/css">
+""" +
+  try_file("$ISABELLE_HOME/lib/html/isabelle.css") + "\n" +
+"""
+body {
+  font-family: IsabelleText;
+  font-size: 14pt;
+}
+""" +
+  try_file("$ISABELLE_HOME_USER/etc/isabelle.css") + "\n" +
+"""
+</style>
+</head>
+</html>
+""")))
+  }
+
+  val empty_body = XML.document_node(doc, XML.elem(HTML.BODY))
+  doc.appendChild(empty_body)
+
+  panel.setDocument(doc, rcontext)
+  add(panel, BorderLayout.CENTER)
+
+  
+  // register for state-view
+  Isabelle.plugin.state_update += (cmd => {
+    val theory_view = Isabelle.prover_setup(view.getBuffer).get.theory_view
+
+    Swing_Thread.later {
+      val node =
+        if (cmd == null) empty_body
+        else {
+          val xml = XML.elem(HTML.BODY,
+            cmd.results(theory_view.current_document).
+              map((t: XML.Tree) => XML.elem(HTML.PRE, HTML.spans(t))))
+          XML.document_node(doc, xml)
+        }
+      doc.removeChild(doc.getLastChild())
+      doc.appendChild(node)
+      panel.delayedRelayout(node.asInstanceOf[NodeImpl])
+    }
+  })
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/token_marker.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,154 @@
+/*
+ * include isabelle's command- and keyword-declarations
+ * live in jEdits syntax-highlighting
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+
+import isabelle.prover.Prover
+import isabelle.Markup
+
+import org.gjt.sp.jedit.buffer.JEditBuffer
+import org.gjt.sp.jedit.syntax.{Token => JToken,
+  TokenMarker, TokenHandler, SyntaxStyle, ParserRuleSet}
+
+import java.awt.Color
+import java.awt.Font
+import javax.swing.text.Segment;
+
+
+object DynamicTokenMarker
+{
+  /* line context */
+
+  private val rule_set = new ParserRuleSet("isabelle", "MAIN")
+  private class LineContext(val line: Int, prev: LineContext)
+    extends TokenMarker.LineContext(rule_set, prev)
+
+
+  /* mapping to jEdit token types */
+  // TODO: as properties or CSS style sheet
+
+  private val choose_byte: Map[String, Byte] =
+  {
+    import JToken._
+    Map[String, Byte](
+      // logical entities
+      Markup.TCLASS -> LABEL,
+      Markup.TYCON -> LABEL,
+      Markup.FIXED_DECL -> LABEL,
+      Markup.FIXED -> LABEL,
+      Markup.CONST_DECL -> LABEL,
+      Markup.CONST -> LABEL,
+      Markup.FACT_DECL -> LABEL,
+      Markup.FACT -> LABEL,
+      Markup.DYNAMIC_FACT -> LABEL,
+      Markup.LOCAL_FACT_DECL -> LABEL,
+      Markup.LOCAL_FACT -> LABEL,
+      // inner syntax
+      Markup.TFREE -> LITERAL2,
+      Markup.FREE -> LITERAL2,
+      Markup.TVAR -> LITERAL3,
+      Markup.SKOLEM -> LITERAL3,
+      Markup.BOUND -> LITERAL3,
+      Markup.VAR -> LITERAL3,
+      Markup.NUM -> DIGIT,
+      Markup.FLOAT -> DIGIT,
+      Markup.XNUM -> DIGIT,
+      Markup.XSTR -> LITERAL4,
+      Markup.LITERAL -> LITERAL4,
+      Markup.INNER_COMMENT -> COMMENT1,
+      Markup.SORT -> FUNCTION,
+      Markup.TYP -> FUNCTION,
+      Markup.TERM -> FUNCTION,
+      Markup.PROP -> FUNCTION,
+      Markup.ATTRIBUTE -> FUNCTION,
+      Markup.METHOD -> FUNCTION,
+      // ML syntax
+      Markup.ML_KEYWORD -> KEYWORD2,
+      Markup.ML_IDENT -> NULL,
+      Markup.ML_TVAR -> LITERAL3,
+      Markup.ML_NUMERAL -> DIGIT,
+      Markup.ML_CHAR -> LITERAL1,
+      Markup.ML_STRING -> LITERAL1,
+      Markup.ML_COMMENT -> COMMENT1,
+      Markup.ML_MALFORMED -> INVALID,
+      // embedded source text
+      Markup.ML_SOURCE -> COMMENT4,
+      Markup.DOC_SOURCE -> COMMENT4,
+      Markup.ANTIQ -> COMMENT4,
+      Markup.ML_ANTIQ -> COMMENT4,
+      Markup.DOC_ANTIQ -> COMMENT4,
+      // outer syntax
+      Markup.IDENT -> NULL,
+      Markup.COMMAND -> OPERATOR,
+      Markup.KEYWORD -> KEYWORD4,
+      Markup.VERBATIM -> COMMENT3,
+      Markup.COMMENT -> COMMENT1,
+      Markup.CONTROL -> COMMENT3,
+      Markup.MALFORMED -> INVALID,
+      Markup.STRING -> LITERAL3,
+      Markup.ALTSTRING -> LITERAL1
+    ).withDefaultValue(NULL)
+  }
+
+  def choose_color(kind: String, styles: Array[SyntaxStyle]): Color =
+    styles(choose_byte(kind)).getForegroundColor
+}
+
+
+class DynamicTokenMarker(buffer: JEditBuffer, prover: Prover)
+  extends TokenMarker
+{
+  override def markTokens(prev: TokenMarker.LineContext,
+      handler: TokenHandler, line_segment: Segment): TokenMarker.LineContext =
+  {
+    val previous = prev.asInstanceOf[DynamicTokenMarker.LineContext]
+    val line = if (prev == null) 0 else previous.line + 1
+    val context = new DynamicTokenMarker.LineContext(line, previous)
+    val start = buffer.getLineStartOffset(line)
+    val stop = start + line_segment.count
+
+    val theory_view = Isabelle.prover_setup(buffer).get.theory_view
+    val document = theory_view.current_document()
+    def to: Int => Int = theory_view.to_current(document, _)
+    def from: Int => Int = theory_view.from_current(document, _)
+
+    var next_x = start
+    var cmd = document.command_at(from(start))
+    while (cmd.isDefined && cmd.get.start(document) < from(stop)) {
+      val command = cmd.get
+      for {
+        markup <- command.highlight(document).flatten
+        command_start = command.start(document)
+        abs_start = to(command_start + markup.start)
+        abs_stop = to(command_start + markup.stop)
+        if (abs_stop > start)
+        if (abs_start < stop)
+        byte = DynamicTokenMarker.choose_byte(markup.info.toString)
+        token_start = (abs_start - start) max 0
+        token_length =
+          (abs_stop - abs_start) -
+          ((start - abs_start) max 0) -
+          ((abs_stop - stop) max 0)
+      } {
+        if (start + token_start > next_x)
+          handler.handleToken(line_segment, 1,
+            next_x - start, start + token_start - next_x, context)
+        handler.handleToken(line_segment, byte,
+          token_start, token_length, context)
+        next_x = start + token_start + token_length
+      }
+      cmd = document.commands.next(command)
+    }
+    if (next_x < stop)
+      handler.handleToken(line_segment, 1, next_x - start, stop - next_x, context)
+
+    handler.handleToken(line_segment, JToken.END, line_segment.count, 0, context)
+    handler.setLineContext(context)
+    return context
+  }
+}
--- a/src/Tools/jEdit/src/proofdocument/Change.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Changes of plain text
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.proofdocument
-
-
-sealed abstract class Edit
-{
-  val start: Int
-  def before(offset: Int): Int
-  def after(offset: Int): Int
-}
-
-
-case class Insert(start: Int, text: String) extends Edit
-{
-  def before(offset: Int): Int =
-    if (start > offset) offset
-    else (offset - text.length) max start
-
-  def after(offset: Int): Int =
-    if (start <= offset) offset + text.length else offset
-}
-
-
-case class Remove(start: Int, text: String) extends Edit
-{
-  def before(offset: Int): Int =
-    if (start <= offset) offset + text.length else offset
-
-  def after(offset: Int): Int =
-    if (start > offset) offset
-    else (offset - text.length) max start
-}
-// TODO: merge multiple inserts?
-
-
-class Change(
-  val id: String,
-  val parent: Option[Change],
-  val edits: List[Edit])
-{
-  def ancestors(done: Change => Boolean): List[Change] =
-    if (done(this)) Nil
-    else this :: parent.map(_.ancestors(done)).getOrElse(Nil)
-  def ancestors: List[Change] = ancestors(_ => false)
-
-  override def toString =
-    "Change(" + id + " <- " + parent.map(_.id) + ", " + edits + ")"
-}
\ No newline at end of file
--- a/src/Tools/jEdit/src/proofdocument/ProofDocument.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +0,0 @@
-/*
- * Document as list of commands, consisting of lists of tokens
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- * @author Makarius
- */
-
-package isabelle.proofdocument
-
-import scala.actors.Actor, Actor._
-
-import java.util.regex.Pattern
-
-import isabelle.prover.{Prover, Command, Command_State}
-
-
-object ProofDocument
-{
-  // Be careful when changing this regex. Not only must it handle the
-  // spurious end of a token but also:  
-  // Bug ID: 5050507 Pattern.matches throws StackOverflow Error
-  // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507
-  
-  val token_pattern = 
-    Pattern.compile(
-      "\\{\\*([^*]|\\*[^}]|\\*\\z)*(\\z|\\*\\})|" +
-      "\\(\\*([^*]|\\*[^)]|\\*\\z)*(\\z|\\*\\))|" +
-      "(\\?'?|')[A-Za-z_0-9.]*|" + 
-      "[A-Za-z_0-9.]+|" + 
-      "[!#$%&*+-/<=>?@^_|~]+|" +
-      "\"([^\\\\\"]?(\\\\(.|\\z))?)*+(\"|\\z)|" +
-      "`([^\\\\`]?(\\\\(.|\\z))?)*+(`|\\z)|" +
-      "[()\\[\\]{}:;]", Pattern.MULTILINE)
-
-  val empty =
-    new ProofDocument(isabelle.jedit.Isabelle.system.id(),
-      Linear_Set(), Map(), Linear_Set(), Map(), _ => false)
-
-  type StructureChange = List[(Option[Command], Option[Command])]
-
-}
-
-class ProofDocument(
-  val id: String,
-  val tokens: Linear_Set[Token],
-  val token_start: Map[Token, Int],
-  val commands: Linear_Set[Command],
-  var states: Map[Command, Command_State],   // FIXME immutable
-  is_command_keyword: String => Boolean)
-{
-  import ProofDocument.StructureChange
-
-  def set_command_keyword(f: String => Boolean): ProofDocument =
-    new ProofDocument(id, tokens, token_start, commands, states, f)
-
-  def content = Token.string_from_tokens(Nil ++ tokens, token_start)
-
-
-  
-  /** token view **/
-
-  def text_changed(change: Change): (ProofDocument, StructureChange) =
-  {
-    def edit_doc(doc_chgs: (ProofDocument, StructureChange), edit: Edit) = {
-      val (doc, chgs) = doc_chgs
-      val (new_doc, chg) = doc.text_edit(edit, change.id)
-      (new_doc, chgs ++ chg)
-    }
-    ((this, Nil: StructureChange) /: change.edits)(edit_doc)
-  }
-
-  def text_edit(e: Edit, id: String): (ProofDocument, StructureChange) =
-  {
-    case class TextChange(start: Int, added: String, removed: String)
-    val change = e match {
-      case Insert(s, a) => TextChange(s, a, "")
-      case Remove(s, r) => TextChange(s, "", r)
-    }
-    //indices of tokens
-    var start: Map[Token, Int] = token_start
-    def stop(t: Token) = start(t) + t.length
-    // split old token lists
-    val tokens = Nil ++ this.tokens
-    val (begin, remaining) = tokens.span(stop(_) < change.start)
-    val (removed, end) = remaining.span(token_start(_) <= change.start + change.removed.length)
-    // update indices
-    start = end.foldLeft(start)((s, t) =>
-      s + (t -> (s(t) + change.added.length - change.removed.length)))
-
-    val split_begin = removed.takeWhile(start(_) < change.start).
-      map (t => {
-          val split_tok = new Token(t.content.substring(0, change.start - start(t)), t.kind)
-          start += (split_tok -> start(t))
-          split_tok
-        })
-
-    val split_end = removed.dropWhile(stop(_) < change.start + change.removed.length).
-      map (t => {
-          val split_tok =
-            new Token(t.content.substring(change.start + change.removed.length - start(t)), t.kind)
-          start += (split_tok -> start(t))
-          split_tok
-        })
-    // update indices
-    start = removed.foldLeft (start) ((s, t) => s - t)
-    start = split_end.foldLeft (start) ((s, t) =>
-    s + (t -> (change.start + change.added.length)))
-
-    val ins = new Token(change.added, Token.Kind.OTHER)
-    start += (ins -> change.start)
-    
-    var invalid_tokens = split_begin ::: ins :: split_end ::: end
-    var new_tokens: List[Token] = Nil
-    var old_suffix: List[Token] = Nil
-
-    val match_start = invalid_tokens.firstOption.map(start(_)).getOrElse(0)
-    val matcher =
-      ProofDocument.token_pattern.matcher(Token.string_from_tokens(invalid_tokens, start))
-
-    while (matcher.find() && invalid_tokens != Nil) {
-			val kind =
-        if (is_command_keyword(matcher.group))
-          Token.Kind.COMMAND_START
-        else if (matcher.end - matcher.start > 2 && matcher.group.substring(0, 2) == "(*")
-          Token.Kind.COMMENT
-        else
-          Token.Kind.OTHER
-      val new_token = new Token(matcher.group, kind)
-      start += (new_token -> (match_start + matcher.start))
-      new_tokens ::= new_token
-
-      invalid_tokens = invalid_tokens dropWhile (stop(_) < stop(new_token))
-      invalid_tokens match {
-        case t :: ts =>
-          if (start(t) == start(new_token) &&
-              start(t) > change.start + change.added.length) {
-          old_suffix = t :: ts
-          new_tokens = new_tokens.tail
-          invalid_tokens = Nil
-        }
-        case _ =>
-      }
-    }
-    val insert = new_tokens.reverse
-    val new_token_list = begin ::: insert ::: old_suffix
-    token_changed(id, begin.lastOption, insert,
-      old_suffix.firstOption, new_token_list, start)
-  }
-
-  
-  /** command view **/
-
-  private def token_changed(
-    new_id: String,
-    before_change: Option[Token],
-    inserted_tokens: List[Token],
-    after_change: Option[Token],
-    new_tokens: List[Token],
-    new_token_start: Map[Token, Int]):
-  (ProofDocument, StructureChange) =
-  {
-    val new_tokenset = Linear_Set[Token]() ++ new_tokens
-    val cmd_before_change = before_change match {
-      case None => None
-      case Some(bc) =>
-        val cmd_with_bc = commands.find(_.contains(bc)).get
-        if (cmd_with_bc.tokens.last == bc) {
-          if (new_tokenset.next(bc).map(_.is_start).getOrElse(true))
-            Some(cmd_with_bc)
-          else commands.prev(cmd_with_bc)
-        }
-        else commands.prev(cmd_with_bc)
-    }
-
-    val cmd_after_change = after_change match {
-      case None => None
-      case Some(ac) =>
-        val cmd_with_ac = commands.find(_.contains(ac)).get
-        if (ac.is_start)
-          Some(cmd_with_ac)
-        else
-          commands.next(cmd_with_ac)
-    }
-
-    val removed_commands = commands.dropWhile(Some(_) != cmd_before_change).drop(1).
-      takeWhile(Some(_) != cmd_after_change)
-
-    // calculate inserted commands
-    def tokens_to_commands(tokens: List[Token]): List[Command]= {
-      tokens match {
-        case Nil => Nil
-        case t :: ts =>
-          val (cmd, rest) =
-            ts.span(t => t.kind != Token.Kind.COMMAND_START && t.kind != Token.Kind.COMMENT)
-          new Command(t :: cmd, new_token_start) :: tokens_to_commands(rest)
-      }
-    }
-
-    val split_begin =
-      if (before_change.isDefined) {
-        val changed =
-          if (cmd_before_change.isDefined)
-            new_tokens.dropWhile(_ != cmd_before_change.get.tokens.last).drop(1)
-          else new_tokenset
-        if (changed.exists(_ == before_change.get))
-          changed.takeWhile(_ != before_change.get).toList :::
-            List(before_change.get)
-        else Nil
-      } else Nil
-
-    val split_end =
-      if (after_change.isDefined) {
-        val unchanged = new_tokens.dropWhile(_ != after_change.get)
-        if(cmd_after_change.isDefined) {
-          if (unchanged.exists(_ == cmd_after_change.get.tokens.first))
-            unchanged.takeWhile(_ != cmd_after_change.get.tokens.first).toList
-          else Nil
-        } else {
-          unchanged
-        }
-      } else Nil
-
-    val rescan_begin =
-      split_begin :::
-        before_change.map(bc => new_tokens.dropWhile(_ != bc).drop(1)).getOrElse(new_tokens)
-    val rescanning_tokens =
-      after_change.map(ac => rescan_begin.takeWhile(_ != ac)).getOrElse(rescan_begin) :::
-        split_end
-    val inserted_commands = tokens_to_commands(rescanning_tokens.toList)
-
-    // build new document
-    val new_commandset = commands.
-      delete_between(cmd_before_change, cmd_after_change).
-      append_after(cmd_before_change, inserted_commands)
-
-
-    val doc =
-      new ProofDocument(new_id, new_tokenset, new_token_start, new_commandset,
-        states -- removed_commands, is_command_keyword)
-
-    val removes =
-      for (cmd <- removed_commands) yield (cmd_before_change -> None)
-    val inserts =
-      for (cmd <- inserted_commands) yield (doc.commands.prev(cmd) -> Some(cmd))
-
-    return (doc, removes.toList ++ inserts)
-  }
-
-  val commands_offsets = {
-    var last_stop = 0
-    (for (c <- commands) yield {
-      val r = c -> (last_stop,c.stop(this))
-      last_stop = c.stop(this)
-      r
-    }).toArray
-  }
-
-  def command_at(pos: Int): Option[Command] =
-    find_command(pos, 0, commands_offsets.length)
-
-  // use a binary search to find commands for a given offset
-  private def find_command(pos: Int, array_start: Int, array_stop: Int): Option[Command] =
-  {
-    val middle_index = (array_start + array_stop) / 2
-    if (middle_index >= commands_offsets.length) return None
-    val (middle, (start, stop)) = commands_offsets(middle_index)
-    // does middle contain pos?
-    if (start <= pos && pos < stop)
-      Some(middle)
-    else if (start > pos)
-      find_command(pos, array_start, middle_index)
-    else if (stop <= pos)
-      find_command(pos, middle_index + 1, array_stop)
-    else error("impossible")
-  }
-}
--- a/src/Tools/jEdit/src/proofdocument/Token.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Document tokens as text ranges
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.proofdocument
-
-
-import isabelle.prover.Command
-
-
-object Token {
-  object Kind extends Enumeration
-  {
-    val COMMAND_START = Value("COMMAND_START")
-    val COMMENT = Value("COMMENT")
-    val OTHER = Value("OTHER")
-  }
-
-  def string_from_tokens(tokens: List[Token], starts: Token => Int): String = {
-    def stop(t: Token) = starts(t) + t.length
-    tokens match {
-      case Nil => ""
-      case tok :: toks =>
-        val (res, _) = toks.foldLeft(tok.content, stop(tok))((a, token) =>
-          (a._1 + " " * (starts(token) - a._2) + token.content, stop(token)))
-        res
-    }
-  }
-
-}
-
-class Token(
-  val content: String,
-  val kind: Token.Kind.Value)
-{
-  override def toString = content
-  val length = content.length
-  val is_start = kind == Token.Kind.COMMAND_START || kind == Token.Kind.COMMENT
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/change.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,54 @@
+/*
+ * Changes of plain text
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.proofdocument
+
+
+sealed abstract class Edit
+{
+  val start: Int
+  def before(offset: Int): Int
+  def after(offset: Int): Int
+}
+
+
+case class Insert(start: Int, text: String) extends Edit
+{
+  def before(offset: Int): Int =
+    if (start > offset) offset
+    else (offset - text.length) max start
+
+  def after(offset: Int): Int =
+    if (start <= offset) offset + text.length else offset
+}
+
+
+case class Remove(start: Int, text: String) extends Edit
+{
+  def before(offset: Int): Int =
+    if (start <= offset) offset + text.length else offset
+
+  def after(offset: Int): Int =
+    if (start > offset) offset
+    else (offset - text.length) max start
+}
+// TODO: merge multiple inserts?
+
+
+class Change(
+  val id: String,
+  val parent: Option[Change],
+  val edits: List[Edit])
+{
+  def ancestors(done: Change => Boolean): List[Change] =
+    if (done(this)) Nil
+    else this :: parent.map(_.ancestors(done)).getOrElse(Nil)
+  def ancestors: List[Change] = ancestors(_ => false)
+
+  override def toString =
+    "Change(" + id + " <- " + parent.map(_.id) + ", " + edits + ")"
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/command.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,124 @@
+/*
+ * Prover commands with semantic state
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.prover
+
+
+import scala.actors.Actor, Actor._
+
+import scala.collection.mutable
+
+import isabelle.proofdocument.{Token, ProofDocument}
+import isabelle.jedit.{Isabelle, Plugin}
+import isabelle.XML
+
+
+trait Accumulator extends Actor
+{
+  start() // start actor
+
+  protected var _state: State
+  def state = _state
+
+  override def act() {
+    loop {
+      react {
+        case (prover: Prover, message: XML.Tree) => _state = _state.+(prover, message)
+        case bad => System.err.println("prover: ignoring bad message " + bad)
+      }
+    }
+  }
+}
+
+
+object Command
+{
+  object Status extends Enumeration
+  {
+    val UNPROCESSED = Value("UNPROCESSED")
+    val FINISHED = Value("FINISHED")
+    val FAILED = Value("FAILED")
+  }
+
+  case class HighlightInfo(highlight: String) { override def toString = highlight }
+  case class TypeInfo(ty: String)
+  case class RefInfo(file: Option[String], line: Option[Int],
+    command_id: Option[String], offset: Option[Int])
+}
+
+
+class Command(
+    val tokens: List[Token],
+    val starts: Map[Token, Int]) extends Accumulator
+{
+  require(!tokens.isEmpty)
+
+  val id = Isabelle.system.id()
+  override def hashCode = id.hashCode
+
+
+  /* content */
+
+  override def toString = name
+
+  val name = tokens.head.content
+  val content: String = Token.string_from_tokens(tokens, starts)
+  def content(i: Int, j: Int): String = content.substring(i, j)
+  val symbol_index = new Symbol.Index(content)
+
+  def start(doc: ProofDocument) = doc.token_start(tokens.first)
+  def stop(doc: ProofDocument) = doc.token_start(tokens.last) + tokens.last.length
+
+  def contains(p: Token) = tokens.contains(p)
+
+  protected override var _state = new State(this)
+
+
+  /* markup */
+
+  lazy val empty_markup = new Markup_Text(Nil, content)
+
+  def markup_node(begin: Int, end: Int, info: Any): Markup_Tree =
+  {
+    val start = symbol_index.decode(begin)
+    val stop = symbol_index.decode(end)
+    new Markup_Tree(new Markup_Node(start, stop, info), Nil)
+  }
+
+
+  /* results, markup, ... */
+
+  private val empty_cmd_state = new Command_State(this)
+  private def cmd_state(doc: ProofDocument) =
+    doc.states.getOrElse(this, empty_cmd_state)
+
+  def status(doc: ProofDocument) = cmd_state(doc).state.status
+  def results(doc: ProofDocument) = cmd_state(doc).results
+  def markup_root(doc: ProofDocument) = cmd_state(doc).markup_root
+  def highlight(doc: ProofDocument) = cmd_state(doc).highlight
+  def type_at(doc: ProofDocument, offset: Int) = cmd_state(doc).type_at(offset)
+  def ref_at(doc: ProofDocument, offset: Int) = cmd_state(doc).ref_at(offset)
+}
+
+
+class Command_State(val command: Command) extends Accumulator
+{
+  protected override var _state = new State(command)
+
+  def results: List[XML.Tree] =
+    command.state.results ::: state.results
+
+  def markup_root: Markup_Text =
+    (command.state.markup_root /: state.markup_root.markup)(_ + _)
+
+  def type_at(pos: Int): Option[String] = state.type_at(pos)
+
+  def ref_at(pos: Int): Option[Markup_Node] = state.ref_at(pos)
+
+  def highlight: Markup_Text =
+    (command.state.highlight /: state.highlight.markup)(_ + _)
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/markup_node.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,111 @@
+/*
+ * Document markup nodes, with connection to Swing tree model
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.prover
+
+
+import javax.swing.tree.DefaultMutableTreeNode
+
+import isabelle.proofdocument.ProofDocument
+
+
+class Markup_Node(val start: Int, val stop: Int, val info: Any)
+{
+  def fits_into(that: Markup_Node): Boolean =
+    that.start <= this.start && this.stop <= that.stop
+}
+
+
+class Markup_Tree(val node: Markup_Node, val branches: List[Markup_Tree])
+{
+  def set_branches(bs: List[Markup_Tree]): Markup_Tree = new Markup_Tree(node, bs)
+
+  private def add(branch: Markup_Tree) =   // FIXME avoid sort
+    set_branches((branch :: branches) sort ((a, b) => a.node.start < b.node.start))
+
+  private def remove(bs: List[Markup_Tree]) = set_branches(branches -- bs)
+
+  def + (new_tree: Markup_Tree): Markup_Tree =
+  {
+    val new_node = new_tree.node
+    if (new_node fits_into node) {
+      var inserted = false
+      val new_branches =
+        branches.map(branch =>
+          if ((new_node fits_into branch.node) && !inserted) {
+            inserted = true
+            branch + new_tree
+          }
+          else branch)
+      if (!inserted) {
+        // new_tree did not fit into children of this
+        // -> insert between this and its branches
+        val fitting = branches filter(_.node fits_into new_node)
+        (this remove fitting) add ((new_tree /: fitting)(_ + _))
+      }
+      else set_branches(new_branches)
+    }
+    else {
+      System.err.println("ignored nonfitting markup: " + new_node)
+      this
+    }
+  }
+
+  def flatten: List[Markup_Node] =
+  {
+    var next_x = node.start
+    if (branches.isEmpty) List(this.node)
+    else {
+      val filled_gaps =
+        for {
+          child <- branches
+          markups =
+            if (next_x < child.node.start)
+              new Markup_Node(next_x, child.node.start, node.info) :: child.flatten
+            else child.flatten
+          update = (next_x = child.node.stop)
+          markup <- markups
+        } yield markup
+      if (next_x < node.stop)
+        filled_gaps + new Markup_Node(next_x, node.stop, node.info)
+      else filled_gaps
+    }
+  }
+}
+
+
+class Markup_Text(val markup: List[Markup_Tree], val content: String)
+{
+  private lazy val root =
+    new Markup_Tree(new Markup_Node(0, content.length, None), markup)
+
+  def + (new_tree: Markup_Tree): Markup_Text =
+    new Markup_Text((root + new_tree).branches, content)
+
+  def filter(pred: Markup_Node => Boolean): Markup_Text =
+  {
+    def filt(tree: Markup_Tree): List[Markup_Tree] =
+    {
+      val branches = tree.branches.flatMap(filt(_))
+      if (pred(tree.node)) List(tree.set_branches(branches))
+      else branches
+    }
+    new Markup_Text(markup.flatMap(filt(_)), content)
+  }
+
+  def flatten: List[Markup_Node] = markup.flatten(_.flatten)
+
+  def swing_tree(swing_node: Markup_Node => DefaultMutableTreeNode): DefaultMutableTreeNode =
+  {
+    def swing(tree: Markup_Tree): DefaultMutableTreeNode =
+    {
+      val node = swing_node(tree.node)
+      tree.branches foreach ((branch: Markup_Tree) => node.add(swing(branch)))
+      node
+    }
+    swing(root)
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/proof_document.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,277 @@
+/*
+ * Document as list of commands, consisting of lists of tokens
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.proofdocument
+
+import scala.actors.Actor, Actor._
+
+import java.util.regex.Pattern
+
+import isabelle.prover.{Prover, Command, Command_State}
+
+
+object ProofDocument
+{
+  // Be careful when changing this regex. Not only must it handle the
+  // spurious end of a token but also:  
+  // Bug ID: 5050507 Pattern.matches throws StackOverflow Error
+  // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507
+  
+  val token_pattern = 
+    Pattern.compile(
+      "\\{\\*([^*]|\\*[^}]|\\*\\z)*(\\z|\\*\\})|" +
+      "\\(\\*([^*]|\\*[^)]|\\*\\z)*(\\z|\\*\\))|" +
+      "(\\?'?|')[A-Za-z_0-9.]*|" + 
+      "[A-Za-z_0-9.]+|" + 
+      "[!#$%&*+-/<=>?@^_|~]+|" +
+      "\"([^\\\\\"]?(\\\\(.|\\z))?)*+(\"|\\z)|" +
+      "`([^\\\\`]?(\\\\(.|\\z))?)*+(`|\\z)|" +
+      "[()\\[\\]{}:;]", Pattern.MULTILINE)
+
+  val empty =
+    new ProofDocument(isabelle.jedit.Isabelle.system.id(),
+      Linear_Set(), Map(), Linear_Set(), Map(), _ => false)
+
+  type StructureChange = List[(Option[Command], Option[Command])]
+
+}
+
+class ProofDocument(
+  val id: String,
+  val tokens: Linear_Set[Token],
+  val token_start: Map[Token, Int],
+  val commands: Linear_Set[Command],
+  var states: Map[Command, Command_State],   // FIXME immutable
+  is_command_keyword: String => Boolean)
+{
+  import ProofDocument.StructureChange
+
+  def set_command_keyword(f: String => Boolean): ProofDocument =
+    new ProofDocument(id, tokens, token_start, commands, states, f)
+
+  def content = Token.string_from_tokens(Nil ++ tokens, token_start)
+
+
+  
+  /** token view **/
+
+  def text_changed(change: Change): (ProofDocument, StructureChange) =
+  {
+    def edit_doc(doc_chgs: (ProofDocument, StructureChange), edit: Edit) = {
+      val (doc, chgs) = doc_chgs
+      val (new_doc, chg) = doc.text_edit(edit, change.id)
+      (new_doc, chgs ++ chg)
+    }
+    ((this, Nil: StructureChange) /: change.edits)(edit_doc)
+  }
+
+  def text_edit(e: Edit, id: String): (ProofDocument, StructureChange) =
+  {
+    case class TextChange(start: Int, added: String, removed: String)
+    val change = e match {
+      case Insert(s, a) => TextChange(s, a, "")
+      case Remove(s, r) => TextChange(s, "", r)
+    }
+    //indices of tokens
+    var start: Map[Token, Int] = token_start
+    def stop(t: Token) = start(t) + t.length
+    // split old token lists
+    val tokens = Nil ++ this.tokens
+    val (begin, remaining) = tokens.span(stop(_) < change.start)
+    val (removed, end) = remaining.span(token_start(_) <= change.start + change.removed.length)
+    // update indices
+    start = end.foldLeft(start)((s, t) =>
+      s + (t -> (s(t) + change.added.length - change.removed.length)))
+
+    val split_begin = removed.takeWhile(start(_) < change.start).
+      map (t => {
+          val split_tok = new Token(t.content.substring(0, change.start - start(t)), t.kind)
+          start += (split_tok -> start(t))
+          split_tok
+        })
+
+    val split_end = removed.dropWhile(stop(_) < change.start + change.removed.length).
+      map (t => {
+          val split_tok =
+            new Token(t.content.substring(change.start + change.removed.length - start(t)), t.kind)
+          start += (split_tok -> start(t))
+          split_tok
+        })
+    // update indices
+    start = removed.foldLeft (start) ((s, t) => s - t)
+    start = split_end.foldLeft (start) ((s, t) =>
+    s + (t -> (change.start + change.added.length)))
+
+    val ins = new Token(change.added, Token.Kind.OTHER)
+    start += (ins -> change.start)
+    
+    var invalid_tokens = split_begin ::: ins :: split_end ::: end
+    var new_tokens: List[Token] = Nil
+    var old_suffix: List[Token] = Nil
+
+    val match_start = invalid_tokens.firstOption.map(start(_)).getOrElse(0)
+    val matcher =
+      ProofDocument.token_pattern.matcher(Token.string_from_tokens(invalid_tokens, start))
+
+    while (matcher.find() && invalid_tokens != Nil) {
+			val kind =
+        if (is_command_keyword(matcher.group))
+          Token.Kind.COMMAND_START
+        else if (matcher.end - matcher.start > 2 && matcher.group.substring(0, 2) == "(*")
+          Token.Kind.COMMENT
+        else
+          Token.Kind.OTHER
+      val new_token = new Token(matcher.group, kind)
+      start += (new_token -> (match_start + matcher.start))
+      new_tokens ::= new_token
+
+      invalid_tokens = invalid_tokens dropWhile (stop(_) < stop(new_token))
+      invalid_tokens match {
+        case t :: ts =>
+          if (start(t) == start(new_token) &&
+              start(t) > change.start + change.added.length) {
+          old_suffix = t :: ts
+          new_tokens = new_tokens.tail
+          invalid_tokens = Nil
+        }
+        case _ =>
+      }
+    }
+    val insert = new_tokens.reverse
+    val new_token_list = begin ::: insert ::: old_suffix
+    token_changed(id, begin.lastOption, insert,
+      old_suffix.firstOption, new_token_list, start)
+  }
+
+  
+  /** command view **/
+
+  private def token_changed(
+    new_id: String,
+    before_change: Option[Token],
+    inserted_tokens: List[Token],
+    after_change: Option[Token],
+    new_tokens: List[Token],
+    new_token_start: Map[Token, Int]):
+  (ProofDocument, StructureChange) =
+  {
+    val new_tokenset = Linear_Set[Token]() ++ new_tokens
+    val cmd_before_change = before_change match {
+      case None => None
+      case Some(bc) =>
+        val cmd_with_bc = commands.find(_.contains(bc)).get
+        if (cmd_with_bc.tokens.last == bc) {
+          if (new_tokenset.next(bc).map(_.is_start).getOrElse(true))
+            Some(cmd_with_bc)
+          else commands.prev(cmd_with_bc)
+        }
+        else commands.prev(cmd_with_bc)
+    }
+
+    val cmd_after_change = after_change match {
+      case None => None
+      case Some(ac) =>
+        val cmd_with_ac = commands.find(_.contains(ac)).get
+        if (ac.is_start)
+          Some(cmd_with_ac)
+        else
+          commands.next(cmd_with_ac)
+    }
+
+    val removed_commands = commands.dropWhile(Some(_) != cmd_before_change).drop(1).
+      takeWhile(Some(_) != cmd_after_change)
+
+    // calculate inserted commands
+    def tokens_to_commands(tokens: List[Token]): List[Command]= {
+      tokens match {
+        case Nil => Nil
+        case t :: ts =>
+          val (cmd, rest) =
+            ts.span(t => t.kind != Token.Kind.COMMAND_START && t.kind != Token.Kind.COMMENT)
+          new Command(t :: cmd, new_token_start) :: tokens_to_commands(rest)
+      }
+    }
+
+    val split_begin =
+      if (before_change.isDefined) {
+        val changed =
+          if (cmd_before_change.isDefined)
+            new_tokens.dropWhile(_ != cmd_before_change.get.tokens.last).drop(1)
+          else new_tokenset
+        if (changed.exists(_ == before_change.get))
+          changed.takeWhile(_ != before_change.get).toList :::
+            List(before_change.get)
+        else Nil
+      } else Nil
+
+    val split_end =
+      if (after_change.isDefined) {
+        val unchanged = new_tokens.dropWhile(_ != after_change.get)
+        if(cmd_after_change.isDefined) {
+          if (unchanged.exists(_ == cmd_after_change.get.tokens.first))
+            unchanged.takeWhile(_ != cmd_after_change.get.tokens.first).toList
+          else Nil
+        } else {
+          unchanged
+        }
+      } else Nil
+
+    val rescan_begin =
+      split_begin :::
+        before_change.map(bc => new_tokens.dropWhile(_ != bc).drop(1)).getOrElse(new_tokens)
+    val rescanning_tokens =
+      after_change.map(ac => rescan_begin.takeWhile(_ != ac)).getOrElse(rescan_begin) :::
+        split_end
+    val inserted_commands = tokens_to_commands(rescanning_tokens.toList)
+
+    // build new document
+    val new_commandset = commands.
+      delete_between(cmd_before_change, cmd_after_change).
+      append_after(cmd_before_change, inserted_commands)
+
+
+    val doc =
+      new ProofDocument(new_id, new_tokenset, new_token_start, new_commandset,
+        states -- removed_commands, is_command_keyword)
+
+    val removes =
+      for (cmd <- removed_commands) yield (cmd_before_change -> None)
+    val inserts =
+      for (cmd <- inserted_commands) yield (doc.commands.prev(cmd) -> Some(cmd))
+
+    return (doc, removes.toList ++ inserts)
+  }
+
+  val commands_offsets = {
+    var last_stop = 0
+    (for (c <- commands) yield {
+      val r = c -> (last_stop,c.stop(this))
+      last_stop = c.stop(this)
+      r
+    }).toArray
+  }
+
+  def command_at(pos: Int): Option[Command] =
+    find_command(pos, 0, commands_offsets.length)
+
+  // use a binary search to find commands for a given offset
+  private def find_command(pos: Int, array_start: Int, array_stop: Int): Option[Command] =
+  {
+    val middle_index = (array_start + array_stop) / 2
+    if (middle_index >= commands_offsets.length) return None
+    val (middle, (start, stop)) = commands_offsets(middle_index)
+    // does middle contain pos?
+    if (start <= pos && pos < stop)
+      Some(middle)
+    else if (start > pos)
+      find_command(pos, array_start, middle_index)
+    else if (stop <= pos)
+      find_command(pos, middle_index + 1, array_stop)
+    else error("impossible")
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/prover.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,175 @@
+/*
+ * Higher-level prover communication: interactive document model
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.prover
+
+
+import scala.actors.Actor, Actor._
+
+import javax.swing.JTextArea
+
+import isabelle.jedit.Isabelle
+import isabelle.proofdocument.{ProofDocument, Change, Token}
+
+
+class Prover(system: Isabelle_System, logic: String)
+{
+  /* incoming messages */
+
+  private var prover_ready = false
+
+  private val receiver = new Actor {
+    def act() {
+      loop {
+        react {
+          case result: Isabelle_Process.Result => handle_result(result)
+          case change: Change if prover_ready => handle_change(change)
+          case bad if prover_ready => System.err.println("prover: ignoring bad message " + bad)
+        }
+      }
+    }
+  }
+
+  def input(change: Change) { receiver ! change }
+
+
+  /* outgoing messages */
+
+  val command_change = new Event_Bus[Command]
+  val document_change = new Event_Bus[ProofDocument]
+
+
+  /* prover process */
+
+  private val process =
+    new Isabelle_Process(system, receiver, "-m", "xsymbols", logic) with Isar_Document
+
+
+  /* outer syntax keywords and completion */
+
+  @volatile private var _command_decls = Map[String, String]()
+  def command_decls() = _command_decls
+
+  @volatile private var _keyword_decls = Set[String]()
+  def keyword_decls() = _keyword_decls
+
+  @volatile private var _completion = Isabelle.completion
+  def completion() = _completion
+
+
+  /* document state information */
+
+  @volatile private var states = Map[Isar_Document.State_ID, Command_State]()
+  @volatile private var commands = Map[Isar_Document.Command_ID, Command]()
+  val document_0 =
+    ProofDocument.empty.
+    set_command_keyword((s: String) => command_decls().contains(s))
+  @volatile private var document_versions = List(document_0)
+
+  def command(id: Isar_Document.Command_ID): Option[Command] = commands.get(id)
+  def document(id: Isar_Document.Document_ID): Option[ProofDocument] =
+    document_versions.find(_.id == id)
+
+
+  /* prover results */
+
+  val output_text_view = new JTextArea    // FIXME separate jEdit component
+
+  private def handle_result(result: Isabelle_Process.Result)
+  {
+    // FIXME separate jEdit component
+    Swing_Thread.later { output_text_view.append(result.toString + "\n") }
+
+    val message = Isabelle_Process.parse_message(system, result)
+
+    val state =
+      Position.id_of(result.props) match {
+        case None => None
+        case Some(id) => commands.get(id) orElse states.get(id) orElse None
+      }
+    if (state.isDefined) state.get ! (this, message)
+    else if (result.kind == Isabelle_Process.Kind.STATUS) {
+      //{{{ global status message
+      message match {
+        case XML.Elem(Markup.MESSAGE, _, elems) =>
+          for (elem <- elems) {
+            elem match {
+              // document edits
+              case XML.Elem(Markup.EDITS, (Markup.ID, doc_id) :: _, edits) =>
+                document_versions.find(_.id == doc_id) match {
+                  case Some(doc) =>
+                    for {
+                      XML.Elem(Markup.EDIT, (Markup.ID, cmd_id) :: (Markup.STATE, state_id) :: _, _)
+                      <- edits }
+                    {
+                      commands.get(cmd_id) match {
+                        case Some(cmd) =>
+                          val state = new Command_State(cmd)
+                          states += (state_id -> state)
+                          doc.states += (cmd -> state)
+                          command_change.event(cmd)   // FIXME really!?
+                        case None =>
+                      }
+                    }
+                  case None =>
+                }
+
+              // command and keyword declarations
+              case XML.Elem(Markup.COMMAND_DECL, (Markup.NAME, name) :: (Markup.KIND, kind) :: _, _) =>
+                _command_decls += (name -> kind)
+                _completion += name
+              case XML.Elem(Markup.KEYWORD_DECL, (Markup.NAME, name) :: _, _) =>
+                _keyword_decls += name
+                _completion += name
+
+              // process ready (after initialization)
+              case XML.Elem(Markup.READY, _, _) => prover_ready = true
+
+              case _ =>
+            }
+          }
+        case _ =>
+      }
+      //}}}
+    }
+  }
+
+
+  /* document changes */
+
+  def begin_document(path: String) {
+    process.begin_document(document_0.id, path)
+  }
+
+  def handle_change(change: Change) {
+    val old = document(change.parent.get.id).get
+    val (doc, changes) = old.text_changed(change)
+    document_versions ::= doc
+
+    val id_changes = changes map { case (c1, c2) =>
+        (c1.map(_.id).getOrElse(document_0.id),
+         c2 match {
+            case None => None
+            case Some(command) =>
+              commands += (command.id -> command)
+              process.define_command(command.id, system.symbols.encode(command.content))
+              Some(command.id)
+          })
+    }
+    process.edit_document(old.id, doc.id, id_changes)
+
+    document_change.event(doc)
+  }
+
+
+  /* main controls */
+
+  def start() { receiver.start() }
+
+  def stop() { process.kill() }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/state.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,117 @@
+/*
+ * Accumulating results from prover
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.prover
+
+
+class State(
+  val command: Command,
+  val status: Command.Status.Value,
+  rev_results: List[XML.Tree],
+  val markup_root: Markup_Text)
+{
+  def this(command: Command) =
+    this(command, Command.Status.UNPROCESSED, Nil, command.empty_markup)
+
+
+  /* content */
+
+  private def set_status(st: Command.Status.Value): State =
+    new State(command, st, rev_results, markup_root)
+
+  private def add_result(res: XML.Tree): State =
+    new State(command, status, res :: rev_results, markup_root)
+
+  private def add_markup(node: Markup_Tree): State =
+    new State(command, status, rev_results, markup_root + node)
+
+  lazy val results = rev_results.reverse
+
+
+  /* markup */
+
+  lazy val highlight: Markup_Text =
+  {
+    markup_root.filter(_.info match {
+      case Command.HighlightInfo(_) => true
+      case _ => false
+    })
+  }
+
+  private lazy val types: List[Markup_Node] =
+    markup_root.filter(_.info match {
+      case Command.TypeInfo(_) => true
+      case _ => false }).flatten
+
+  def type_at(pos: Int): Option[String] =
+  {
+    types.find(t => t.start <= pos && pos < t.stop) match {
+      case Some(t) =>
+        t.info match {
+          case Command.TypeInfo(ty) => Some(command.content(t.start, t.stop) + ": " + ty)
+          case _ => None
+        }
+      case None => None
+    }
+  }
+
+  private lazy val refs: List[Markup_Node] =
+    markup_root.filter(_.info match {
+      case Command.RefInfo(_, _, _, _) => true
+      case _ => false }).flatten
+
+  def ref_at(pos: Int): Option[Markup_Node] =
+    refs.find(t => t.start <= pos && pos < t.stop)
+
+
+  /* message dispatch */
+
+  def + (prover: Prover, message: XML.Tree): State =
+  {
+    val changed: State =
+      message match {
+        case XML.Elem(Markup.MESSAGE, (Markup.CLASS, Markup.STATUS) :: _, elems) =>
+          (this /: elems)((state, elem) =>
+            elem match {
+              case XML.Elem(Markup.UNPROCESSED, _, _) => state.set_status(Command.Status.UNPROCESSED)
+              case XML.Elem(Markup.FINISHED, _, _) => state.set_status(Command.Status.FINISHED)
+              case XML.Elem(Markup.FAILED, _, _) => state.set_status(Command.Status.FAILED)
+              case XML.Elem(kind, atts, body) =>
+                val (begin, end) = Position.offsets_of(atts)
+                if (begin.isEmpty || end.isEmpty) state
+                else if (kind == Markup.ML_TYPING) {
+                  val info = body.first.asInstanceOf[XML.Text].content   // FIXME proper match!?
+                  state.add_markup(
+                    command.markup_node(begin.get - 1, end.get - 1, Command.TypeInfo(info)))
+                }
+                else if (kind == Markup.ML_REF) {
+                  body match {
+                    case List(XML.Elem(Markup.ML_DEF, atts, _)) =>
+                      state.add_markup(command.markup_node(
+                        begin.get - 1, end.get - 1,
+                        Command.RefInfo(
+                          Position.file_of(atts),
+                          Position.line_of(atts),
+                          Position.id_of(atts),
+                          Position.offset_of(atts))))
+                    case _ => state
+                  }
+                }
+                else {
+                  state.add_markup(
+                    command.markup_node(begin.get - 1, end.get - 1, Command.HighlightInfo(kind)))
+                }
+              case _ =>
+                System.err.println("ignored status report: " + elem)
+                state
+            })
+        case _ => add_result(message)
+      }
+    if (!(this eq changed)) prover.command_change.event(command)
+    changed
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/theory_view.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,327 @@
+/*
+ * jEdit text area as document text source
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Johannes Hölzl, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.jedit
+
+import scala.actors.Actor, Actor._
+import scala.collection.mutable
+
+import isabelle.proofdocument.{ProofDocument, Change, Edit, Insert, Remove}
+import isabelle.prover.{Prover, Command}
+
+import java.awt.{Color, Graphics2D}
+import javax.swing.event.{CaretListener, CaretEvent}
+
+import org.gjt.sp.jedit.buffer.{BufferListener, JEditBuffer}
+import org.gjt.sp.jedit.textarea.{JEditTextArea, TextAreaExtension, TextAreaPainter}
+import org.gjt.sp.jedit.syntax.{ModeProvider, SyntaxStyle}
+
+
+object TheoryView
+{
+  def choose_color(command: Command, doc: ProofDocument): Color =
+  {
+    command.status(doc) match {
+      case Command.Status.UNPROCESSED => new Color(255, 228, 225)
+      case Command.Status.FINISHED => new Color(234, 248, 255)
+      case Command.Status.FAILED => new Color(255, 106, 106)
+      case _ => Color.red
+    }
+  }
+}
+
+
+class TheoryView(text_area: JEditTextArea)
+{
+  private val buffer = text_area.getBuffer
+
+
+  /* prover setup */
+
+  val prover: Prover = new Prover(Isabelle.system, Isabelle.default_logic())
+
+  prover.command_change += ((command: Command) =>
+    if (current_document().commands.contains(command))
+      Swing_Thread.later {
+        // FIXME proper handling of buffer vs. text areas
+        // repaint if buffer is active
+        if (text_area.getBuffer == buffer) {
+          update_syntax(command)
+          invalidate_line(command)
+          overview.repaint()
+        }
+      })
+
+
+  /* changes vs. edits */
+
+  private val change_0 = new Change(prover.document_0.id, None, Nil)
+  private var _changes = List(change_0)   // owned by Swing/AWT thread
+  def changes = _changes
+  private var current_change = change_0
+
+  private val edits = new mutable.ListBuffer[Edit]   // owned by Swing thread
+
+  private val edits_delay = Swing_Thread.delay_last(300) {
+    if (!edits.isEmpty) {
+      val change = new Change(Isabelle.system.id(), Some(current_change), edits.toList)
+      _changes ::= change
+      prover.input(change)
+      current_change = change
+      edits.clear
+    }
+  }
+
+
+  /* buffer_listener */
+
+  private val buffer_listener = new BufferListener {
+    override def preContentInserted(buffer: JEditBuffer,
+      start_line: Int, offset: Int, num_lines: Int, length: Int)
+    {
+      edits += Insert(offset, buffer.getText(offset, length))
+      edits_delay()
+    }
+
+    override def preContentRemoved(buffer: JEditBuffer,
+      start_line: Int, start: Int, num_lines: Int, removed_length: Int)
+    {
+      edits += Remove(start, buffer.getText(start, removed_length))
+      edits_delay()
+    }
+
+    override def contentInserted(buffer: JEditBuffer,
+      start_line: Int, offset: Int, num_lines: Int, length: Int) { }
+
+    override def contentRemoved(buffer: JEditBuffer,
+      start_line: Int, offset: Int, num_lines: Int, length: Int) { }
+
+    override def bufferLoaded(buffer: JEditBuffer) { }
+    override def foldHandlerChanged(buffer: JEditBuffer) { }
+    override def foldLevelChanged(buffer: JEditBuffer, start_line: Int, end_line: Int) { }
+    override def transactionComplete(buffer: JEditBuffer) { }
+  }
+
+
+  /* text_area_extension */
+
+  private val text_area_extension = new TextAreaExtension {
+    override def paintValidLine(gfx: Graphics2D,
+      screen_line: Int, physical_line: Int, start: Int, end: Int, y: Int)
+    {
+      val document = current_document()
+      def from_current(pos: Int) = TheoryView.this.from_current(document, pos)
+      def to_current(pos: Int) = TheoryView.this.to_current(document, pos)
+      val saved_color = gfx.getColor
+
+      val metrics = text_area.getPainter.getFontMetrics
+
+      // encolor phase
+      var cmd = document.command_at(from_current(start))
+      while (cmd.isDefined && cmd.get.start(document) < end) {
+        val e = cmd.get
+        val begin = start max to_current(e.start(document))
+        val finish = (end - 1) min to_current(e.stop(document))
+        encolor(gfx, y, metrics.getHeight, begin, finish,
+          TheoryView.choose_color(e, document), true)
+        cmd = document.commands.next(e)
+      }
+
+      gfx.setColor(saved_color)
+    }
+
+    override def getToolTipText(x: Int, y: Int): String =
+    {
+      val document = current_document()
+      val offset = from_current(document, text_area.xyToOffset(x, y))
+      document.command_at(offset) match {
+        case Some(cmd) =>
+          document.token_start(cmd.tokens.first)
+          cmd.type_at(document, offset - cmd.start(document)).getOrElse(null)
+        case None => null
+      }
+    }
+  }
+
+
+  /* activation */
+
+  private val overview = new Document_Overview(prover, text_area, to_current)
+
+  private val selected_state_controller = new CaretListener {
+    override def caretUpdate(e: CaretEvent) {
+      val doc = current_document()
+      doc.command_at(e.getDot) match {
+        case Some(cmd)
+          if (doc.token_start(cmd.tokens.first) <= e.getDot &&
+            Isabelle.plugin.selected_state != cmd) =>
+          Isabelle.plugin.selected_state = cmd
+        case _ =>
+      }
+    }
+  }
+
+  def activate() {
+    text_area.addCaretListener(selected_state_controller)
+    text_area.addLeftOfScrollBar(overview)
+    text_area.getPainter.
+      addExtension(TextAreaPainter.LINE_BACKGROUND_LAYER + 1, text_area_extension)
+    buffer.setTokenMarker(new DynamicTokenMarker(buffer, prover))
+    buffer.addBufferListener(buffer_listener)
+
+    val dockable =
+      text_area.getView.getDockableWindowManager.getDockable("isabelle-output")
+    if (dockable != null) {
+      val output_dockable = dockable.asInstanceOf[OutputDockable]
+      val output_text_view = prover.output_text_view
+      output_dockable.set_text(output_text_view)
+    }
+
+    buffer.propertiesChanged()
+  }
+
+  def deactivate() {
+    buffer.setTokenMarker(buffer.getMode.getTokenMarker)
+    buffer.removeBufferListener(buffer_listener)
+    text_area.getPainter.removeExtension(text_area_extension)
+    text_area.removeLeftOfScrollBar(overview)
+    text_area.removeCaretListener(selected_state_controller)
+  }
+
+
+  /* history of changes */
+
+  private def doc_or_pred(c: Change): ProofDocument =
+    prover.document(c.id).getOrElse(doc_or_pred(c.parent.get))
+
+  def current_document() = doc_or_pred(current_change)
+
+
+  /* update to desired version */
+
+  def set_version(goal: Change) {
+    // changes in buffer must be ignored
+    buffer.removeBufferListener(buffer_listener)
+
+    def apply(change: Change): Unit = change.edits.foreach {
+      case Insert(start, text) => buffer.insert(start, text)
+      case Remove(start, text) => buffer.remove(start, text.length)
+    }
+
+    def unapply(change: Change): Unit = change.edits.reverse.foreach {
+      case Insert(start, text) => buffer.remove(start, text.length)
+      case Remove(start, text) => buffer.insert(start, text)
+    }
+
+    // undo/redo changes
+    val ancs_current = current_change.ancestors
+    val ancs_goal = goal.ancestors
+    val paired = ancs_current.reverse zip ancs_goal.reverse
+    def last_common[A](xs: List[(A, A)]): Option[A] = {
+      xs match {
+        case (x, y) :: xs =>
+          if (x == y)
+            xs match {
+              case (a, b) :: ys =>
+                if (a == b) last_common(xs)
+                else Some(x)
+              case _ => Some(x)
+            }
+          else None
+        case _ => None
+      }
+    }
+    val common_anc = last_common(paired).get
+
+    ancs_current.takeWhile(_ != common_anc) map unapply
+    ancs_goal.takeWhile(_ != common_anc).reverse map apply
+
+    current_change = goal
+    // invoke repaint
+    buffer.propertiesChanged()
+    invalidate_all()
+    overview.repaint()
+
+    // track changes in buffer
+    buffer.addBufferListener(buffer_listener)
+  }
+
+
+  /* transforming offsets */
+
+  private def changes_from(doc: ProofDocument): List[Edit] =
+    List.flatten(current_change.ancestors(_.id == doc.id).reverse.map(_.edits)) :::
+      edits.toList
+
+  def from_current(doc: ProofDocument, offset: Int): Int =
+    (offset /: changes_from(doc).reverse) ((i, change) => change before i)
+
+  def to_current(doc: ProofDocument, offset: Int): Int =
+    (offset /: changes_from(doc)) ((i, change) => change after i)
+
+
+  private def lines_of_command(cmd: Command) =
+  {
+    val document = current_document()
+    (buffer.getLineOfOffset(to_current(document, cmd.start(document))),
+     buffer.getLineOfOffset(to_current(document, cmd.stop(document))))
+  }
+
+
+  /* (re)painting */
+
+  private val update_delay = Swing_Thread.delay_first(500) { buffer.propertiesChanged() }
+
+  private def update_syntax(cmd: Command) {
+    val (line1, line2) = lines_of_command(cmd)
+    if (line2 >= text_area.getFirstLine &&
+      line1 <= text_area.getFirstLine + text_area.getVisibleLines)
+        update_delay()
+  }
+
+  private def invalidate_line(cmd: Command) =
+  {
+    val (start, stop) = lines_of_command(cmd)
+    text_area.invalidateLineRange(start, stop)
+
+    if (Isabelle.plugin.selected_state == cmd)
+      Isabelle.plugin.selected_state = cmd  // update State view
+  }
+
+  private def invalidate_all() =
+    text_area.invalidateLineRange(text_area.getFirstPhysicalLine,
+      text_area.getLastPhysicalLine)
+
+  private def encolor(gfx: Graphics2D,
+    y: Int, height: Int, begin: Int, finish: Int, color: Color, fill: Boolean)
+  {
+    val start = text_area.offsetToXY(begin)
+    val stop =
+      if (finish < buffer.getLength) text_area.offsetToXY(finish)
+      else {
+        val p = text_area.offsetToXY(finish - 1)
+        val metrics = text_area.getPainter.getFontMetrics
+        p.x = p.x + (metrics.charWidth(' ') max metrics.getMaxAdvance)
+        p
+      }
+
+    if (start != null && stop != null) {
+      gfx.setColor(color)
+      if (fill) gfx.fillRect(start.x, y, stop.x - start.x, height)
+      else gfx.drawRect(start.x, y, stop.x - start.x, height)
+    }
+  }
+
+
+  /* init */
+
+  prover.start()
+
+  edits += Insert(0, buffer.getText(0, buffer.getLength))
+  edits_delay()
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/token.scala	Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,42 @@
+/*
+ * Document tokens as text ranges
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.proofdocument
+
+
+import isabelle.prover.Command
+
+
+object Token {
+  object Kind extends Enumeration
+  {
+    val COMMAND_START = Value("COMMAND_START")
+    val COMMENT = Value("COMMENT")
+    val OTHER = Value("OTHER")
+  }
+
+  def string_from_tokens(tokens: List[Token], starts: Token => Int): String = {
+    def stop(t: Token) = starts(t) + t.length
+    tokens match {
+      case Nil => ""
+      case tok :: toks =>
+        val (res, _) = toks.foldLeft(tok.content, stop(tok))((a, token) =>
+          (a._1 + " " * (starts(token) - a._2) + token.content, stop(token)))
+        res
+    }
+  }
+
+}
+
+class Token(
+  val content: String,
+  val kind: Token.Kind.Value)
+{
+  override def toString = content
+  val length = content.length
+  val is_start = kind == Token.Kind.COMMAND_START || kind == Token.Kind.COMMENT
+}
--- a/src/Tools/jEdit/src/prover/Command.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * Prover commands with semantic state
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.prover
-
-
-import scala.actors.Actor, Actor._
-
-import scala.collection.mutable
-
-import isabelle.proofdocument.{Token, ProofDocument}
-import isabelle.jedit.{Isabelle, Plugin}
-import isabelle.XML
-
-
-trait Accumulator extends Actor
-{
-  start() // start actor
-
-  protected var _state: State
-  def state = _state
-
-  override def act() {
-    loop {
-      react {
-        case (prover: Prover, message: XML.Tree) => _state = _state.+(prover, message)
-        case bad => System.err.println("prover: ignoring bad message " + bad)
-      }
-    }
-  }
-}
-
-
-object Command
-{
-  object Status extends Enumeration
-  {
-    val UNPROCESSED = Value("UNPROCESSED")
-    val FINISHED = Value("FINISHED")
-    val FAILED = Value("FAILED")
-  }
-
-  case class HighlightInfo(highlight: String) { override def toString = highlight }
-  case class TypeInfo(ty: String)
-  case class RefInfo(file: Option[String], line: Option[Int],
-    command_id: Option[String], offset: Option[Int])
-}
-
-
-class Command(
-    val tokens: List[Token],
-    val starts: Map[Token, Int]) extends Accumulator
-{
-  require(!tokens.isEmpty)
-
-  val id = Isabelle.system.id()
-  override def hashCode = id.hashCode
-
-
-  /* content */
-
-  override def toString = name
-
-  val name = tokens.head.content
-  val content: String = Token.string_from_tokens(tokens, starts)
-  def content(i: Int, j: Int): String = content.substring(i, j)
-  val symbol_index = new Symbol.Index(content)
-
-  def start(doc: ProofDocument) = doc.token_start(tokens.first)
-  def stop(doc: ProofDocument) = doc.token_start(tokens.last) + tokens.last.length
-
-  def contains(p: Token) = tokens.contains(p)
-
-  protected override var _state = new State(this)
-
-
-  /* markup */
-
-  lazy val empty_markup = new Markup_Text(Nil, content)
-
-  def markup_node(begin: Int, end: Int, info: Any): Markup_Tree =
-  {
-    val start = symbol_index.decode(begin)
-    val stop = symbol_index.decode(end)
-    new Markup_Tree(new Markup_Node(start, stop, info), Nil)
-  }
-
-
-  /* results, markup, ... */
-
-  private val empty_cmd_state = new Command_State(this)
-  private def cmd_state(doc: ProofDocument) =
-    doc.states.getOrElse(this, empty_cmd_state)
-
-  def status(doc: ProofDocument) = cmd_state(doc).state.status
-  def results(doc: ProofDocument) = cmd_state(doc).results
-  def markup_root(doc: ProofDocument) = cmd_state(doc).markup_root
-  def highlight(doc: ProofDocument) = cmd_state(doc).highlight
-  def type_at(doc: ProofDocument, offset: Int) = cmd_state(doc).type_at(offset)
-  def ref_at(doc: ProofDocument, offset: Int) = cmd_state(doc).ref_at(offset)
-}
-
-
-class Command_State(val command: Command) extends Accumulator
-{
-  protected override var _state = new State(command)
-
-  def results: List[XML.Tree] =
-    command.state.results ::: state.results
-
-  def markup_root: Markup_Text =
-    (command.state.markup_root /: state.markup_root.markup)(_ + _)
-
-  def type_at(pos: Int): Option[String] = state.type_at(pos)
-
-  def ref_at(pos: Int): Option[Markup_Node] = state.ref_at(pos)
-
-  def highlight: Markup_Text =
-    (command.state.highlight /: state.highlight.markup)(_ + _)
-}
\ No newline at end of file
--- a/src/Tools/jEdit/src/prover/MarkupNode.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * Document markup nodes, with connection to Swing tree model
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.prover
-
-
-import javax.swing.tree.DefaultMutableTreeNode
-
-import isabelle.proofdocument.ProofDocument
-
-
-class Markup_Node(val start: Int, val stop: Int, val info: Any)
-{
-  def fits_into(that: Markup_Node): Boolean =
-    that.start <= this.start && this.stop <= that.stop
-}
-
-
-class Markup_Tree(val node: Markup_Node, val branches: List[Markup_Tree])
-{
-  def set_branches(bs: List[Markup_Tree]): Markup_Tree = new Markup_Tree(node, bs)
-
-  private def add(branch: Markup_Tree) =   // FIXME avoid sort
-    set_branches((branch :: branches) sort ((a, b) => a.node.start < b.node.start))
-
-  private def remove(bs: List[Markup_Tree]) = set_branches(branches -- bs)
-
-  def + (new_tree: Markup_Tree): Markup_Tree =
-  {
-    val new_node = new_tree.node
-    if (new_node fits_into node) {
-      var inserted = false
-      val new_branches =
-        branches.map(branch =>
-          if ((new_node fits_into branch.node) && !inserted) {
-            inserted = true
-            branch + new_tree
-          }
-          else branch)
-      if (!inserted) {
-        // new_tree did not fit into children of this
-        // -> insert between this and its branches
-        val fitting = branches filter(_.node fits_into new_node)
-        (this remove fitting) add ((new_tree /: fitting)(_ + _))
-      }
-      else set_branches(new_branches)
-    }
-    else {
-      System.err.println("ignored nonfitting markup: " + new_node)
-      this
-    }
-  }
-
-  def flatten: List[Markup_Node] =
-  {
-    var next_x = node.start
-    if (branches.isEmpty) List(this.node)
-    else {
-      val filled_gaps =
-        for {
-          child <- branches
-          markups =
-            if (next_x < child.node.start)
-              new Markup_Node(next_x, child.node.start, node.info) :: child.flatten
-            else child.flatten
-          update = (next_x = child.node.stop)
-          markup <- markups
-        } yield markup
-      if (next_x < node.stop)
-        filled_gaps + new Markup_Node(next_x, node.stop, node.info)
-      else filled_gaps
-    }
-  }
-}
-
-
-class Markup_Text(val markup: List[Markup_Tree], val content: String)
-{
-  private lazy val root =
-    new Markup_Tree(new Markup_Node(0, content.length, None), markup)
-
-  def + (new_tree: Markup_Tree): Markup_Text =
-    new Markup_Text((root + new_tree).branches, content)
-
-  def filter(pred: Markup_Node => Boolean): Markup_Text =
-  {
-    def filt(tree: Markup_Tree): List[Markup_Tree] =
-    {
-      val branches = tree.branches.flatMap(filt(_))
-      if (pred(tree.node)) List(tree.set_branches(branches))
-      else branches
-    }
-    new Markup_Text(markup.flatMap(filt(_)), content)
-  }
-
-  def flatten: List[Markup_Node] = markup.flatten(_.flatten)
-
-  def swing_tree(swing_node: Markup_Node => DefaultMutableTreeNode): DefaultMutableTreeNode =
-  {
-    def swing(tree: Markup_Tree): DefaultMutableTreeNode =
-    {
-      val node = swing_node(tree.node)
-      tree.branches foreach ((branch: Markup_Tree) => node.add(swing(branch)))
-      node
-    }
-    swing(root)
-  }
-}
--- a/src/Tools/jEdit/src/prover/Prover.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-/*
- * Higher-level prover communication: interactive document model
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- * @author Makarius
- */
-
-package isabelle.prover
-
-
-import scala.actors.Actor, Actor._
-
-import javax.swing.JTextArea
-
-import isabelle.jedit.Isabelle
-import isabelle.proofdocument.{ProofDocument, Change, Token}
-
-
-class Prover(system: Isabelle_System, logic: String)
-{
-  /* incoming messages */
-
-  private var prover_ready = false
-
-  private val receiver = new Actor {
-    def act() {
-      loop {
-        react {
-          case result: Isabelle_Process.Result => handle_result(result)
-          case change: Change if prover_ready => handle_change(change)
-          case bad if prover_ready => System.err.println("prover: ignoring bad message " + bad)
-        }
-      }
-    }
-  }
-
-  def input(change: Change) { receiver ! change }
-
-
-  /* outgoing messages */
-
-  val command_change = new Event_Bus[Command]
-  val document_change = new Event_Bus[ProofDocument]
-
-
-  /* prover process */
-
-  private val process =
-    new Isabelle_Process(system, receiver, "-m", "xsymbols", logic) with Isar_Document
-
-
-  /* outer syntax keywords and completion */
-
-  @volatile private var _command_decls = Map[String, String]()
-  def command_decls() = _command_decls
-
-  @volatile private var _keyword_decls = Set[String]()
-  def keyword_decls() = _keyword_decls
-
-  @volatile private var _completion = Isabelle.completion
-  def completion() = _completion
-
-
-  /* document state information */
-
-  @volatile private var states = Map[Isar_Document.State_ID, Command_State]()
-  @volatile private var commands = Map[Isar_Document.Command_ID, Command]()
-  val document_0 =
-    ProofDocument.empty.
-    set_command_keyword((s: String) => command_decls().contains(s))
-  @volatile private var document_versions = List(document_0)
-
-  def command(id: Isar_Document.Command_ID): Option[Command] = commands.get(id)
-  def document(id: Isar_Document.Document_ID): Option[ProofDocument] =
-    document_versions.find(_.id == id)
-
-
-  /* prover results */
-
-  val output_text_view = new JTextArea    // FIXME separate jEdit component
-
-  private def handle_result(result: Isabelle_Process.Result)
-  {
-    // FIXME separate jEdit component
-    Swing_Thread.later { output_text_view.append(result.toString + "\n") }
-
-    val message = Isabelle_Process.parse_message(system, result)
-
-    val state =
-      Position.id_of(result.props) match {
-        case None => None
-        case Some(id) => commands.get(id) orElse states.get(id) orElse None
-      }
-    if (state.isDefined) state.get ! (this, message)
-    else if (result.kind == Isabelle_Process.Kind.STATUS) {
-      //{{{ global status message
-      message match {
-        case XML.Elem(Markup.MESSAGE, _, elems) =>
-          for (elem <- elems) {
-            elem match {
-              // document edits
-              case XML.Elem(Markup.EDITS, (Markup.ID, doc_id) :: _, edits) =>
-                document_versions.find(_.id == doc_id) match {
-                  case Some(doc) =>
-                    for {
-                      XML.Elem(Markup.EDIT, (Markup.ID, cmd_id) :: (Markup.STATE, state_id) :: _, _)
-                      <- edits }
-                    {
-                      commands.get(cmd_id) match {
-                        case Some(cmd) =>
-                          val state = new Command_State(cmd)
-                          states += (state_id -> state)
-                          doc.states += (cmd -> state)
-                          command_change.event(cmd)   // FIXME really!?
-                        case None =>
-                      }
-                    }
-                  case None =>
-                }
-
-              // command and keyword declarations
-              case XML.Elem(Markup.COMMAND_DECL, (Markup.NAME, name) :: (Markup.KIND, kind) :: _, _) =>
-                _command_decls += (name -> kind)
-                _completion += name
-              case XML.Elem(Markup.KEYWORD_DECL, (Markup.NAME, name) :: _, _) =>
-                _keyword_decls += name
-                _completion += name
-
-              // process ready (after initialization)
-              case XML.Elem(Markup.READY, _, _) => prover_ready = true
-
-              case _ =>
-            }
-          }
-        case _ =>
-      }
-      //}}}
-    }
-  }
-
-
-  /* document changes */
-
-  def begin_document(path: String) {
-    process.begin_document(document_0.id, path)
-  }
-
-  def handle_change(change: Change) {
-    val old = document(change.parent.get.id).get
-    val (doc, changes) = old.text_changed(change)
-    document_versions ::= doc
-
-    val id_changes = changes map { case (c1, c2) =>
-        (c1.map(_.id).getOrElse(document_0.id),
-         c2 match {
-            case None => None
-            case Some(command) =>
-              commands += (command.id -> command)
-              process.define_command(command.id, system.symbols.encode(command.content))
-              Some(command.id)
-          })
-    }
-    process.edit_document(old.id, doc.id, id_changes)
-
-    document_change.event(doc)
-  }
-
-
-  /* main controls */
-
-  def start() { receiver.start() }
-
-  def stop() { process.kill() }
-}
--- a/src/Tools/jEdit/src/prover/State.scala	Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Accumulating results from prover
- *
- * @author Fabian Immler, TU Munich
- * @author Makarius
- */
-
-package isabelle.prover
-
-
-class State(
-  val command: Command,
-  val status: Command.Status.Value,
-  rev_results: List[XML.Tree],
-  val markup_root: Markup_Text)
-{
-  def this(command: Command) =
-    this(command, Command.Status.UNPROCESSED, Nil, command.empty_markup)
-
-
-  /* content */
-
-  private def set_status(st: Command.Status.Value): State =
-    new State(command, st, rev_results, markup_root)
-
-  private def add_result(res: XML.Tree): State =
-    new State(command, status, res :: rev_results, markup_root)
-
-  private def add_markup(node: Markup_Tree): State =
-    new State(command, status, rev_results, markup_root + node)
-
-  lazy val results = rev_results.reverse
-
-
-  /* markup */
-
-  lazy val highlight: Markup_Text =
-  {
-    markup_root.filter(_.info match {
-      case Command.HighlightInfo(_) => true
-      case _ => false
-    })
-  }
-
-  private lazy val types: List[Markup_Node] =
-    markup_root.filter(_.info match {
-      case Command.TypeInfo(_) => true
-      case _ => false }).flatten
-
-  def type_at(pos: Int): Option[String] =
-  {
-    types.find(t => t.start <= pos && pos < t.stop) match {
-      case Some(t) =>
-        t.info match {
-          case Command.TypeInfo(ty) => Some(command.content(t.start, t.stop) + ": " + ty)
-          case _ => None
-        }
-      case None => None
-    }
-  }
-
-  private lazy val refs: List[Markup_Node] =
-    markup_root.filter(_.info match {
-      case Command.RefInfo(_, _, _, _) => true
-      case _ => false }).flatten
-
-  def ref_at(pos: Int): Option[Markup_Node] =
-    refs.find(t => t.start <= pos && pos < t.stop)
-
-
-  /* message dispatch */
-
-  def + (prover: Prover, message: XML.Tree): State =
-  {
-    val changed: State =
-      message match {
-        case XML.Elem(Markup.MESSAGE, (Markup.CLASS, Markup.STATUS) :: _, elems) =>
-          (this /: elems)((state, elem) =>
-            elem match {
-              case XML.Elem(Markup.UNPROCESSED, _, _) => state.set_status(Command.Status.UNPROCESSED)
-              case XML.Elem(Markup.FINISHED, _, _) => state.set_status(Command.Status.FINISHED)
-              case XML.Elem(Markup.FAILED, _, _) => state.set_status(Command.Status.FAILED)
-              case XML.Elem(kind, atts, body) =>
-                val (begin, end) = Position.offsets_of(atts)
-                if (begin.isEmpty || end.isEmpty) state
-                else if (kind == Markup.ML_TYPING) {
-                  val info = body.first.asInstanceOf[XML.Text].content   // FIXME proper match!?
-                  state.add_markup(
-                    command.markup_node(begin.get - 1, end.get - 1, Command.TypeInfo(info)))
-                }
-                else if (kind == Markup.ML_REF) {
-                  body match {
-                    case List(XML.Elem(Markup.ML_DEF, atts, _)) =>
-                      state.add_markup(command.markup_node(
-                        begin.get - 1, end.get - 1,
-                        Command.RefInfo(
-                          Position.file_of(atts),
-                          Position.line_of(atts),
-                          Position.id_of(atts),
-                          Position.offset_of(atts))))
-                    case _ => state
-                  }
-                }
-                else {
-                  state.add_markup(
-                    command.markup_node(begin.get - 1, end.get - 1, Command.HighlightInfo(kind)))
-                }
-              case _ =>
-                System.err.println("ignored status report: " + elem)
-                state
-            })
-        case _ => add_result(message)
-      }
-    if (!(this eq changed)) prover.command_change.event(command)
-    changed
-  }
-}