manage document blobs as well;
authorwenzelm
Thu, 05 Jan 2017 15:15:51 +0100
changeset 64800 415dafeb9669
parent 64799 c0c648911f1a
child 64801 5ecc426922b7
manage document blobs as well;
src/Pure/PIDE/line.scala
src/Tools/VSCode/src/document_model.scala
src/Tools/VSCode/src/server.scala
src/Tools/VSCode/src/vscode_resources.scala
--- a/src/Pure/PIDE/line.scala	Thu Jan 05 12:23:25 2017 +0100
+++ b/src/Pure/PIDE/line.scala	Thu Jan 05 15:15:51 2017 +0100
@@ -136,6 +136,12 @@
       else ((0 /: lines) { case (n, line) => n + line.text.length + 1 }) - 1
 
     def full_range: Text.Range = Text.Range(0, length)
+
+    lazy val blob: (Bytes, Symbol.Text_Chunk) =
+    {
+      val text = make_text
+      (Bytes(text), Symbol.Text_Chunk(text))
+    }
   }
 
 
--- a/src/Tools/VSCode/src/document_model.scala	Thu Jan 05 12:23:25 2017 +0100
+++ b/src/Tools/VSCode/src/document_model.scala	Thu Jan 05 15:15:51 2017 +0100
@@ -45,6 +45,8 @@
 
   def external(b: Boolean): Document_Model = copy(external_file = b)
 
+  def node_visible: Boolean = !external_file
+
 
   /* header */
 
@@ -60,13 +62,32 @@
 
   /* perspective */
 
-  def node_visible: Boolean = !external_file
+  def node_perspective(doc_blobs: Document.Blobs): (Boolean, Document.Node.Perspective_Text) =
+  {
+    if (is_theory) {
+      val snapshot = this.snapshot()
+
+      val text_perspective =
+        if (node_visible || snapshot.commands_loading_ranges(resources.visible_node(_)).nonEmpty)
+          Text.Perspective.full
+        else Text.Perspective.empty
 
-  def text_perspective: Text.Perspective =
-    if (node_visible) Text.Perspective.full else Text.Perspective.empty
+      (snapshot.node.load_commands_changed(doc_blobs),
+        Document.Node.Perspective(node_required, text_perspective, Document.Node.Overlays.empty))
+    }
+    else (false, Document.Node.no_perspective_text)
+  }
+
 
-  def node_perspective: Document.Node.Perspective_Text =
-    Document.Node.Perspective(node_required, text_perspective, Document.Node.Overlays.empty)
+  /* blob */
+
+  def get_blob: Option[Document.Blob] =
+    if (is_theory) None
+    else {
+      val (bytes, chunk) = doc.blob
+      val changed = pending_edits.nonEmpty
+      Some((Document.Blob(bytes, chunk, changed)))
+    }
 
 
   /* edits */
@@ -84,17 +105,20 @@
     }
   }
 
-  def flush_edits: Option[(List[Document.Edit_Text], Document_Model)] =
+  def flush_edits(doc_blobs: Document.Blobs): Option[(List[Document.Edit_Text], Document_Model)] =
   {
-    val perspective = node_perspective
-    if (pending_edits.nonEmpty || last_perspective != perspective) {
-      val text_edits = pending_edits.toList
-      val edits =
-        session.header_edit(node_name, node_header) ::
-        (if (text_edits.isEmpty) Nil
-         else List[Document.Edit_Text](node_name -> Document.Node.Edits(text_edits))) :::
-        (if (last_perspective == perspective) Nil
-         else List[Document.Edit_Text](node_name -> perspective))
+    val (reparse, perspective) = node_perspective(doc_blobs)
+    if (reparse || pending_edits.nonEmpty || last_perspective != perspective) {
+      val edits: List[Document.Edit_Text] =
+        get_blob match {
+          case None =>
+            List(session.header_edit(node_name, node_header),
+              node_name -> Document.Node.Edits(pending_edits.toList),
+              node_name -> perspective)
+          case Some(blob) =>
+            List(node_name -> Document.Node.Blob(blob),
+              node_name -> Document.Node.Edits(pending_edits.toList))
+        }
       Some((edits, copy(pending_edits = Vector.empty, last_perspective = perspective)))
     }
     else None
--- a/src/Tools/VSCode/src/server.scala	Thu Jan 05 12:23:25 2017 +0100
+++ b/src/Tools/VSCode/src/server.scala	Thu Jan 05 15:15:51 2017 +0100
@@ -110,13 +110,16 @@
 
   /* input from client or file-system */
 
-  private val delay_input =
+  private val delay_input: Standard_Thread.Delay =
     Standard_Thread.delay_last(options.seconds("vscode_input_delay"))
     { resources.flush_input(session) }
 
-  private val delay_load =
-    Standard_Thread.delay_last(options.seconds("vscode_load_delay"))
-    { if (resources.resolve_dependencies(session, watcher)) delay_input.invoke() }
+  private val delay_load: Standard_Thread.Delay =
+    Standard_Thread.delay_last(options.seconds("vscode_load_delay")) {
+      val (invoke_input, invoke_load) = resources.resolve_dependencies(session, watcher)
+      if (invoke_input) delay_input.invoke()
+      if (invoke_load) delay_load.invoke
+    }
 
   private val watcher =
     File_Watcher(sync_documents(_), options.seconds("vscode_load_delay"))
@@ -201,7 +204,8 @@
           new VSCode_Resources(options, text_length, content.loaded_theories,
               content.known_theories, content.syntax, log) {
             override def commit(change: Session.Change): Unit =
-              if (change.deps_changed) delay_load.invoke()
+              if (change.deps_changed || undefined_blobs(change.version.nodes).nonEmpty)
+                delay_load.invoke()
           }
 
         Some(new Session(resources) {
--- a/src/Tools/VSCode/src/vscode_resources.scala	Thu Jan 05 12:23:25 2017 +0100
+++ b/src/Tools/VSCode/src/vscode_resources.scala	Thu Jan 05 15:15:51 2017 +0100
@@ -22,6 +22,14 @@
     models: Map[JFile, Document_Model] = Map.empty,
     pending_input: Set[JFile] = Set.empty,
     pending_output: Set[JFile] = Set.empty)
+  {
+    lazy val document_blobs: Document.Blobs =
+      Document.Blobs(
+        (for {
+          (_, model) <- models.iterator
+          blob <- model.get_blob
+        } yield (model.node_name -> blob)).toMap)
+  }
 }
 
 class VSCode_Resources(
@@ -79,6 +87,12 @@
   def get_model(file: JFile): Option[Document_Model] = state.value.models.get(file)
   def get_model(name: Document.Node.Name): Option[Document_Model] = get_model(node_file(name))
 
+  def visible_node(name: Document.Node.Name): Boolean =
+    get_model(name) match {
+      case Some(model) => model.node_visible
+      case None => false
+    }
+
   def update_model(session: Session, file: JFile, text: String)
   {
     state.change(st =>
@@ -134,33 +148,55 @@
 
   val thy_info = new Thy_Info(this)
 
-  def resolve_dependencies(session: Session, watcher: File_Watcher): Boolean =
+  def resolve_dependencies(session: Session, watcher: File_Watcher): (Boolean, Boolean) =
   {
     state.change_result(st =>
       {
+        /* theory files */
+
         val thys =
           (for ((_, model) <- st.models.iterator if model.is_theory)
            yield (model.node_name, Position.none)).toList
 
+        val thy_files = thy_info.dependencies("", thys).deps.map(_.name)
+
+
+        /* auxiliary files */
+
+        val stable_tip_version =
+          if (st.models.forall({ case (_, model) => model.pending_edits.isEmpty }))
+            session.current_state().stable_tip_version
+          else None
+
+        val aux_files =
+          stable_tip_version match {
+            case Some(version) => undefined_blobs(version.nodes)
+            case None => Nil
+          }
+
+
+        /* loaded models */
+
         val loaded_models =
           (for {
-            dep <- thy_info.dependencies("", thys).deps.iterator
-            file = node_file(dep.name)
+            node_name <- thy_files.iterator ++ aux_files.iterator
+            file = node_file(node_name)
             if !st.models.isDefinedAt(file)
             text <- { watcher.register_parent(file); try_read(file) }
           }
           yield {
-            val model = Document_Model.init(session, node_name(file))
+            val model = Document_Model.init(session, node_name)
             val model1 = (model.update_text(text) getOrElse model).external(true)
             (file, model1)
           }).toList
 
-        if (loaded_models.isEmpty) (false, st)
-        else
-          (true,
-            st.copy(
-              models = st.models ++ loaded_models,
-              pending_input = st.pending_input ++ loaded_models.iterator.map(_._1)))
+        val invoke_input = loaded_models.nonEmpty
+        val invoke_load = stable_tip_version.isEmpty
+
+        ((invoke_input, invoke_load),
+          st.copy(
+            models = st.models ++ loaded_models,
+            pending_input = st.pending_input ++ loaded_models.iterator.map(_._1)))
       })
   }
 
@@ -175,10 +211,10 @@
           (for {
             file <- st.pending_input.iterator
             model <- st.models.get(file)
-            (edits, model1) <- model.flush_edits
+            (edits, model1) <- model.flush_edits(st.document_blobs)
           } yield (edits, (file, model1))).toList
 
-        session.update(Document.Blobs.empty, changed_models.flatMap(_._1))
+        session.update(st.document_blobs, changed_models.flatMap(_._1))
         st.copy(
           models = (st.models /: changed_models.iterator.map(_._2))(_ + _),
           pending_input = Set.empty)