| author | wenzelm | 
| Mon, 13 Feb 2023 10:49:33 +0100 | |
| changeset 77287 | d060545f01a2 | 
| parent 77202 | 064566bc1f35 | 
| child 82918 | af85ea5d9b20 | 
| permissions | -rw-r--r-- | 
| 76606 | 1 | /* Title: Pure/PIDE/document_editor.scala | 
| 2 | Author: Makarius | |
| 3 | ||
| 76730 | 4 | Central resources and configuration for interactive document preparation. | 
| 76606 | 5 | */ | 
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 10 | import scala.collection.immutable.SortedSet | 
| 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 11 | |
| 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 12 | |
| 76606 | 13 | object Document_Editor {
 | 
| 14 | /* document output */ | |
| 15 | ||
| 16 | def document_name: String = "document" | |
| 17 |   def document_output_dir(): Path = Path.explode("$ISABELLE_HOME_USER/document_output")
 | |
| 77185 | 18 | def document_output(name: String): Path = document_output_dir() + Path.basic(name) | 
| 19 | ||
| 77202 
064566bc1f35
clarified signature: follow terminology of isabelle.Sessions and isabelle.Build;
 wenzelm parents: 
77197diff
changeset | 20 |   object Meta_Info {
 | 
| 
064566bc1f35
clarified signature: follow terminology of isabelle.Sessions and isabelle.Build;
 wenzelm parents: 
77197diff
changeset | 21 |     def read(name: String = document_name): Option[Meta_Info] = {
 | 
| 77185 | 22 | val json_path = document_output(name).json | 
| 23 |       if (json_path.is_file) {
 | |
| 24 | val json = JSON.parse(File.read(json_path)) | |
| 25 |         for {
 | |
| 26 | selection <- JSON.list(json, "selection", JSON.Value.String.unapply) | |
| 27 | sources <- JSON.string(json, "sources") | |
| 28 | log <- JSON.string(json, "log") | |
| 29 | pdf <- JSON.string(json, "pdf") | |
| 30 |         } yield {
 | |
| 77202 
064566bc1f35
clarified signature: follow terminology of isabelle.Sessions and isabelle.Build;
 wenzelm parents: 
77197diff
changeset | 31 | Meta_Info(name, | 
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 32 | SortedSet.from(selection), | 
| 77185 | 33 | SHA1.fake_digest(sources), | 
| 34 | SHA1.fake_digest(log), | |
| 35 | SHA1.fake_digest(pdf)) | |
| 36 | } | |
| 37 | } | |
| 38 | else None | |
| 39 | } | |
| 76606 | 40 | |
| 77185 | 41 | def write( | 
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 42 | selection: SortedSet[String], | 
| 77185 | 43 | doc: Document_Build.Document_Output, | 
| 44 | name: String = document_name | |
| 45 |     ): Unit = {
 | |
| 46 | val json = | |
| 47 | JSON.Object( | |
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 48 | "selection" -> selection.toList, | 
| 77185 | 49 | "sources" -> doc.sources.toString, | 
| 50 | "log" -> SHA1.digest(doc.log).toString, | |
| 51 | "pdf" -> SHA1.digest(doc.pdf).toString) | |
| 52 | File.write(document_output(name).json, JSON.Format.pretty_print(json)) | |
| 53 | } | |
| 54 | } | |
| 55 | ||
| 77202 
064566bc1f35
clarified signature: follow terminology of isabelle.Sessions and isabelle.Build;
 wenzelm parents: 
77197diff
changeset | 56 | sealed case class Meta_Info( | 
| 77185 | 57 | name: String, | 
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 58 | selection: SortedSet[String], | 
| 77185 | 59 | sources: SHA1.Digest, | 
| 60 | log: SHA1.Digest, | |
| 61 | pdf: SHA1.Digest | |
| 62 |   ) {
 | |
| 63 |     def check_files(): Boolean = {
 | |
| 64 | val path = document_output(name) | |
| 65 | path.log.is_file && | |
| 66 | path.pdf.is_file && | |
| 67 | log == SHA1.digest(File.read(path.log)) && | |
| 68 | pdf == SHA1.digest(path.pdf) | |
| 69 | } | |
| 70 | } | |
| 71 | ||
| 72 | def write_document( | |
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 73 | selection: SortedSet[String], | 
| 77185 | 74 | doc: Document_Build.Document_Output, | 
| 75 | name: String = document_name | |
| 76 |   ): Unit = {
 | |
| 77 | val output = document_output(name) | |
| 77184 | 78 | File.write(output.log, doc.log) | 
| 79 | Bytes.write(output.pdf, doc.pdf) | |
| 77202 
064566bc1f35
clarified signature: follow terminology of isabelle.Sessions and isabelle.Build;
 wenzelm parents: 
77197diff
changeset | 80 | Meta_Info.write(selection, doc, name = name) | 
| 77184 | 81 | } | 
| 82 | ||
| 77185 | 83 |   def view_document(name: String = document_name): Unit = {
 | 
| 84 | val path = document_output(name).pdf | |
| 76606 | 85 | if (path.is_file) Isabelle_System.pdf_viewer(path) | 
| 86 | } | |
| 87 | ||
| 88 | ||
| 76730 | 89 | /* configuration state */ | 
| 76609 
cc9ddf373bd2
maintain global state of document editor views, notably for is_active operation;
 wenzelm parents: 
76606diff
changeset | 90 | |
| 77144 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 91 | sealed case class Session( | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 92 | background: Option[Sessions.Background], | 
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 93 | selection: SortedSet[String], | 
| 77144 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 94 | snapshot: Option[Document.Snapshot] | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 95 |   ) {
 | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 96 | def is_vacuous: Boolean = background.isEmpty | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 97 | def is_pending: Boolean = snapshot.isEmpty | 
| 77149 
3991a35cd740
automatically build document when selected theories are finished;
 wenzelm parents: 
77147diff
changeset | 98 | def is_ready: Boolean = background.isDefined && snapshot.isDefined | 
| 77144 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 99 | |
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 100 | def get_background: Sessions.Background = background.get | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 101 | def get_variant: Document_Build.Document_Variant = get_background.info.documents.head | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 102 | def get_snapshot: Document.Snapshot = snapshot.get | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 103 | } | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 104 | |
| 76609 
cc9ddf373bd2
maintain global state of document editor views, notably for is_active operation;
 wenzelm parents: 
76606diff
changeset | 105 | sealed case class State( | 
| 76678 | 106 | session_background: Option[Sessions.Background] = None, | 
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 107 | selection: SortedSet[String] = SortedSet.empty, | 
| 76609 
cc9ddf373bd2
maintain global state of document editor views, notably for is_active operation;
 wenzelm parents: 
76606diff
changeset | 108 | views: Set[AnyRef] = Set.empty, | 
| 
cc9ddf373bd2
maintain global state of document editor views, notably for is_active operation;
 wenzelm parents: 
76606diff
changeset | 109 |   ) {
 | 
| 76678 | 110 | def is_active: Boolean = session_background.isDefined && views.nonEmpty | 
| 76609 
cc9ddf373bd2
maintain global state of document editor views, notably for is_active operation;
 wenzelm parents: 
76606diff
changeset | 111 | |
| 76715 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 112 | def all_document_theories: List[Document.Node.Name] = | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 113 |       session_background match {
 | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 114 | case Some(background) => background.base.all_document_theories | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 115 | case None => Nil | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 116 | } | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 117 | |
| 76716 
a7602257a825
clarified state document nodes for Theories_Status / Document_Dockable;
 wenzelm parents: 
76715diff
changeset | 118 | def active_document_theories: List[Document.Node.Name] = | 
| 
a7602257a825
clarified state document nodes for Theories_Status / Document_Dockable;
 wenzelm parents: 
76715diff
changeset | 119 | if (is_active) all_document_theories else Nil | 
| 
a7602257a825
clarified state document nodes for Theories_Status / Document_Dockable;
 wenzelm parents: 
76715diff
changeset | 120 | |
| 76715 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 121 | def select( | 
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 122 | theories: Iterable[String], | 
| 76715 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 123 | set: Boolean = false, | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 124 | toggle: Boolean = false | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 125 |     ): State = {
 | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 126 | copy(selection = | 
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 127 |         theories.foldLeft(selection) {
 | 
| 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 128 | case (sel, theory) => | 
| 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 129 | val b = if (toggle) !selection(theory) else set | 
| 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 130 | if (b) sel + theory else sel - theory | 
| 76715 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 131 | }) | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 132 | } | 
| 
bf5ff407f32f
clarified state of document model vs. document editor selection (again, see also a9d52d02bd83);
 wenzelm parents: 
76678diff
changeset | 133 | |
| 76609 
cc9ddf373bd2
maintain global state of document editor views, notably for is_active operation;
 wenzelm parents: 
76606diff
changeset | 134 | def register_view(id: AnyRef): State = copy(views = views + id) | 
| 
cc9ddf373bd2
maintain global state of document editor views, notably for is_active operation;
 wenzelm parents: 
76606diff
changeset | 135 | def unregister_view(id: AnyRef): State = copy(views = views - id) | 
| 77144 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 136 | |
| 77161 
913c781ff6ba
support document preparation from already loaded theories;
 wenzelm parents: 
77149diff
changeset | 137 |     def session(pide_session: isabelle.Session): Session = {
 | 
| 77144 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 138 | val background = session_background.filter(_.info.documents.nonEmpty) | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 139 | val snapshot = | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 140 | if (background.isEmpty) None | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 141 |         else {
 | 
| 77161 
913c781ff6ba
support document preparation from already loaded theories;
 wenzelm parents: 
77149diff
changeset | 142 | val snapshot = pide_session.snapshot() | 
| 77197 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 143 | def document_ready(theory: String): Boolean = | 
| 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 144 | pide_session.resources.session_base.loaded_theory(theory) || | 
| 
a541da01ba67
clarified signature selection: SortedSet[String], which fits better to stored json and works properly on Windows (NB: document theories have an authentic session-theory name);
 wenzelm parents: 
77195diff
changeset | 145 | snapshot.theory_consolidated(theory) | 
| 77161 
913c781ff6ba
support document preparation from already loaded theories;
 wenzelm parents: 
77149diff
changeset | 146 | if (snapshot.is_outdated || !selection.forall(document_ready)) None | 
| 77147 | 147 | else Some(snapshot) | 
| 77144 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 148 | } | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 149 | Session(background, selection, snapshot) | 
| 
42c3970e1ac1
clarified Document_Editor.Session: more explicit types, more robust operations;
 wenzelm parents: 
76994diff
changeset | 150 | } | 
| 76609 
cc9ddf373bd2
maintain global state of document editor views, notably for is_active operation;
 wenzelm parents: 
76606diff
changeset | 151 | } | 
| 77195 | 152 | |
| 153 | ||
| 154 | /* build */ | |
| 155 | ||
| 156 | def build( | |
| 157 | session_context: Export.Session_Context, | |
| 158 | document_session: Document_Editor.Session, | |
| 159 | progress: Progress | |
| 160 |   ): Unit = {
 | |
| 161 | val session_background = document_session.get_background | |
| 162 | val context = | |
| 163 | Document_Build.context(session_context, | |
| 164 | document_session = Some(session_background.base), | |
| 165 | document_selection = document_session.selection, | |
| 166 | progress = progress) | |
| 167 | ||
| 168 | Isabelle_System.make_directory(document_output_dir()) | |
| 169 |     Isabelle_System.with_tmp_dir("document") { tmp_dir =>
 | |
| 170 | val engine = context.get_engine() | |
| 171 | val variant = document_session.get_variant | |
| 172 | val directory = engine.prepare_directory(context, tmp_dir, variant, verbose = true) | |
| 173 | val ok = | |
| 77202 
064566bc1f35
clarified signature: follow terminology of isabelle.Sessions and isabelle.Build;
 wenzelm parents: 
77197diff
changeset | 174 |         Meta_Info.read() match {
 | 
| 
064566bc1f35
clarified signature: follow terminology of isabelle.Sessions and isabelle.Build;
 wenzelm parents: 
77197diff
changeset | 175 | case Some(meta_info) => | 
| 
064566bc1f35
clarified signature: follow terminology of isabelle.Sessions and isabelle.Build;
 wenzelm parents: 
77197diff
changeset | 176 | meta_info.check_files() && meta_info.sources == directory.sources | 
| 77195 | 177 | case None => false | 
| 178 | } | |
| 179 |       if (!ok) {
 | |
| 180 | write_document(document_session.selection, | |
| 181 | engine.build_document(context, directory, verbose = true)) | |
| 182 | } | |
| 183 | } | |
| 184 | } | |
| 76606 | 185 | } |