abs. stops, markup nodes depend on doc-version;
authorimmler@in.tum.de
Wed, 22 Apr 2009 17:35:49 +0200
changeset 34554 7dc6c231da40
parent 34553 d013be0adb66
child 34555 7c001369956a
abs. stops, markup nodes depend on doc-version; fixed missing positions in ProofDocument.text_changed; relink only changed commands in ProofDocument.token_changed
src/Tools/jEdit/src/jedit/DynamicTokenMarker.scala
src/Tools/jEdit/src/jedit/IsabelleSideKickParser.scala
src/Tools/jEdit/src/jedit/PhaseOverviewPanel.scala
src/Tools/jEdit/src/jedit/TheoryView.scala
src/Tools/jEdit/src/proofdocument/ProofDocument.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/utils/LinearSet.scala
--- a/src/Tools/jEdit/src/jedit/DynamicTokenMarker.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/jedit/DynamicTokenMarker.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -74,22 +74,22 @@
     val start = buffer.getLineStartOffset(line)
     val stop = start + line_segment.count
 
-    val current_document = prover.document
-   
-    def to: Int => Int = Isabelle.prover_setup(buffer).get.theory_view.to_current(current_document.id, _)
-    def from: Int => Int = Isabelle.prover_setup(buffer).get.theory_view.from_current(current_document.id, _)
+    val document = prover.document
+
+    def to: Int => Int = Isabelle.prover_setup(buffer).get.theory_view.to_current(document.id, _)
+    def from: Int => Int = Isabelle.prover_setup(buffer).get.theory_view.from_current(document.id, _)
 
     var next_x = start
     for {
-      command <- current_document.commands.dropWhile(_.stop <= from(start)).takeWhile(_.start < from(stop))
+      command <- document.commands.dropWhile(_.stop(document) <= from(start)).takeWhile(_.start(document) < from(stop))
       markup <- command.root_node.flatten
-      if(to(markup.abs_stop) > start)
-      if(to(markup.abs_start) < stop)
+      if(to(markup.abs_stop(document)) > start)
+      if(to(markup.abs_start(document)) < stop)
       byte = DynamicTokenMarker.choose_byte(markup.kind)
-      token_start = to(markup.abs_start) - start max 0
-      token_length = to(markup.abs_stop) - to(markup.abs_start) -
-                     (start - to(markup.abs_start) max 0) -
-                     (to(markup.abs_stop) - stop max 0)
+      token_start = to(markup.abs_start(document)) - start max 0
+      token_length = to(markup.abs_stop(document)) - to(markup.abs_start(document)) -
+                     (start - to(markup.abs_start(document)) max 0) -
+                     (to(markup.abs_stop(document)) - stop max 0)
     } {
       if (start + token_start > next_x)
         handler.handleToken(line_segment, 1, next_x - start, start + token_start - next_x, context)
--- a/src/Tools/jEdit/src/jedit/IsabelleSideKickParser.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/jedit/IsabelleSideKickParser.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -33,7 +33,7 @@
     if (prover_setup.isDefined) {
         val document = prover_setup.get.prover.document
         for (command <- document.commands)
-          data.root.add(command.root_node.swing_node)
+          data.root.add(command.root_node.swing_node(document))
         
         if (stopped) data.root.add(new DefaultMutableTreeNode("<parser stopped>"))
     } else {
--- a/src/Tools/jEdit/src/jedit/PhaseOverviewPanel.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/jedit/PhaseOverviewPanel.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -7,6 +7,7 @@
 package isabelle.jedit
 
 import isabelle.prover.Command
+import isabelle.proofdocument.ProofDocument
 import isabelle.utils.Delay
 
 import javax.swing._
@@ -57,9 +58,9 @@
     } else ""
 	}
 
-  private def paintCommand(command : Command, buffer : JEditBuffer, doc_id: String, gfx : Graphics) {
-    val line1 = buffer.getLineOfOffset(to_current(doc_id, command.start))
-    val line2 = buffer.getLineOfOffset(to_current(doc_id, command.stop - 1)) + 1
+  private def paintCommand(command : Command, buffer : JEditBuffer, doc: ProofDocument, gfx : Graphics) {
+    val line1 = buffer.getLineOfOffset(to_current(doc.id, command.start(doc)))
+    val line2 = buffer.getLineOfOffset(to_current(doc.id, command.stop(doc) - 1)) + 1
     val y = lineToY(line1)
     val height = lineToY(line2) - y - 1
     val (light, dark) = command.status match {
@@ -82,7 +83,7 @@
 		val buffer = textarea.getBuffer
     val document = prover.document
     for (c <- document.commands)
-      paintCommand(c, buffer, document.id, gfx)
+      paintCommand(c, buffer, document, gfx)
 
 	}
 
--- a/src/Tools/jEdit/src/jedit/TheoryView.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/jedit/TheoryView.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -66,8 +66,9 @@
 
   private val selected_state_controller = new CaretListener {
     override def caretUpdate(e: CaretEvent) = {
-      val cmd = prover.document.find_command_at(e.getDot)
-      if (cmd != null && cmd.start <= e.getDot &&
+      val doc = prover.document
+      val cmd = doc.find_command_at(e.getDot)
+      if (cmd != null && doc.token_start(cmd.tokens.first) <= e.getDot &&
           Isabelle.prover_setup(buffer).get.selected_state != cmd)
         Isabelle.prover_setup(buffer).get.selected_state = cmd
     }
@@ -141,8 +142,8 @@
   {
     val document = prover.document
     if (text_area != null) {
-      val start = text_area.getLineOfOffset(to_current(document.id, cmd.start))
-      val stop = text_area.getLineOfOffset(to_current(document.id, cmd.stop) - 1)
+      val start = text_area.getLineOfOffset(to_current(document.id, cmd.start(document)))
+      val stop = text_area.getLineOfOffset(to_current(document.id, cmd.stop(document)) - 1)
       text_area.invalidateLineRange(start, stop)
 
       if (Isabelle.prover_setup(buffer).get.selected_state == cmd)
@@ -189,18 +190,18 @@
 
     val metrics = text_area.getPainter.getFontMetrics
     var e = document.find_command_at(from_current(start))
-    val commands = document.commands.dropWhile(_.stop <= from_current(start)).
-      takeWhile(c => to_current(c.start) < end)
+    val commands = document.commands.dropWhile(_.stop(document) <= from_current(start)).
+      takeWhile(c => to_current(c.start(document)) < end)
     // encolor phase
     for (e <- commands) {
-      val begin = start max to_current(e.start)
-      val finish = end - 1 min to_current(e.stop)
+      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), true)
 
       // paint details of command
       for (node <- e.root_node.dfs) {
-        val begin = to_current(node.start + e.start)
-        val finish = to_current(node.stop + e.start)
+        val begin = to_current(node.abs_start(document))
+        val finish = to_current(node.abs_stop(document))
         if (finish > start && begin < end) {
           encolor(gfx, y + metrics.getHeight - 2, 1, begin max start, finish min end - 1,
             DynamicTokenMarker.choose_color(node.kind, text_area.getPainter.getStyles), true)
--- a/src/Tools/jEdit/src/proofdocument/ProofDocument.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/proofdocument/ProofDocument.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -75,16 +75,25 @@
     val (removed, end) = remaining.span(token_start(_) <= change.start + change.removed)
     // update indices
     start = end.foldLeft (start) ((s, t) => s + (t -> (s(t) + change.added.length - change.removed)))
-    start = removed.foldLeft (start) ((s, t) => s - t)
 
     val split_begin = removed.takeWhile(start(_) < change.start).
-      map (t => new Token(t.content.substring(0, change.start - start(t)),
-                          t.kind))
+      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).
-      map (t => new Token(t.content.substring(change.start + change.removed - start(t)),
-                          t.kind))
+      map (t => {
+          val split_tok = new Token(t.content.substring(change.start + change.removed - start(t)),
+                          t.kind)
+          start += (split_tok -> start(t))
+          split_tok
+        })
     // update indices
-    start = split_end.foldLeft (start) ((s, t) => s + (t -> (change.start + change.added.length)))
+    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)
@@ -121,77 +130,75 @@
     }
     val insert = new_tokens.reverse
     val new_token_list = begin ::: insert ::: old_suffix
+    val new_tokenset = (LinearSet() ++ new_token_list).asInstanceOf[LinearSet[Token]]
     token_changed(change.id,
                   begin.lastOption,
                   insert,
-                  removed,
                   old_suffix.firstOption,
-                  new_token_list,
+                  new_tokenset,
                   start)
   }
   
   /** command view **/
 
   def find_command_at(pos: Int): Command = {
-    for (cmd <- commands) { if (pos < cmd.stop) return cmd }
+    for (cmd <- commands) { if (pos < cmd.stop(this)) return cmd }
     return null
   }
 
   private def token_changed(new_id: String,
                             before_change: Option[Token],
                             inserted_tokens: List[Token],
-                            removed_tokens: List[Token],
                             after_change: Option[Token],
-                            new_token_list: List[Token],
+                            new_tokenset: LinearSet[Token],
                             new_token_start: Map[Token, Int]): (ProofDocument, StructureChange) =
   {
-    val commands_list = List[Command]() ++ commands
-
-    // calculate removed commands
-    val first_removed = removed_tokens.firstOption
+    val cmd_first_changed =
+      if (before_change.isDefined) commands.find(_.tokens.contains(before_change.get))
+      else None
+    val cmd_last_changed =
+      if (after_change.isDefined) commands.find(_.tokens.contains(after_change.get))
+      else None
 
-    val (begin, remaining) =
-      first_removed match {
-        case None => (Nil, commands_list)
-        case Some(fr) => commands_list.break(_.tokens.contains(fr))
-      }
-    val (removed_commands, end) =
-      after_change match {
-        case None => (remaining, Nil)
-        case Some(ac) => remaining.break(_.tokens.contains(ac))
-      }
+    val cmd_before_change =
+      if (cmd_first_changed.isDefined) commands.prev(cmd_first_changed.get)
+      else None
+    val cmd_after_change =
+      if (cmd_last_changed.isDefined) commands.next(cmd_last_changed.get)
+      else None
 
+    val removed_commands = commands.dropWhile(Some(_) != cmd_first_changed).
+      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(_.kind != Token.Kind.COMMAND_START)
-          new Command(t::cmd) :: tokens_to_commands (rest)
+          new Command(t::cmd, new_token_start) :: tokens_to_commands (rest)
       }
     }
 
-    // calculate inserted commands
-    val new_commands = tokens_to_commands(new_token_list)
-    val new_tokenset = (LinearSet() ++ new_token_list).asInstanceOf[LinearSet[Token]]
-    val new_commandset = (LinearSet() ++ (new_commands)).asInstanceOf[LinearSet[Command]]
-    // drop known commands from the beginning
-    val first_changed = before_change match {
-      case None => new_tokenset.first_elem
-      case Some(bc) => new_tokenset.next(bc)
-    }
-    val changed_commands = first_changed match {
-      case None => Nil
-      case Some(fc) => new_commands.dropWhile(!_.tokens.contains(fc))
-    }
-    val inserted_commands = after_change match {
-      case None => changed_commands
-      case Some(ac) => changed_commands.takeWhile(!_.tokens.contains(ac))
-    }
-    val change = new StructureChange(new_commands.find(_.tokens.contains(before_change)),
-                                     inserted_commands, removed_commands)
+    val split_begin_tokens =
+      if (!cmd_first_changed.isDefined || !before_change.isDefined) Nil
+      else {
+        cmd_first_changed.get.tokens.takeWhile(_ != before_change.get) ::: List(before_change.get)
+      }
+    val split_end_tokens =
+      if (!cmd_last_changed.isDefined || !after_change.isDefined) Nil
+      else {
+        cmd_last_changed.get.tokens.dropWhile(_ != after_change.get)
+      }
+
+    val rescanning_tokens = split_begin_tokens ::: inserted_tokens ::: split_end_tokens
+    val inserted_commands = tokens_to_commands(rescanning_tokens)
+
+    val change = new StructureChange(cmd_before_change, inserted_commands, removed_commands.toList)
     // build new document
-    var new_commands = commands
-    while(new_commands.next())
+    val new_commandset = commands.delete_between(cmd_before_change, cmd_after_change).
+        insert_after(cmd_before_change, inserted_commands)
+
     val doc =
       new ProofDocument(new_id, new_tokenset, new_token_start, new_commandset, active, is_command_keyword)
     return (doc, change)
--- a/src/Tools/jEdit/src/proofdocument/Token.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/proofdocument/Token.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -38,5 +38,5 @@
 
 class Token(val content: String, val kind: Token.Kind.Value) {
   val length = content.length
-  override def toString = content + "(" + kind + ")"
+  override def toString = content
 }
--- a/src/Tools/jEdit/src/prover/Command.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/prover/Command.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -29,7 +29,7 @@
 }
 
 
-class Command(val tokens: List[Token])
+class Command(val tokens: List[Token], val starts: Map[Token, Int])
 {
   val id = Isabelle.plugin.id()
 
@@ -38,10 +38,10 @@
   override def toString = name
 
   val name = tokens.head.content
-  val content:String = Token.string_from_tokens(tokens.takeWhile(_.kind != Token.Kind.COMMENT))
+  val content:String = Token.string_from_tokens(tokens.takeWhile(_.kind != Token.Kind.COMMENT), starts)
 
-  def start = tokens.first.start
-  def stop = tokens.last.stop
+  def start(doc: ProofDocument) = doc.token_start(tokens.first)
+  def stop(doc: ProofDocument) = doc.token_start(tokens.last) + tokens.last.length
 
   /* command status */
 
@@ -80,10 +80,14 @@
   /* markup */
 
   val root_node =
-    new MarkupNode(this, 0, stop - start, id, Markup.COMMAND_SPAN, content)
+    new MarkupNode(this, 0, starts(tokens.last) - starts(tokens.first) + tokens.last.length, id, Markup.COMMAND_SPAN, content)
 
-  def node_from(kind: String, begin: Int, end: Int) = {
-    val markup_content = content.substring(begin, end)
-    new MarkupNode(this, begin, end, id, kind, markup_content)
+  def add_markup(kind: String, begin: Int, end: Int) = {
+    val markup_content = if (end <= content.length) content.substring(begin, end)
+      else {
+        System.err.println (root_node.stop, content, content.length, end)
+        "wrong indices?"
+      }
+    root_node insert new MarkupNode(this, begin, end, id, kind, markup_content)
   }
 }
--- a/src/Tools/jEdit/src/prover/MarkupNode.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/prover/MarkupNode.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -6,6 +6,8 @@
 
 package isabelle.prover
 
+import isabelle.proofdocument.ProofDocument
+
 import sidekick.IAsset
 import javax.swing._
 import javax.swing.text.Position
@@ -13,10 +15,10 @@
 
 object MarkupNode {
 
-  def markup2default_node(node : MarkupNode) : DefaultMutableTreeNode = {
+  def markup2default_node(node: MarkupNode, cmd: Command, doc: ProofDocument) : DefaultMutableTreeNode = {
 
     implicit def int2pos(offset: Int): Position =
-      new Position { def getOffset = offset }
+      new Position { def getOffset = offset; override def toString = offset.toString}
 
     object RelativeAsset extends IAsset {
       override def getIcon : Icon = null
@@ -25,10 +27,10 @@
       override def getName : String = node.id
       override def setName (name : String) = ()
       override def setStart(start : Position) = ()
-      override def getStart : Position = node.abs_start
+      override def getStart : Position = node.abs_start(doc)
       override def setEnd(end : Position) = ()
-      override def getEnd : Position = node.abs_stop
-      override def toString = node.id + ": " + node.kind + "[" + node.start + " - " + node.stop + "]"
+      override def getEnd : Position = node.abs_stop(doc)
+      override def toString = node.id + ": " + node.kind + "[" + getStart + " - " + getEnd + "]"
     }
 
     new DefaultMutableTreeNode(RelativeAsset)
@@ -38,40 +40,27 @@
 class MarkupNode (val base : Command, val start : Int, val stop : Int,
                     val id : String, val kind : String, val desc : String) {
 
-  val swing_node : DefaultMutableTreeNode = MarkupNode.markup2default_node (this)
+  def swing_node(doc: ProofDocument) : DefaultMutableTreeNode = {
+    val node = MarkupNode.markup2default_node (this, base, doc)
+    for (c <- children) node add c.swing_node(doc)
+    node
+  }
+    
+  def abs_start(doc: ProofDocument) = base.start(doc) + start
+  def abs_stop(doc: ProofDocument) = base.start(doc) + stop
 
   var parent : MarkupNode = null
   def orphan = parent == null
 
-  def length = stop - start
-  def abs_start = base.start + start
-  def abs_stop = base.start + stop
-
-  private var children_cell : List[MarkupNode] = Nil
-  //track changes in swing_node
-  def children = children_cell
-  def children_= (cs : List[MarkupNode]) = {
-    swing_node.removeAllChildren
-    for (c <- cs) swing_node add c.swing_node
-    children_cell = cs
-  }
+  var children : List[MarkupNode] = Nil
 
   private def add(child : MarkupNode) {
     child parent = this
-    children_cell = (child :: children) sort ((a, b) => a.start < b.start)
-
-    swing_node add child.swing_node
+    children = (child :: children) sort ((a, b) => a.start < b.start)
   }
 
   private def remove(nodes : List[MarkupNode]) {
-    children_cell = children diff nodes
-
-      for (node <- nodes) try {
-        swing_node remove node.swing_node
-      } catch { case e : IllegalArgumentException =>
-        System.err.println(e.toString)
-        case e => throw e
-      }
+    children = children diff nodes
   }
 
   def dfs : List[MarkupNode] = {
--- a/src/Tools/jEdit/src/prover/Prover.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/prover/Prover.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -190,7 +190,7 @@
                       // inner syntax: id from props
                       else command
                     if (cmd != null) {
-                      cmd.root_node.insert(cmd.node_from(kind, begin, end))
+                      cmd.add_markup(kind, begin, end)
                       command_change(cmd)
                     }
                   case _ =>
@@ -249,7 +249,7 @@
       for (cmd <- changes.removed_commands) yield {
         commands -= cmd.id
         if (cmd.state_id != null) states -= cmd.state_id
-        (document.commands.prev(cmd).map(_.id).getOrElse(document_id0)) -> None
+        changes.before_change.map(_.id).getOrElse(document_id0) -> None
       }
     val inserts =
       for (cmd <- changes.added_commands) yield {
--- a/src/Tools/jEdit/src/utils/LinearSet.scala	Mon Apr 20 20:28:45 2009 +0200
+++ b/src/Tools/jEdit/src/utils/LinearSet.scala	Wed Apr 22 17:35:49 2009 +0200
@@ -43,7 +43,7 @@
   def contains(elem: A): Boolean =
     !isEmpty && (last_elem.get == elem || body.isDefinedAt(elem))
 
-  def insert_after(hook: Option[A], elem: A): LinearSet[A] =
+  private def _insert_after(hook: Option[A], elem: A): LinearSet[A] =
     if (contains(elem)) throw new LinearSet.Duplicate(elem.toString)
     else hook match {
       case Some(hook) =>
@@ -55,8 +55,11 @@
         if (isEmpty) LinearSet.make(Some(elem), Some(elem), Map.empty)
         else LinearSet.make(Some(elem), last_elem, body + (elem -> first_elem.get))
     }
-    
-  def +(elem: A): LinearSet[A] = insert_after(last_elem, elem)
+
+  def insert_after(hook: Option[A], elems: Seq[A]): LinearSet[A] =
+    elems.reverse.foldLeft (this) ((ls, elem) => ls._insert_after(hook, elem))
+
+  def +(elem: A): LinearSet[A] = _insert_after(last_elem, elem)
 
   def delete_after(elem: Option[A]): LinearSet[A] =
     elem match {
@@ -70,7 +73,18 @@
         else if (size == 1) empty
         else LinearSet.make(Some(body(first_elem.get)), last_elem, body - first_elem.get)
     }
-    
+
+  def delete_between(from: Option[A], to: Option[A]): LinearSet[A] = {
+    if(!first_elem.isDefined) this
+    else {
+      val next = if (from == last_elem) None
+                 else if (from == None) first_elem
+                 else from.map(body(_))
+      if (next == to) this
+      else delete_after(from).delete_between(from, to)
+    }
+  }
+
   def -(elem: A): LinearSet[A] =
     if (!contains(elem)) throw new LinearSet.Undefined(elem.toString)
     else delete_after(body find (p => p._2 == elem) map (p => p._1))