automatically resolve dependencies from document models and file-system;
authorwenzelm
Sat, 31 Dec 2016 20:26:34 +0100
changeset 64727 13e37567a0d6
parent 64726 c534a2ac537d
child 64728 601866c61ded
automatically resolve dependencies from document models and file-system;
src/Tools/VSCode/etc/options
src/Tools/VSCode/src/document_model.scala
src/Tools/VSCode/src/server.scala
src/Tools/VSCode/src/vscode_resources.scala
--- a/src/Tools/VSCode/etc/options	Sat Dec 31 15:32:54 2016 +0100
+++ b/src/Tools/VSCode/etc/options	Sat Dec 31 20:26:34 2016 +0100
@@ -6,6 +6,9 @@
 option vscode_output_delay : real = 0.5
   -- "delay for client output (rendering)"
 
+option vscode_load_delay : real = 0.5
+  -- "delay for file load operations"
+
 option vscode_tooltip_margin : int = 60
   -- "margin for pretty-printing of tooltips"
 
--- a/src/Tools/VSCode/src/document_model.scala	Sat Dec 31 15:32:54 2016 +0100
+++ b/src/Tools/VSCode/src/document_model.scala	Sat Dec 31 20:26:34 2016 +0100
@@ -47,6 +47,8 @@
 
   val file: JFile = VSCode_Resources.canonical_file(uri)
 
+  def external(b: Boolean): Document_Model = copy(external_file = b)
+
   def register(watcher: File_Watcher)
   {
     val dir = file.getParentFile
--- a/src/Tools/VSCode/src/server.scala	Sat Dec 31 15:32:54 2016 +0100
+++ b/src/Tools/VSCode/src/server.scala	Sat Dec 31 20:26:34 2016 +0100
@@ -114,7 +114,12 @@
     Standard_Thread.delay_last(options.seconds("vscode_input_delay"))
     { resources.flush_input(session) }
 
-  private val watcher = File_Watcher(sync_documents(_))
+  private val delay_load =
+    Standard_Thread.delay_last(options.seconds("vscode_load_delay"))
+    { if (resources.resolve_dependencies(session)) delay_input.invoke() }
+
+  private val watcher =
+    File_Watcher(sync_documents(_), options.seconds("vscode_load_delay"))
 
   private def sync_documents(changed: Set[JFile]): Unit =
     if (resources.sync_models(changed)) delay_input.invoke()
@@ -178,7 +183,10 @@
         val content = Build.session_content(options, false, session_dirs, session_name)
         val resources =
           new VSCode_Resources(options, text_length, content.loaded_theories,
-            content.known_theories, content.syntax, log)
+              content.known_theories, content.syntax, log) {
+            override def commit(change: Session.Change): Unit =
+              if (change.deps_changed) delay_load.invoke()
+          }
 
         Some(new Session(resources) {
           override def output_delay = options.seconds("editor_output_delay")
--- a/src/Tools/VSCode/src/vscode_resources.scala	Sat Dec 31 15:32:54 2016 +0100
+++ b/src/Tools/VSCode/src/vscode_resources.scala	Sat Dec 31 20:26:34 2016 +0100
@@ -12,6 +12,8 @@
 import java.net.{URI, URISyntaxException}
 import java.io.{File => JFile}
 
+import scala.util.parsing.input.{Reader, CharSequenceReader}
+
 
 object VSCode_Resources
 {
@@ -64,6 +66,23 @@
     else name.copy(node = "file://" + name.node)
   }
 
+  override def with_thy_reader[A](name: Document.Node.Name, f: Reader[Char] => A): A =
+  {
+    val uri = name.node
+    get_model(uri) match {
+      case Some(model) =>
+        val reader = new CharSequenceReader(model.doc.make_text)
+        f(reader)
+
+      case None =>
+        val file = VSCode_Resources.canonical_file(uri)
+        if (!file.isFile) error("No such file: " + quote(file.toString))
+
+        val reader = Scan.byte_reader(file)
+        try { f(reader) } finally { reader.close }
+    }
+  }
+
 
   /* document models */
 
@@ -74,7 +93,7 @@
     state.change(st =>
       {
         val model = st.models.getOrElse(uri, Document_Model.init(session, uri))
-        val model1 = (model.update_text(text) getOrElse model).copy(external_file = false)
+        val model1 = (model.update_text(text) getOrElse model).external(false)
         st.copy(
           models = st.models + (uri -> model1),
           pending_input = st.pending_input + uri)
@@ -86,7 +105,7 @@
       st.models.get(uri) match {
         case None => (None, st)
         case Some(model) =>
-          (Some(model), st.copy(models = st.models + (uri -> model.copy(external_file = true))))
+          (Some(model), st.copy(models = st.models + (uri -> model.external(true))))
       })
 
   def sync_models(changed_files: Set[JFile]): Boolean =
@@ -106,6 +125,40 @@
       })
 
 
+  /* resolve dependencies */
+
+  def resolve_dependencies(session: Session): Boolean =
+  {
+    val thys =
+      (for ((_, model) <- state.value.models.iterator if model.is_theory)
+       yield (model.node_name, Position.none)).toList
+    val deps = new Thy_Info(this).dependencies("", thys).deps
+
+    state.change_result(st =>
+      {
+        val loaded_models =
+          for {
+            uri <- deps.map(_.name.node)
+            if get_model(uri).isEmpty
+            text <-
+              try { Some(File.read(VSCode_Resources.canonical_file(uri))) }
+              catch { case ERROR(_) => None }
+          }
+          yield {
+            val model = Document_Model.init(session, uri)
+            val model1 = (model.update_text(text) getOrElse model).external(true)
+            (uri, model1)
+          }
+        if (loaded_models.isEmpty) (false, st)
+        else
+          (true,
+            st.copy(
+              models = st.models ++ loaded_models,
+              pending_input = st.pending_input ++ loaded_models.map(_._1)))
+      })
+  }
+
+
   /* pending input */
 
   def flush_input(session: Session)