| author | wenzelm | 
| Sat, 10 Oct 2020 20:56:09 +0200 | |
| changeset 72422 | 9d59738102b8 | 
| parent 71601 | 97ccf48c2f0c | 
| child 72760 | 042180540068 | 
| permissions | -rw-r--r-- | 
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 1 | /* Title: Pure/Tools/doc.scala | 
| 52427 | 2 | Author: Makarius | 
| 3 | ||
| 56424 
7032378cc097
proper settings instead of hard-wired information;
 wenzelm parents: 
56423diff
changeset | 4 | Access to Isabelle documentation. | 
| 52427 | 5 | */ | 
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 10 | import scala.util.matching.Regex | |
| 11 | ||
| 12 | ||
| 13 | object Doc | |
| 14 | {
 | |
| 15 | /* dirs */ | |
| 16 | ||
| 17 | def dirs(): List[Path] = | |
| 67604 
02cf352cbc4c
permissive Doc.dirs: some entries may be absent due to distribution bootstrap, e.g. $JEDIT_HOME/dist/doc;
 wenzelm parents: 
67471diff
changeset | 18 |     Path.split(Isabelle_System.getenv("ISABELLE_DOCS"))
 | 
| 52740 | 19 | |
| 52427 | 20 | |
| 21 | /* contents */ | |
| 22 | ||
| 56422 | 23 | private def contents_lines(): List[(Path, String)] = | 
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 24 |     for {
 | 
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 25 | dir <- dirs() | 
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 26 |       catalog = dir + Path.basic("Contents")
 | 
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 27 | if catalog.is_file | 
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 28 | line <- split_lines(Library.trim_line(File.read(catalog))) | 
| 56422 | 29 | } yield (dir, line) | 
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 30 | |
| 52427 | 31 | sealed abstract class Entry | 
| 56423 
c2f52824dbb2
explicit indication of important doc sections ("!"), which are expanded in the tree view;
 wenzelm parents: 
56422diff
changeset | 32 | case class Section(text: String, important: Boolean) extends Entry | 
| 56422 | 33 | case class Doc(name: String, title: String, path: Path) extends Entry | 
| 52542 
19d674acb764
more release notes according to availability in proper release vs. repository clone;
 wenzelm parents: 
52541diff
changeset | 34 | case class Text_File(name: String, path: Path) extends Entry | 
| 52427 | 35 | |
| 69283 | 36 | def text_file(path: Path): Option[Text_File] = | 
| 37 |     if (path.is_file) {
 | |
| 71397 | 38 | val a = path.implode | 
| 39 |       val b = Library.try_unprefix("$ISABELLE_HOME/", a).getOrElse(a)
 | |
| 40 | Some(Text_File(b, path)) | |
| 69283 | 41 | } | 
| 53777 | 42 | else None | 
| 43 | ||
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 44 |   private val Section_Entry = new Regex("""^(\S.*)\s*$""")
 | 
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 45 |   private val Doc_Entry = new Regex("""^\s+(\S+)\s+(.+)\s*$""")
 | 
| 52427 | 46 | |
| 52542 
19d674acb764
more release notes according to availability in proper release vs. repository clone;
 wenzelm parents: 
52541diff
changeset | 47 | private def release_notes(): List[Entry] = | 
| 69409 
e7a5340128f0
clarified doc sections: add-on components may focus their own application name;
 wenzelm parents: 
69283diff
changeset | 48 |     Section("Release Notes", true) ::
 | 
| 71601 | 49 |       Path.split(Isabelle_System.getenv_strict("ISABELLE_DOCS_RELEASE_NOTES")).flatMap(text_file)
 | 
| 52541 
97c950217d7f
quick access to release notes (imitating website/documentation.html);
 wenzelm parents: 
52448diff
changeset | 50 | |
| 53777 | 51 | private def examples(): List[Entry] = | 
| 56424 
7032378cc097
proper settings instead of hard-wired information;
 wenzelm parents: 
56423diff
changeset | 52 |     Section("Examples", true) ::
 | 
| 
7032378cc097
proper settings instead of hard-wired information;
 wenzelm parents: 
56423diff
changeset | 53 |       Path.split(Isabelle_System.getenv_strict("ISABELLE_DOCS_EXAMPLES")).map(file =>
 | 
| 
7032378cc097
proper settings instead of hard-wired information;
 wenzelm parents: 
56423diff
changeset | 54 |         text_file(file) match {
 | 
| 
7032378cc097
proper settings instead of hard-wired information;
 wenzelm parents: 
56423diff
changeset | 55 | case Some(entry) => entry | 
| 56425 | 56 |           case None => error("Bad entry in ISABELLE_DOCS_EXAMPLES: " + file)
 | 
| 56424 
7032378cc097
proper settings instead of hard-wired information;
 wenzelm parents: 
56423diff
changeset | 57 | }) | 
| 53777 | 58 | |
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 59 | def contents(): List[Entry] = | 
| 61157 | 60 |   {
 | 
| 61 | val main_contents = | |
| 62 |       for {
 | |
| 63 | (dir, line) <- contents_lines() | |
| 64 | entry <- | |
| 65 |           line match {
 | |
| 66 | case Section_Entry(text) => | |
| 67 |               Library.try_unsuffix("!", text) match {
 | |
| 68 | case None => Some(Section(text, false)) | |
| 69 | case Some(txt) => Some(Section(txt, true)) | |
| 70 | } | |
| 71 | case Doc_Entry(name, title) => Some(Doc(name, title, dir + Path.basic(name))) | |
| 72 | case _ => None | |
| 73 | } | |
| 74 | } yield entry | |
| 75 | ||
| 76 | examples() ::: release_notes() ::: main_contents | |
| 77 | } | |
| 52427 | 78 | |
| 67471 | 79 | def doc_names(): List[String] = | 
| 80 | for (Doc(name, _, _) <- contents()) yield name | |
| 81 | ||
| 52427 | 82 | |
| 83 | /* view */ | |
| 84 | ||
| 56422 | 85 | def view(path: Path) | 
| 52427 | 86 |   {
 | 
| 67178 | 87 | if (path.is_file) Output.writeln(Library.trim_line(File.read(path)), stdout = true) | 
| 56422 | 88 |     else {
 | 
| 89 |       val pdf = path.ext("pdf")
 | |
| 90 | if (pdf.is_file) Isabelle_System.pdf_viewer(pdf) | |
| 91 |       else error("Bad Isabelle documentation file: " + pdf)
 | |
| 52427 | 92 | } | 
| 93 | } | |
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 94 | |
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 95 | |
| 62831 | 96 | /* Isabelle tool wrapper */ | 
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 97 | |
| 62831 | 98 |   val isabelle_tool = Isabelle_Tool("doc", "view Isabelle documentation", args =>
 | 
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 99 |   {
 | 
| 62831 | 100 |     val getopts = Getopts("""
 | 
| 62438 | 101 | Usage: isabelle doc [DOC ...] | 
| 102 | ||
| 103 | View Isabelle documentation. | |
| 104 | """) | |
| 62831 | 105 | val docs = getopts(args) | 
| 62438 | 106 | |
| 62831 | 107 | val entries = contents() | 
| 67178 | 108 | if (docs.isEmpty) Output.writeln(cat_lines(contents_lines().map(_._2)), stdout = true) | 
| 62831 | 109 |     else {
 | 
| 110 | docs.foreach(doc => | |
| 111 |         entries.collectFirst { case Doc(name, _, path) if doc == name => path } match {
 | |
| 112 | case Some(path) => view(path) | |
| 113 |           case None => error("No Isabelle documentation entry: " + quote(doc))
 | |
| 114 | } | |
| 115 | ) | |
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
52429diff
changeset | 116 | } | 
| 62831 | 117 | }) | 
| 52427 | 118 | } |