| author | desharna | 
| Sat, 15 Mar 2025 20:17:03 +0100 | |
| changeset 82282 | 919eb0e67930 | 
| parent 80441 | c420429fdf4c | 
| child 82787 | ddb68e3058d3 | 
| permissions | -rw-r--r-- | 
| 79503 | 1 | /* Title: Pure/General/latex.scala | 
| 67172 | 2 | Author: Makarius | 
| 3 | ||
| 4 | Support for LaTeX. | |
| 5 | */ | |
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 67173 | 10 | import java.io.{File => JFile}
 | 
| 11 | ||
| 67172 | 12 | import scala.annotation.tailrec | 
| 74748 | 13 | import scala.collection.mutable | 
| 74839 | 14 | import scala.collection.immutable.TreeMap | 
| 71601 | 15 | import scala.util.matching.Regex | 
| 67172 | 16 | |
| 17 | ||
| 75393 | 18 | object Latex {
 | 
| 74826 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 19 | /* output name for LaTeX macros */ | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 20 | |
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 21 | private val output_name_map: Map[Char, String] = | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 22 |     Map('_' -> "UNDERSCORE",
 | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 23 | '\'' -> "PRIME", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 24 | '0' -> "ZERO", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 25 | '1' -> "ONE", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 26 | '2' -> "TWO", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 27 | '3' -> "THREE", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 28 | '4' -> "FOUR", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 29 | '5' -> "FIVE", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 30 | '6' -> "SIX", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 31 | '7' -> "SEVEN", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 32 | '8' -> "EIGHT", | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 33 | '9' -> "NINE") | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 34 | |
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 35 | def output_name(name: String): String = | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 36 |     if (name.exists(output_name_map.keySet)) {
 | 
| 80441 | 37 |       Library.string_builder() { res =>
 | 
| 38 |         for (c <- name) {
 | |
| 39 |           output_name_map.get(c) match {
 | |
| 40 | case None => res += c | |
| 41 | case Some(s) => res ++= s | |
| 42 | } | |
| 74826 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 43 | } | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 44 | } | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 45 | } | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 46 | else name | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 47 | |
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 48 | |
| 74786 | 49 | /* index entries */ | 
| 50 | ||
| 75393 | 51 |   def index_escape(str: String): String = {
 | 
| 74786 | 52 | val special1 = "!\"@|" | 
| 53 |     val special2 = "\\{}#"
 | |
| 54 |     if (str.exists(c => special1.contains(c) || special2.contains(c))) {
 | |
| 80441 | 55 |       Library.string_builder() { res =>
 | 
| 56 |         for (c <- str) {
 | |
| 57 |           if (special1.contains(c)) {
 | |
| 58 | res ++= "\\char" | |
| 59 | res ++= Value.Int(c) | |
| 60 | } | |
| 61 |           else {
 | |
| 62 |             if (special2.contains(c)) { res += '"'}
 | |
| 63 | res += c | |
| 64 | } | |
| 74786 | 65 | } | 
| 66 | } | |
| 67 | } | |
| 68 | else str | |
| 69 | } | |
| 70 | ||
| 75393 | 71 |   object Index_Item {
 | 
| 74786 | 72 | sealed case class Value(text: Text, like: String) | 
| 73 | def unapply(tree: XML.Tree): Option[Value] = | |
| 74 |       tree match {
 | |
| 75 | case XML.Wrapped_Elem(Markup.Latex_Index_Item(_), text, like) => | |
| 76 | Some(Value(text, XML.content(like))) | |
| 77 | case _ => None | |
| 78 | } | |
| 79 | } | |
| 80 | ||
| 75393 | 81 |   object Index_Entry {
 | 
| 74786 | 82 | sealed case class Value(items: List[Index_Item.Value], kind: String) | 
| 83 | def unapply(tree: XML.Tree): Option[Value] = | |
| 84 |       tree match {
 | |
| 85 | case XML.Elem(Markup.Latex_Index_Entry(kind), body) => | |
| 86 | val items = body.map(Index_Item.unapply) | |
| 87 | if (items.forall(_.isDefined)) Some(Value(items.map(_.get), kind)) else None | |
| 88 | case _ => None | |
| 89 | } | |
| 90 | } | |
| 91 | ||
| 92 | ||
| 74839 | 93 | /* tags */ | 
| 94 | ||
| 75393 | 95 |   object Tags {
 | 
| 78601 | 96 |     enum Op { case fold, drop, keep }
 | 
| 74839 | 97 | |
| 98 | val standard = "document,theory,proof,ML,visible,-invisible,important,unimportant" | |
| 99 | ||
| 77218 | 100 |     private def explode(spec: String): List[String] = space_explode(',', spec)
 | 
| 74839 | 101 | |
| 102 | def apply(spec: String): Tags = | |
| 103 | new Tags(spec, | |
| 78601 | 104 |         (explode(standard) ::: explode(spec)).foldLeft(TreeMap.empty[String, Op]) {
 | 
| 74839 | 105 | case (m, tag) => | 
| 106 |             tag.toList match {
 | |
| 107 | case '/' :: cs => m + (cs.mkString -> Op.fold) | |
| 108 | case '-' :: cs => m + (cs.mkString -> Op.drop) | |
| 109 | case '+' :: cs => m + (cs.mkString -> Op.keep) | |
| 110 | case cs => m + (cs.mkString -> Op.keep) | |
| 111 | } | |
| 112 | }) | |
| 113 | ||
| 114 |     val empty: Tags = apply("")
 | |
| 115 | } | |
| 116 | ||
| 78601 | 117 |   class Tags private(spec: String, map: TreeMap[String, Tags.Op]) {
 | 
| 74839 | 118 | override def toString: String = spec | 
| 119 | ||
| 78601 | 120 | def get(name: String): Option[Tags.Op] = map.get(name) | 
| 74839 | 121 | |
| 75393 | 122 |     def sty(comment_latex: Boolean): File.Content = {
 | 
| 74839 | 123 |       val path = Path.explode("isabelletags.sty")
 | 
| 74840 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 124 | val comment = | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 125 |         if (comment_latex) """\usepackage{comment}"""
 | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 126 | else """%plain TeX version of comment package -- much faster! | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 127 | \let\isafmtname\fmtname\def\fmtname{plain}
 | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 128 | \usepackage{comment}
 | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 129 | \let\fmtname\isafmtname""" | 
| 74839 | 130 | val tags = | 
| 131 | (for ((name, op) <- map.iterator) | |
| 132 |           yield "\\isa" + op + "tag{" + name + "}").toList
 | |
| 75824 | 133 | File.content(path, comment + """ | 
| 74839 | 134 | |
| 135 | \newcommand{\isakeeptag}[1]%
 | |
| 136 | {\includecomment{isadelim#1}\includecomment{isatag#1}\csarg\def{isafold#1}{}}
 | |
| 137 | \newcommand{\isadroptag}[1]%
 | |
| 138 | {\excludecomment{isadelim#1}\excludecomment{isatag#1}\csarg\def{isafold#1}{}}
 | |
| 139 | \newcommand{\isafoldtag}[1]%
 | |
| 140 | {\includecomment{isadelim#1}\excludecomment{isatag#1}\csarg\def{isafold#1}{\isafold{#1}}}
 | |
| 141 | ||
| 77216 | 142 | """ + terminate_lines(tags)) | 
| 74839 | 143 | } | 
| 144 | } | |
| 145 | ||
| 146 | ||
| 73780 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 147 | /* output text and positions */ | 
| 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 148 | |
| 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 149 | type Text = XML.Body | 
| 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 150 | |
| 74777 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 151 | def position(a: String, b: String): String = "%:%" + a + "=" + b + "%:%\n" | 
| 73780 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 152 | |
| 74777 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 153 | def init_position(file_pos: String): List[String] = | 
| 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 154 | if (file_pos.isEmpty) Nil | 
| 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 155 |     else List("\\endinput\n", position(Markup.FILE, file_pos))
 | 
| 73780 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 156 | |
| 77000 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 157 |   def append_position(path: Path, file_pos: String): Unit = {
 | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 158 | val pos = init_position(file_pos).mkString | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 159 |     if (pos.nonEmpty) {
 | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 160 |       val sep = if (File.read(path).endsWith("\n")) "" else "\n"
 | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 161 | File.append(path, sep + pos) | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 162 | } | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 163 | } | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 164 | |
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 165 |   def copy_file(src: Path, dst: Path): Unit = {
 | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 166 | Isabelle_System.copy_file(src, dst) | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 167 |     if (src.is_latex) {
 | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 168 | val target = if (dst.is_dir) dst + src.base else dst | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 169 | val file_pos = File.symbolic_path(src) | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 170 | append_position(target, file_pos) | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 171 | } | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 172 | } | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 173 | |
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 174 |   def copy_file_base(base_dir: Path, src: Path, target_dir: Path): Unit = {
 | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 175 | Isabelle_System.copy_file_base(base_dir, src, target_dir) | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 176 |     if (src.is_latex) {
 | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 177 | val file_pos = File.symbolic_path(base_dir + src) | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 178 | append_position(target_dir + src, file_pos) | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 179 | } | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 180 | } | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 181 | |
| 76450 
107d8203fbd7
clarified signature: allow to change options in instances of Document_Build.Engine;
 wenzelm parents: 
75824diff
changeset | 182 |   class Output(val options: Options) {
 | 
| 76826 | 183 | def latex_output(latex_text: Text): String = make(latex_text) | 
| 74786 | 184 | |
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 185 | def latex_macro0(name: String, optional_argument: String = ""): Text = | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 186 |       XML.string("\\" + name + optional_argument)
 | 
| 74790 | 187 | |
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 188 | def latex_macro(name: String, body: Text, optional_argument: String = ""): Text = | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 189 |       XML.enclose("\\" + name + optional_argument + "{", "}", body)
 | 
| 74790 | 190 | |
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 191 | def latex_environment(name: String, body: Text, optional_argument: String = ""): Text = | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 192 | XML.enclose( | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 193 |         "%\n\\begin{" + name + "}" + optional_argument + "%\n",
 | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 194 |         "%\n\\end{" + name + "}", body)
 | 
| 74823 | 195 | |
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 196 | def latex_heading(kind: String, body: Text, optional_argument: String = ""): Text = | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 197 | XML.enclose( | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 198 |         "%\n\\" + options.string("document_heading_prefix") + kind + optional_argument + "{",
 | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 199 | "%\n}\n", body) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 200 | |
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 201 | def latex_body(kind: String, body: Text, optional_argument: String = ""): Text = | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 202 |       latex_environment("isamarkup" + kind, body, optional_argument)
 | 
| 74823 | 203 | |
| 75393 | 204 |     def latex_tag(name: String, body: Text, delim: Boolean = false): Text = {
 | 
| 74826 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 205 | val s = output_name(name) | 
| 74840 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 206 | val kind = if (delim) "delim" else "tag" | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 207 |       val end = if (delim) "" else "{\\isafold" + s + "}%\n"
 | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 208 |       if (options.bool("document_comment_latex")) {
 | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 209 | XML.enclose( | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 210 |           "%\n\\begin{isa" + kind + s + "}\n",
 | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 211 |           "%\n\\end{isa" + kind + s + "}\n" + end, body)
 | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 212 | } | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 213 |       else {
 | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 214 | XML.enclose( | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 215 | "%\n\\isa" + kind + s + "\n", | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 216 | "%\n\\endisa" + kind + s + "\n" + end, body) | 
| 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 217 | } | 
| 74826 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 218 | } | 
| 
0e4d8aa61ad7
more symbolic latex_output via XML (using YXML within text);
 wenzelm parents: 
74824diff
changeset | 219 | |
| 77016 | 220 |     def cite(inner: Bibtex.Cite.Inner): Text = {
 | 
| 221 | val body = | |
| 222 | latex_macro0(inner.kind) ::: | |
| 223 | (if (inner.location.isEmpty) Nil | |
| 224 |          else XML.string("[") ::: inner.location ::: XML.string("]")) :::
 | |
| 77024 | 225 |         XML.string("{" + inner.citations + "}")
 | 
| 77016 | 226 | |
| 227 | if (inner.pos.isEmpty) body | |
| 228 | else List(XML.Elem(Markup.Latex_Output(inner.pos), body)) | |
| 76956 
e47fb5cfef41
clarified Latex markup: optional cite "location" consists of nested document text;
 wenzelm parents: 
76955diff
changeset | 229 | } | 
| 
e47fb5cfef41
clarified Latex markup: optional cite "location" consists of nested document text;
 wenzelm parents: 
76955diff
changeset | 230 | |
| 75393 | 231 |     def index_item(item: Index_Item.Value): String = {
 | 
| 77368 | 232 | val like = if_proper(item.like, index_escape(item.like) + "@") | 
| 74786 | 233 | val text = index_escape(latex_output(item.text)) | 
| 234 | like + text | |
| 235 | } | |
| 236 | ||
| 75393 | 237 |     def index_entry(entry: Index_Entry.Value): Text = {
 | 
| 74786 | 238 |       val items = entry.items.map(index_item).mkString("!")
 | 
| 77368 | 239 | val kind = if_proper(entry.kind, "|" + index_escape(entry.kind)) | 
| 74786 | 240 |       latex_macro("index", XML.string(items + kind))
 | 
| 241 | } | |
| 242 | ||
| 243 | ||
| 244 | /* standard output of text with per-line positions */ | |
| 74784 
d2522bb4db1b
symbolic latex_output via XML, interpreted in Isabelle/Scala;
 wenzelm parents: 
74783diff
changeset | 245 | |
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 246 | def unknown_elem(elem: XML.Elem, pos: Position.T): XML.Body = | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 247 |       error("Unknown latex markup element " + quote(elem.name) + Position.here(pos) +
 | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 248 | ":\n" + XML.string_of_tree(elem)) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 249 | |
| 77005 | 250 | def make( | 
| 251 | latex_text: Text, | |
| 252 | file_pos: String = "", | |
| 253 | line_pos: Properties.T => Option[Int] = Position.Line.unapply | |
| 254 |     ): String = {
 | |
| 74777 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 255 | var line = 1 | 
| 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 256 | val result = new mutable.ListBuffer[String] | 
| 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 257 | val positions = new mutable.ListBuffer[String] ++= init_position(file_pos) | 
| 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 258 | |
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 259 | val file_position = if (file_pos.isEmpty) Position.none else Position.File(file_pos) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 260 | |
| 75393 | 261 |       def traverse(xml: XML.Body): Unit = {
 | 
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 262 |         xml.foreach {
 | 
| 74777 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 263 | case XML.Text(s) => | 
| 77007 | 264 | line += Library.count_newlines(s) | 
| 74777 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 265 | result += s | 
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 266 | case elem @ XML.Elem(markup, body) => | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 267 | val a = Markup.Optional_Argument.get(markup.properties) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 268 |             traverse {
 | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 269 |               markup match {
 | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 270 | case Markup.Document_Latex(props) => | 
| 77005 | 271 |                   if (positions.nonEmpty) {
 | 
| 272 |                     for (l <- line_pos(props)) {
 | |
| 273 | val s = position(Value.Int(line), Value.Int(l)) | |
| 274 | if (positions.last != s) positions += s | |
| 275 | } | |
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 276 | } | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 277 | body | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 278 | case Markup.Latex_Output(_) => XML.string(latex_output(body)) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 279 | case Markup.Latex_Macro0(name) if body.isEmpty => latex_macro0(name, a) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 280 | case Markup.Latex_Macro(name) => latex_macro(name, body, a) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 281 | case Markup.Latex_Environment(name) => latex_environment(name, body, a) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 282 | case Markup.Latex_Heading(kind) => latex_heading(kind, body, a) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 283 | case Markup.Latex_Body(kind) => latex_body(kind, body, a) | 
| 74840 
4faf0ec33cbf
option document_comment_latex supports e.g. Dagstuhl LIPIcs;
 wenzelm parents: 
74839diff
changeset | 284 | case Markup.Latex_Delim(name) => latex_tag(name, body, delim = true) | 
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 285 | case Markup.Latex_Tag(name) => latex_tag(name, body) | 
| 76955 | 286 | case Markup.Latex_Cite(_) => | 
| 287 |                   elem match {
 | |
| 77016 | 288 | case Bibtex.Cite(inner) => cite(inner) | 
| 76955 | 289 | case _ => unknown_elem(elem, file_position) | 
| 290 | } | |
| 74838 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 291 | case Markup.Latex_Index_Entry(_) => | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 292 |                   elem match {
 | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 293 | case Index_Entry(entry) => index_entry(entry) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 294 | case _ => unknown_elem(elem, file_position) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 295 | } | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 296 | case _ => unknown_elem(elem, file_position) | 
| 
4c8d9479f916
more uniform treatment of optional_argument for Latex elements;
 wenzelm parents: 
74836diff
changeset | 297 | } | 
| 74783 | 298 | } | 
| 74777 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 299 | } | 
| 73780 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 300 | } | 
| 74777 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 301 | traverse(latex_text) | 
| 73780 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 302 | |
| 74777 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 303 | result ++= positions | 
| 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 304 | result.mkString | 
| 
2fd0c33fe440
clarified signature: Latex.Output as parameter to Document_Build.Engine;
 wenzelm parents: 
74748diff
changeset | 305 | } | 
| 73780 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 306 | } | 
| 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 307 | |
| 
466fae6bf22e
compose Latex text as XML, output exported YXML in Isabelle/Scala;
 wenzelm parents: 
73736diff
changeset | 308 | |
| 67173 | 309 | /* generated .tex file */ | 
| 310 | ||
| 67184 | 311 | private val File_Pattern = """^%:%file=(.+)%:%$""".r | 
| 67194 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 312 | private val Line_Pattern = """^*%:%(\d+)=(\d+)%:%$""".r | 
| 67173 | 313 | |
| 75393 | 314 |   def read_tex_file(tex_file: Path): Tex_File = {
 | 
| 67194 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 315 | val positions = | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 316 | Line.logical_lines(File.read(tex_file)).reverse. | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 317 | takeWhile(_ != "\\endinput").reverse | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 318 | |
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 319 | val source_file = | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 320 |       positions match {
 | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 321 | case File_Pattern(file) :: _ => Some(file) | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 322 | case _ => None | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 323 | } | 
| 67173 | 324 | |
| 67194 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 325 | val source_lines = | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 326 | if (source_file.isEmpty) Nil | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 327 | else | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 328 | positions.flatMap(line => | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 329 |           line match {
 | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 330 | case Line_Pattern(Value.Int(line), Value.Int(source_line)) => Some(line -> source_line) | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 331 | case _ => None | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 332 | }) | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 333 | |
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 334 | new Tex_File(tex_file, source_file, source_lines) | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 335 | } | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 336 | |
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 337 | final class Tex_File private[Latex]( | 
| 75393 | 338 | tex_file: Path, | 
| 339 | source_file: Option[String], | |
| 340 | source_lines: List[(Int, Int)] | |
| 341 |   ) {
 | |
| 67173 | 342 | override def toString: String = tex_file.toString | 
| 343 | ||
| 67194 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 344 | def source_position(l: Int): Option[Position.T] = | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 345 |       source_file match {
 | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 346 | case None => None | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 347 | case Some(file) => | 
| 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 348 | val source_line = | 
| 73359 | 349 |             source_lines.iterator.takeWhile({ case (m, _) => m <= l }).
 | 
| 350 |               foldLeft(0) { case (_, (_, n)) => n }
 | |
| 67194 
1c0a6a957114
positions as postlude: avoid intrusion of odd %-forms into main tex source;
 wenzelm parents: 
67190diff
changeset | 351 | if (source_line == 0) None else Some(Position.Line_File(source_line, file)) | 
| 67173 | 352 | } | 
| 353 | ||
| 354 | def position(line: Int): Position.T = | |
| 77000 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 355 | source_position(line) getOrElse | 
| 
ffc0774e0efe
clarified file positions: retain original source path;
 wenzelm parents: 
76962diff
changeset | 356 | Position.Line_File(line, source_file.getOrElse(tex_file.implode)) | 
| 67173 | 357 | } | 
| 358 | ||
| 359 | ||
| 360 | /* latex log */ | |
| 361 | ||
| 75393 | 362 |   def latex_errors(dir: Path, root_name: String): List[String] = {
 | 
| 77035 | 363 | val root_log_path = dir + Path.explode(root_name).log | 
| 73782 | 364 |     if (root_log_path.is_file) {
 | 
| 365 |       for { (msg, pos) <- filter_errors(dir, File.read(root_log_path)) }
 | |
| 366 | yield "Latex error" + Position.here(pos) + ":\n" + Library.indent_lines(2, msg) | |
| 367 | } | |
| 368 | else Nil | |
| 369 | } | |
| 370 | ||
| 75393 | 371 |   def filter_errors(dir: Path, root_log: String): List[(String, Position.T)] = {
 | 
| 67173 | 372 | val seen_files = Synchronized(Map.empty[JFile, Tex_File]) | 
| 373 | ||
| 374 | def check_tex_file(path: Path): Option[Tex_File] = | |
| 375 | seen_files.change_result(seen => | |
| 376 |         seen.get(path.file) match {
 | |
| 377 | case None => | |
| 378 |             if (path.is_file) {
 | |
| 379 | val tex_file = read_tex_file(path) | |
| 380 | (Some(tex_file), seen + (path.file -> tex_file)) | |
| 381 | } | |
| 382 | else (None, seen) | |
| 383 | case some => (some, seen) | |
| 384 | }) | |
| 385 | ||
| 386 | def tex_file_position(path: Path, line: Int): Position.T = | |
| 387 |       check_tex_file(path) match {
 | |
| 388 | case Some(tex_file) => tex_file.position(line) | |
| 389 | case None => Position.Line_File(line, path.implode) | |
| 390 | } | |
| 391 | ||
| 75393 | 392 |     object File_Line_Error {
 | 
| 71601 | 393 | val Pattern: Regex = """^(.*?\.\w\w\w):(\d+): (.*)$""".r | 
| 67173 | 394 | def unapply(line: String): Option[(Path, Int, String)] = | 
| 67172 | 395 |         line match {
 | 
| 396 | case Pattern(file, Value.Int(line), message) => | |
| 397 | val path = File.standard_path(file) | |
| 398 |             if (Path.is_wellformed(path)) {
 | |
| 67183 | 399 | val file = (dir + Path.explode(path)).canonical | 
| 67423 | 400 |               val msg = Library.perhaps_unprefix("LaTeX Error: ", message)
 | 
| 401 | if (file.is_file) Some((file, line, msg)) else None | |
| 67172 | 402 | } | 
| 403 | else None | |
| 404 | case _ => None | |
| 405 | } | |
| 406 | } | |
| 407 | ||
| 67418 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 408 | val Line_Error = """^l\.\d+ (.*)$""".r | 
| 67196 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 409 | val More_Error = | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 410 | List( | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 411 | "<argument>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 412 | "<template>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 413 | "<recently read>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 414 | "<to be read again>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 415 | "<inserted text>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 416 | "<output>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 417 | "<everypar>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 418 | "<everymath>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 419 | "<everydisplay>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 420 | "<everyhbox>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 421 | "<everyvbox>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 422 | "<everyjob>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 423 | "<everycr>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 424 | "<mark>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 425 | "<everyeof>", | 
| 
eb29f4868d14
more error information according to @<Print type of token list@> in pdfweb.tex;
 wenzelm parents: 
67194diff
changeset | 426 |         "<write>").mkString("^(?:", "|", ") (.*)$").r
 | 
| 67172 | 427 | |
| 73474 
4e12a6caefb3
turn LaTeX warning into error, for the sake of isabelle.sty/bbbfont;
 wenzelm parents: 
73359diff
changeset | 428 | val Bad_Font = """^LaTeX Font Warning: (Font .*\btxmia\b.* undefined).*$""".r | 
| 67483 
aae933ca6fbd
tuned message: same error may occur in different contexts;
 wenzelm parents: 
67482diff
changeset | 429 | val Bad_File = """^! LaTeX Error: (File `.*' not found\.)$""".r | 
| 67482 | 430 | |
| 67423 | 431 | val error_ignore = | 
| 432 | Set( | |
| 433 | "See the LaTeX manual or LaTeX Companion for explanation.", | |
| 434 | "Type H <return> for immediate help.") | |
| 435 | ||
| 75393 | 436 |     def error_suffix1(lines: List[String]): Option[String] = {
 | 
| 71784 | 437 | val lines1 = | 
| 438 |         lines.take(20).takeWhile({ case File_Line_Error((_, _, _)) => false case _ => true })
 | |
| 67418 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 439 |       lines1.zipWithIndex.collectFirst({
 | 
| 67423 | 440 | case (Line_Error(msg), i) => | 
| 441 | cat_lines(lines1.take(i).filterNot(error_ignore) ::: List(msg)) }) | |
| 67418 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 442 | } | 
| 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 443 | def error_suffix2(lines: List[String]): Option[String] = | 
| 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 444 |       lines match {
 | 
| 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 445 | case More_Error(msg) :: _ => Some(msg) | 
| 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 446 | case _ => None | 
| 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 447 | } | 
| 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 448 | |
| 75393 | 449 | @tailrec def filter( | 
| 450 | lines: List[String], | |
| 451 | result: List[(String, Position.T)] | |
| 452 |     ) : List[(String, Position.T)] = {
 | |
| 67172 | 453 |       lines match {
 | 
| 67173 | 454 | case File_Line_Error((file, line, msg1)) :: rest1 => | 
| 67183 | 455 | val pos = tex_file_position(file, line) | 
| 67418 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 456 | val msg2 = error_suffix1(rest1) orElse error_suffix2(rest1) getOrElse "" | 
| 
5a6ed2e679fb
more general error suffixes, e.g. for messages that are broken over several lines;
 wenzelm parents: 
67417diff
changeset | 457 | filter(rest1, (Exn.cat_message(msg1, msg2), pos) :: result) | 
| 73474 
4e12a6caefb3
turn LaTeX warning into error, for the sake of isabelle.sty/bbbfont;
 wenzelm parents: 
73359diff
changeset | 458 | case Bad_Font(msg) :: rest => | 
| 
4e12a6caefb3
turn LaTeX warning into error, for the sake of isabelle.sty/bbbfont;
 wenzelm parents: 
73359diff
changeset | 459 | filter(rest, (msg, Position.none) :: result) | 
| 67483 
aae933ca6fbd
tuned message: same error may occur in different contexts;
 wenzelm parents: 
67482diff
changeset | 460 | case Bad_File(msg) :: rest => | 
| 67482 | 461 | filter(rest, (msg, Position.none) :: result) | 
| 67172 | 462 | case _ :: rest => filter(rest, result) | 
| 463 | case Nil => result.reverse | |
| 464 | } | |
| 67173 | 465 | } | 
| 67172 | 466 | |
| 67174 | 467 | filter(Line.logical_lines(root_log), Nil) | 
| 67173 | 468 | } | 
| 67172 | 469 | } |