src/Pure/Thy/present.scala
changeset 67176 13b5c3ff1954
parent 66075 408a5325379c
child 67177 af5b89bc065c
--- a/src/Pure/Thy/present.scala	Sun Dec 10 14:50:44 2017 +0100
+++ b/src/Pure/Thy/present.scala	Sun Dec 10 18:31:41 2017 +0100
@@ -131,4 +131,144 @@
   {
     make_html(snapshot.markup_to_XML(Text.Range.full, document_span_elements))
   }
+
+
+
+  /** build document **/
+
+  val default_document_name = "document"
+  val default_document_format = "pdf"
+  val document_formats = List("pdf", "dvi")
+  def default_document_dir(name: String): Path = Path.explode("output") + Path.basic(name)
+
+  def document_tags(tags: List[String]): String =
+  {
+    cat_lines(
+      tags.map(tag =>
+        tag.toList match {
+          case '/' :: cs => "\\isafoldtag{" + cs.mkString + "}"
+          case '-' :: cs => "\\isadroptag{" + cs.mkString + "}"
+          case '+' :: cs => "\\isakeeptag{" + cs.mkString + "}"
+          case cs => "\\isafoldtag{" + cs.mkString + "}"
+        })) + "\n"
+  }
+
+  def build_document(
+    document_name: String = default_document_name,
+    document_format: String = default_document_format,
+    document_dir: Option[Path] = None,
+    clean: Boolean = false,
+    tags: List[String] = Nil)
+  {
+    if (!document_formats.contains(document_format))
+      error("Bad document output format: " + quote(document_format))
+
+    val dir = document_dir getOrElse default_document_dir(document_name)
+    if (!dir.is_dir) error("Bad document output directory " + dir)
+
+    val root_name =
+    {
+      val root1 = "root_" + document_name
+      if ((dir + Path.explode(root1).ext("tex")).is_file) root1 else "root"
+    }
+
+
+    /* bash scripts */
+
+    def root_bash(ext: String): String = Bash.string(root_name + "." + ext)
+
+    def latex_bash(fmt: String, ext: String = "tex"): String =
+      "isabelle latex -o " + Bash.string(fmt) + " " + Bash.string(root_name + "." + ext)
+
+    def bash(script: String): Process_Result =
+    {
+      Output.writeln(script)  // FIXME
+      Isabelle_System.bash(script, cwd = dir.file)
+    }
+
+
+    /* clean target */
+
+    val document_target = Path.parent + Path.explode(document_name).ext(document_format)
+
+    if (clean) {
+      bash("rm -f *.aux *.out *.ind *.idx *.ilg *.bbl *.blg *.log " +
+        File.bash_path(document_target)).check
+    }
+
+
+    /* prepare document */
+
+    File.write(dir + Path.explode("isabelletags.sty"), document_tags(tags))
+
+    val result =
+      if ((dir + Path.explode("build")).is_file) {
+        bash("./build " + Bash.string(document_format) + " " + Bash.string(document_name))
+      }
+      else {
+        bash(
+          List(
+            latex_bash("sty"),
+            latex_bash(document_format),
+            "{ [ ! -f " + root_bash("bib") + " ] || " + latex_bash("bbl") + "; }",
+            "{ [ ! -f " + root_bash("idx") + " ] || " + latex_bash("idx") + "; }",
+            latex_bash(document_format),
+            latex_bash(document_format)).mkString(" && "))
+      }
+
+
+    /* result */
+
+    if (!result.ok) {
+      cat_error(cat_lines(Latex.latex_errors(dir, root_name)),
+        "Document preparation failure in directory " + dir)
+    }
+
+    bash("[ -f " + root_bash(document_format) + " ] && cp -f " +
+      root_bash(document_format) + " " + File.bash_path(document_target)).check
+
+    // beware!
+    if (clean) Isabelle_System.rm_tree(dir)
+  }
+
+
+  /* Isabelle tool wrapper */
+
+  val isabelle_tool =
+    Isabelle_Tool("document", "prepare theory session document", args =>
+  {
+    var clean = false
+    var document_dir: Option[Path] = None
+    var document_name = default_document_name
+    var document_format = default_document_format
+    var tags: List[String] = Nil
+
+    val getopts = Getopts("""
+Usage: isabelle document [OPTIONS]
+
+  Options are:
+    -c           aggressive cleanup of -d DIR content
+    -d DIR       document output directory (default """ +
+      default_document_dir(default_document_name) + """)
+    -n NAME      document name (default """ + quote(default_document_name) + """)
+    -o FORMAT    document format: """ +
+      commas(document_formats.map(fmt =>
+        fmt + (if (fmt == default_document_format) " (default)" else ""))) + """
+    -t TAGS      markup for tagged regions
+
+  Prepare the theory session document in document directory, producing the
+  specified output format.
+""",
+      "c" -> (_ => clean = true),
+      "d:" -> (arg => document_dir = Some(Path.explode(arg))),
+      "n:" -> (arg => document_name = arg),
+      "o:" -> (arg => document_format = arg),
+      "t:" -> (arg => tags = space_explode(',', arg)))
+
+    val more_args = getopts(args)
+    if (more_args.nonEmpty) getopts.usage()
+
+    build_document(document_dir = document_dir, document_name = document_name,
+      document_format = document_format, clean = clean, tags = tags)
+  })
 }