propagate header changes to prover process;
authorwenzelm
Sun, 10 Jul 2011 00:21:19 +0200
changeset 43722 9b5dadb0c28d
parent 43721 fad8634cee62
child 43723 8a63c95b1d5b
propagate header changes to prover process; simplified Document case classes; Document.State.assignments: indexed by Version_ID;
src/Pure/PIDE/document.ML
src/Pure/PIDE/document.scala
src/Pure/PIDE/isar_document.ML
src/Pure/PIDE/isar_document.scala
src/Pure/System/session.scala
src/Pure/Thy/thy_header.scala
src/Pure/Thy/thy_syntax.scala
src/Tools/jEdit/src/document_model.scala
--- a/src/Pure/PIDE/document.ML	Sat Jul 09 21:53:27 2011 +0200
+++ b/src/Pure/PIDE/document.ML	Sun Jul 10 00:21:19 2011 +0200
@@ -16,12 +16,14 @@
   val parse_id: string -> id
   val print_id: id -> string
   type edit = string * ((command_id option * command_id option) list) option
+  type header = string * (string * string list * string list)
   type state
   val init_state: state
   val get_theory: state -> version_id -> Position.T -> string -> theory
   val cancel_execution: state -> unit -> unit
   val define_command: command_id -> string -> state -> state
-  val edit: version_id -> version_id -> edit list -> state -> (command_id * exec_id) list * state
+  val edit: version_id -> version_id -> edit list -> header list ->
+    state -> (command_id * exec_id) list * state
   val execute: version_id -> state -> state
   val state: unit -> state
   val change_state: (state -> state) -> unit
@@ -78,6 +80,8 @@
   (*NONE: remove node, SOME: insert/remove commands*)
   ((command_id option * command_id option) list) option;
 
+type header = string * (string * string list * string list);
+
 fun the_entry (Node {entries, ...}) id =
   (case Entries.lookup entries id of
     NONE => err_undef "command entry" id
@@ -309,8 +313,10 @@
 
 in
 
-fun edit (old_id: version_id) (new_id: version_id) edits state =
+fun edit (old_id: version_id) (new_id: version_id) edits headers state =
   let
+    (* FIXME apply headers *)
+
     val old_version = the_version state old_id;
     val _ = Time.now ();  (* FIXME odd workaround *)
     val new_version = fold edit_nodes edits old_version;
--- a/src/Pure/PIDE/document.scala	Sat Jul 09 21:53:27 2011 +0200
+++ b/src/Pure/PIDE/document.scala	Sun Jul 10 00:21:19 2011 +0200
@@ -70,11 +70,6 @@
     val blobs: Map[String, Blob],
     val commands: Linear_Set[Command])
   {
-    /* header */
-
-    def set_header(new_header: Node.Header): Node = copy(header = new_header)
-
-
     /* commands */
 
     private lazy val full_index: (Array[(Command, Text.Offset)], Text.Range) =
@@ -135,25 +130,24 @@
 
   object Version
   {
-    val init: Version = new Version(no_id, Map().withDefaultValue(Node.empty))
+    val init: Version = Version(no_id, Map().withDefaultValue(Node.empty))
   }
 
-  class Version(val id: Version_ID, val nodes: Map[String, Node])
+  sealed case class Version(val id: Version_ID, val nodes: Map[String, Node])
 
 
   /* changes of plain text, eventually resulting in document edits */
 
   object Change
   {
-    val init = new Change(Future.value(Version.init), Nil, Future.value(Nil, Version.init))
+    val init = Change(Future.value(Version.init), Nil, Future.value(Version.init))
   }
 
-  class Change(
+  sealed case class Change(
     val previous: Future[Version],
     val edits: List[Edit_Text],
-    val result: Future[(List[Edit_Command], Version)])
+    val version: Future[Version])
   {
-    val version: Future[Version] = result.map(_._2)
     def is_finished: Boolean = previous.is_finished && version.is_finished
   }
 
@@ -216,7 +210,7 @@
     val versions: Map[Version_ID, Version] = Map(),
     val commands: Map[Command_ID, Command.State] = Map(),
     val execs: Map[Exec_ID, (Command.State, Set[Version])] = Map(),
-    val assignments: Map[Version, State.Assignment] = Map(),
+    val assignments: Map[Version_ID, State.Assignment] = Map(),
     val disposed: Set[ID] = Set(),  // FIXME unused!?
     val history: History = History.init)
   {
@@ -227,7 +221,7 @@
       val id = version.id
       if (versions.isDefinedAt(id) || disposed(id)) fail
       copy(versions = versions + (id -> version),
-        assignments = assignments + (version -> State.Assignment(former_assignment)))
+        assignments = assignments + (id -> State.Assignment(former_assignment)))
     }
 
     def define_command(command: Command): State =
@@ -242,7 +236,8 @@
     def the_version(id: Version_ID): Version = versions.getOrElse(id, fail)
     def the_command(id: Command_ID): Command.State = commands.getOrElse(id, fail)
     def the_exec_state(id: Exec_ID): Command.State = execs.getOrElse(id, fail)._1
-    def the_assignment(version: Version): State.Assignment = assignments.getOrElse(version, fail)
+    def the_assignment(version: Version): State.Assignment =
+      assignments.getOrElse(version.id, fail)
 
     def accumulate(id: ID, message: XML.Elem): (Command.State, State) =
       execs.get(id) match {
@@ -272,22 +267,21 @@
           (st.command, exec_id)
         }
       val new_assignment = the_assignment(version).assign(assigned_execs)
-      val new_state =
-        copy(assignments = assignments + (version -> new_assignment), execs = new_execs)
+      val new_state = copy(assignments = assignments + (id -> new_assignment), execs = new_execs)
       (assigned_execs.map(_._1), new_state)
     }
 
     def is_assigned(version: Version): Boolean =
-      assignments.get(version) match {
+      assignments.get(version.id) match {
         case Some(assgn) => assgn.is_finished
         case None => false
       }
 
     def extend_history(previous: Future[Version],
         edits: List[Edit_Text],
-        result: Future[(List[Edit_Command], Version)]): (Change, State) =
+        version: Future[Version]): (Change, State) =
     {
-      val change = new Change(previous, edits, result)
+      val change = Change(previous, edits, version)
       (change, copy(history = history + change))
     }
 
--- a/src/Pure/PIDE/isar_document.ML	Sat Jul 09 21:53:27 2011 +0200
+++ b/src/Pure/PIDE/isar_document.ML	Sun Jul 10 00:21:19 2011 +0200
@@ -13,7 +13,7 @@
 
 val _ =
   Isabelle_Process.add_command "Isar_Document.edit_version"
-    (fn [old_id_string, new_id_string, edits_yxml] => Document.change_state (fn state =>
+    (fn [old_id_string, new_id_string, edits_yxml, headers_yxml] => Document.change_state (fn state =>
       let
         val old_id = Document.parse_id old_id_string;
         val new_id = Document.parse_id new_id_string;
@@ -26,9 +26,15 @@
                   (XML_Data.dest_pair
                     (XML_Data.dest_option XML_Data.dest_int)
                     (XML_Data.dest_option XML_Data.dest_int))))) (YXML.parse_body edits_yxml);
+        val headers =
+          XML_Data.dest_list
+            (XML_Data.dest_pair XML_Data.dest_string
+              (XML_Data.dest_triple XML_Data.dest_string
+                (XML_Data.dest_list XML_Data.dest_string)
+                (XML_Data.dest_list XML_Data.dest_string))) (YXML.parse_body headers_yxml);
 
       val await_cancellation = Document.cancel_execution state;
-      val (updates, state') = Document.edit old_id new_id edits state;
+      val (updates, state') = Document.edit old_id new_id edits headers state;
       val _ = await_cancellation ();
       val _ =
         Output.status (Markup.markup (Markup.assign new_id)
--- a/src/Pure/PIDE/isar_document.scala	Sat Jul 09 21:53:27 2011 +0200
+++ b/src/Pure/PIDE/isar_document.scala	Sun Jul 10 00:21:19 2011 +0200
@@ -140,9 +140,9 @@
   /* document versions */
 
   def edit_version(old_id: Document.Version_ID, new_id: Document.Version_ID,
-      edits: List[Document.Edit_Command_ID])
+      edits: List[Document.Edit_Command_ID], headers: List[(String, Thy_Header.Header)])
   {
-    val arg =
+    val arg1 =
       XML_Data.make_list(
         XML_Data.make_pair(XML_Data.make_string)(
           XML_Data.make_option(XML_Data.make_list(
@@ -150,7 +150,11 @@
                 XML_Data.make_option(XML_Data.make_long))(
                 XML_Data.make_option(XML_Data.make_long))))))(edits)
 
+    val arg2 =
+      XML_Data.make_list(XML_Data.make_pair(XML_Data.make_string)(Thy_Header.make_xml_data))(headers)
+
     input("Isar_Document.edit_version",
-      Document.ID(old_id), Document.ID(new_id), YXML.string_of_body(arg))
+      Document.ID(old_id), Document.ID(new_id),
+        YXML.string_of_body(arg1), YXML.string_of_body(arg2))
   }
 }
--- a/src/Pure/System/session.scala	Sat Jul 09 21:53:27 2011 +0200
+++ b/src/Pure/System/session.scala	Sun Jul 10 00:21:19 2011 +0200
@@ -165,7 +165,12 @@
   private case object Interrupt
   private case class Init_Node(name: String, header: Document.Node.Header, text: String)
   private case class Edit_Node(name: String, header: Document.Node.Header, edits: List[Text.Edit])
-  private case class Change_Node(name: String, header: Document.Node.Header, change: Document.Change)
+  private case class Change_Node(
+    name: String,
+    doc_edits: List[Document.Edit_Command],
+    header_edits: List[(String, Thy_Header.Header)],
+    previous: Document.Version,
+    version: Document.Version)
 
   private val (_, session_actor) = Simple_Thread.actor("session_actor", daemon = true)
   {
@@ -182,27 +187,36 @@
       val syntax = current_syntax()
       val previous = global_state().history.tip.version
       val doc_edits = edits.map(edit => (name, edit))
-      val result = Future.fork { Thy_Syntax.text_edits(syntax, previous.join, doc_edits) }
-      val change = global_state.change_yield(_.extend_history(previous, doc_edits, result))
+      val result = Future.fork {
+        Thy_Syntax.text_edits(syntax, previous.join, doc_edits, List((name, header)))
+      }
+      val change =
+        global_state.change_yield(_.extend_history(previous, doc_edits, result.map(_._3)))
 
-      change.version.map(_ => {
-        assignments.await { global_state().is_assigned(previous.get_finished) }
-        this_actor ! Change_Node(name, header, change) })
+      result.map {
+        case (doc_edits, header_edits, _) =>
+          assignments.await { global_state().is_assigned(previous.get_finished) }
+          this_actor !
+            Change_Node(name, doc_edits, header_edits, previous.join, change.version.join)
+      }
     }
     //}}}
 
 
     /* resulting changes */
 
-    def handle_change(name: String, header: Document.Node.Header, change: Document.Change)
+    def handle_change(change: Change_Node)
     //{{{
     {
-      val previous = change.previous.get_finished
-      val (node_edits, version) = change.result.get_finished
+      val previous = change.previous
+      val version = change.version
+      val name = change.name
+      val doc_edits = change.doc_edits
+      val header_edits = change.header_edits
 
       var former_assignment = global_state().the_assignment(previous).get_finished
       for {
-        (name, Some(cmd_edits)) <- node_edits
+        (name, Some(cmd_edits)) <- doc_edits
         (prev, None) <- cmd_edits
         removed <- previous.nodes(name).commands.get_after(prev)
       } former_assignment -= removed
@@ -216,14 +230,15 @@
         command.id
       }
       val id_edits =
-        node_edits map {
+        doc_edits map {
           case (name, edits) =>
             val ids =
               edits.map(_.map { case (c1, c2) => (c1.map(id_command), c2.map(id_command)) })
             (name, ids)
         }
+
       global_state.change(_.define_version(version, former_assignment))
-      prover.get.edit_version(previous.id, version.id, id_edits)
+      prover.get.edit_version(previous.id, version.id, id_edits, header_edits)
     }
     //}}}
 
@@ -315,8 +330,8 @@
           handle_edits(name, header, List(Some(text_edits)))
           reply(())
 
-        case Change_Node(name, header, change) if prover.isDefined =>
-          handle_change(name, header, change)
+        case change: Change_Node if prover.isDefined =>
+          handle_change(change)
 
         case input: Isabelle_Process.Input =>
           raw_messages.event(input)
--- a/src/Pure/Thy/thy_header.scala	Sat Jul 09 21:53:27 2011 +0200
+++ b/src/Pure/Thy/thy_header.scala	Sun Jul 10 00:21:19 2011 +0200
@@ -31,6 +31,11 @@
       Header(f(name), imports.map(f), uses.map(f))
   }
 
+  def make_xml_data(header: Header): XML.Body =
+    XML_Data.make_triple(XML_Data.make_string)(
+      XML_Data.make_list(XML_Data.make_string))(
+        XML_Data.make_list(XML_Data.make_string))(header.name, header.imports, header.uses)
+
 
   /* file name */
 
--- a/src/Pure/Thy/thy_syntax.scala	Sat Jul 09 21:53:27 2011 +0200
+++ b/src/Pure/Thy/thy_syntax.scala	Sun Jul 10 00:21:19 2011 +0200
@@ -99,8 +99,12 @@
 
   /** text edits **/
 
-  def text_edits(syntax: Outer_Syntax, previous: Document.Version,
-      edits: List[Document.Edit_Text]): (List[Document.Edit_Command], Document.Version) =
+  def text_edits(
+      syntax: Outer_Syntax,
+      previous: Document.Version,
+      edits: List[Document.Edit_Text],
+      headers: List[(String, Document.Node.Header)])
+    : (List[Document.Edit_Command], List[(String, Thy_Header.Header)], Document.Version) =
   {
     /* phase 1: edit individual command source */
 
@@ -169,10 +173,25 @@
     }
 
 
+    /* node header */
+
+    def node_header(name: String, node: Document.Node)
+        : (List[(String, Thy_Header.Header)], Document.Node.Header) =
+      (node.header.thy_header, headers.find(p => p._1 == name).map(_._2)) match {
+        case (Exn.Res(thy_header0), Some(header @ Document.Node.Header(_, Exn.Res(thy_header))))
+        if thy_header0 != thy_header =>
+          (List((name, thy_header)), header)
+        case (Exn.Exn(_), Some(header @ Document.Node.Header(_, Exn.Res(thy_header)))) =>
+          (List((name, thy_header)), header)
+        case _ => (Nil, node.header)
+      }
+
+
     /* resulting document edits */
 
     {
       val doc_edits = new mutable.ListBuffer[Document.Edit_Command]
+      val header_edits = new mutable.ListBuffer[(String, Thy_Header.Header)]
       var nodes = previous.nodes
 
       edits foreach {
@@ -194,9 +213,13 @@
             inserted_commands.map(cmd => (commands2.prev(cmd), Some(cmd)))
 
           doc_edits += (name -> Some(cmd_edits))
-          nodes += (name -> Document.Node(node.header, node.blobs, commands2))
+
+          val (new_headers, new_header) = node_header(name, node)
+          header_edits ++= new_headers
+
+          nodes += (name -> Document.Node(new_header, node.blobs, commands2))
       }
-      (doc_edits.toList, new Document.Version(Document.new_id(), nodes))
+      (doc_edits.toList, header_edits.toList, Document.Version(Document.new_id(), nodes))
     }
   }
 }
--- a/src/Tools/jEdit/src/document_model.scala	Sat Jul 09 21:53:27 2011 +0200
+++ b/src/Tools/jEdit/src/document_model.scala	Sun Jul 10 00:21:19 2011 +0200
@@ -64,7 +64,7 @@
   private val node_name = (master_dir + Path.basic(thy_name)).implode
 
   private def node_header(): Document.Node.Header =
-    Document.Node.Header(master_dir,
+    Document.Node.Header(Path.current,  // FIXME master_dir (!?)
       Exn.capture { Thy_Header.check(thy_name, buffer.getSegment(0, buffer.getLength)) })
 
   private object pending_edits  // owned by Swing thread