clarified Document_Editor.Session: more explicit types, more robust operations;
authorwenzelm
Tue, 31 Jan 2023 12:27:00 +0100
changeset 77144 42c3970e1ac1
parent 77143 61f6bb753cbf
child 77145 de618831ffd9
clarified Document_Editor.Session: more explicit types, more robust operations; eliminated await_stable_snapshot in favour of delay_build;
src/Pure/PIDE/document_editor.scala
src/Pure/PIDE/editor.scala
src/Tools/jEdit/src/document_dockable.scala
--- a/src/Pure/PIDE/document_editor.scala	Mon Jan 30 16:26:10 2023 +0100
+++ b/src/Pure/PIDE/document_editor.scala	Tue Jan 31 12:27:00 2023 +0100
@@ -22,6 +22,19 @@
 
   /* configuration state */
 
+  sealed case class Session(
+    background: Option[Sessions.Background],
+    selection: Set[Document.Node.Name],
+    snapshot: Option[Document.Snapshot]
+  ) {
+    def is_vacuous: Boolean = background.isEmpty
+    def is_pending: Boolean = snapshot.isEmpty
+
+    def get_background: Sessions.Background = background.get
+    def get_variant: Document_Build.Document_Variant = get_background.info.documents.head
+    def get_snapshot: Document.Snapshot = snapshot.get
+  }
+
   sealed case class State(
     session_background: Option[Sessions.Background] = None,
     selection: Set[Document.Node.Name] = Set.empty,
@@ -53,5 +66,16 @@
 
     def register_view(id: AnyRef): State = copy(views = views + id)
     def unregister_view(id: AnyRef): State = copy(views = views - id)
+
+    def session(get_snapshot: () => Document.Snapshot): Session = {
+      val background = session_background.filter(_.info.documents.nonEmpty)
+      val snapshot =
+        if (background.isEmpty) None
+        else {
+          val snapshot = get_snapshot()
+          if (snapshot.is_outdated) None else Some(snapshot)
+        }
+      Session(background, selection, snapshot)
+    }
   }
 }
--- a/src/Pure/PIDE/editor.scala	Mon Jan 30 16:26:10 2023 +0100
+++ b/src/Pure/PIDE/editor.scala	Tue Jan 31 12:27:00 2023 +0100
@@ -37,8 +37,8 @@
     if (changed) document_state_changed()
   }
 
-  def document_session(): Option[Sessions.Background] =
-    document_state().session_background.filter(_.info.documents.nonEmpty)
+  def document_session(): Document_Editor.Session =
+    document_state().session(() => session.snapshot())
 
   def document_required(): List[Document.Node.Name] = {
     val st = document_state()
--- a/src/Tools/jEdit/src/document_dockable.scala	Mon Jan 30 16:26:10 2023 +0100
+++ b/src/Tools/jEdit/src/document_dockable.scala	Tue Jan 31 12:27:00 2023 +0100
@@ -197,24 +197,21 @@
   }
 
   private def document_build(
-    session_background: Sessions.Background,
+    document_session: Document_Editor.Session,
     progress: Log_Progress
   ): Unit = {
-    val document_selection = PIDE.editor.document_selection()
-
-    val snapshot = PIDE.session.await_stable_snapshot()
+    val session_background = document_session.get_background
+    val snapshot = document_session.get_snapshot
     val session_context = JEdit_Sessions.open_session_context(document_snapshot = Some(snapshot))
     try {
       val context =
         Document_Build.context(session_context,
           document_session = Some(session_background.base),
-          document_selection = document_selection,
+          document_selection = document_session.selection,
           progress = progress)
 
-      val variant = session_background.info.documents.head
-
       Isabelle_System.make_directory(Document_Editor.document_output_dir())
-      val doc = context.build_document(variant, verbose = true)
+      val doc = context.build_document(document_session.get_variant, verbose = true)
 
       File.write(Document_Editor.document_output().log, doc.log)
       Bytes.write(Document_Editor.document_output().pdf, doc.pdf)
@@ -223,33 +220,40 @@
     finally { session_context.close() }
   }
 
-  private def build_document(): Unit = {
-    PIDE.editor.document_session() match {
-      case Some(session_background) =>
-        run_process(only_running = true) { progress =>
-          show_page(output_page)
-          val result = Exn.capture { document_build(session_background, progress) }
-          val msgs =
-            result match {
-              case Exn.Res(_) =>
-                List(Protocol.writeln_message("OK"))
-              case Exn.Exn(exn: Document_Build.Build_Error) =>
-                exn.log_errors.map(s => Protocol.error_message(YXML.parse_body(s)))
-              case Exn.Exn(exn) =>
-                List(Protocol.error_message(YXML.parse_body(Exn.print(exn))))
-            }
+  private def document_build_attempt(): Boolean = {
+    val document_session = PIDE.editor.document_session()
+    if (document_session.is_vacuous) true
+    else if (document_session.is_pending) false
+    else {
+      run_process(only_running = true) { progress =>
+        show_page(output_page)
+        val result = Exn.capture { document_build(document_session, progress) }
+        val msgs =
+          result match {
+            case Exn.Res(_) =>
+              List(Protocol.writeln_message("OK"))
+            case Exn.Exn(exn: Document_Build.Build_Error) =>
+              exn.log_errors.map(s => Protocol.error_message(YXML.parse_body(s)))
+            case Exn.Exn(exn) =>
+              List(Protocol.error_message(YXML.parse_body(Exn.print(exn))))
+          }
 
-          progress.stop_program()
-          running_process(progress)
-          finish_process(Pretty.separate(msgs))
+        progress.stop_program()
+        running_process(progress)
+        finish_process(Pretty.separate(msgs))
 
-          show_state()
-          show_page(if (Exn.is_interrupt_exn(result)) input_page else output_page)
-        }
-      case None =>
+        show_state()
+        show_page(if (Exn.is_interrupt_exn(result)) input_page else output_page)
+      }
+      true
     }
   }
 
+  private lazy val delay_build: Delay =
+    Delay.first(PIDE.session.output_delay, gui = true) {
+      if (!document_build_attempt()) delay_build.invoke()
+    }
+
 
   /* controls */
 
@@ -274,7 +278,7 @@
   private val build_button =
     new GUI.Button("<html><b>Build</b></html>") {
       tooltip = "Build document"
-      override def clicked(): Unit = build_document()
+      override def clicked(): Unit = delay_build.invoke()
     }
 
   private val cancel_button =