| author | wenzelm | 
| Thu, 02 Nov 2023 10:29:24 +0100 | |
| changeset 78875 | b7d355b2b176 | 
| parent 78592 | fdfe9b91d96e | 
| child 80889 | 510f6cb6721e | 
| permissions | -rw-r--r-- | 
| 64622 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 1 | /* Title: Pure/PIDE/rendering.scala | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 2 | Author: Makarius | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 3 | |
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 4 | Isabelle-specific implementation of quasi-abstract rendering and | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 5 | markup interpretation. | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 6 | */ | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 7 | |
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 8 | package isabelle | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 9 | |
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 10 | |
| 66158 | 11 | import java.io.{File => JFile}
 | 
| 12 | import java.nio.file.FileSystems | |
| 13 | ||
| 72869 | 14 | import scala.collection.immutable.SortedMap | 
| 15 | ||
| 16 | ||
| 66158 | 17 | |
| 75393 | 18 | object Rendering {
 | 
| 65101 | 19 | /* color */ | 
| 20 | ||
| 75393 | 21 |   object Color extends Enumeration {
 | 
| 65104 
66b19d05dcee
decorations for background and foreground colors;
 wenzelm parents: 
65101diff
changeset | 22 | // background | 
| 68871 
f5c76072db55
more explicit status for "canceled" command within theory node;
 wenzelm parents: 
68822diff
changeset | 23 | val unprocessed1, running1, canceled, bad, intensify, entity, active, active_result, | 
| 67322 | 24 | markdown_bullet1, markdown_bullet2, markdown_bullet3, markdown_bullet4 = Value | 
| 71601 | 25 | val background_colors: ValueSet = values | 
| 65104 
66b19d05dcee
decorations for background and foreground colors;
 wenzelm parents: 
65101diff
changeset | 26 | |
| 
66b19d05dcee
decorations for background and foreground colors;
 wenzelm parents: 
65101diff
changeset | 27 | // foreground | 
| 65637 | 28 | val quoted, antiquoted = Value | 
| 71601 | 29 | val foreground_colors: ValueSet = values -- background_colors | 
| 65121 | 30 | |
| 65124 | 31 | // message underline | 
| 65637 | 32 | val writeln, information, warning, legacy, error = Value | 
| 71601 | 33 | val message_underline_colors: ValueSet = values -- background_colors -- foreground_colors | 
| 65124 | 34 | |
| 35 | // message background | |
| 65637 | 36 | val writeln_message, information_message, tracing_message, | 
| 37 | warning_message, legacy_message, error_message = Value | |
| 71601 | 38 | val message_background_colors: ValueSet = | 
| 65143 | 39 | values -- background_colors -- foreground_colors -- message_underline_colors | 
| 65144 | 40 | |
| 41 | // text | |
| 65637 | 42 | val main, keyword1, keyword2, keyword3, quasi_keyword, improper, operator, | 
| 43 | tfree, tvar, free, skolem, bound, `var`, inner_numeral, inner_quoted, | |
| 69965 
da5e7278286b
more markup for various text kinds, notably for nested formal comments;
 wenzelm parents: 
69916diff
changeset | 44 | inner_cartouche, comment1, comment2, comment3, dynamic, class_parameter, | 
| 
da5e7278286b
more markup for various text kinds, notably for nested formal comments;
 wenzelm parents: 
69916diff
changeset | 45 | antiquote, raw_text, plain_text = Value | 
| 71601 | 46 | val text_colors: ValueSet = | 
| 65144 | 47 | values -- background_colors -- foreground_colors -- message_underline_colors -- | 
| 48 | message_background_colors | |
| 65911 | 49 | |
| 65913 | 50 | // text overview | 
| 65911 | 51 | val unprocessed, running = Value | 
| 65913 | 52 | val text_overview_colors = Set(unprocessed, running, error, warning) | 
| 65101 | 53 | } | 
| 54 | ||
| 55 | ||
| 65190 | 56 | /* output messages */ | 
| 64676 | 57 | |
| 58 | val state_pri = 1 | |
| 59 | val writeln_pri = 2 | |
| 60 | val information_pri = 3 | |
| 61 | val tracing_pri = 4 | |
| 62 | val warning_pri = 5 | |
| 63 | val legacy_pri = 6 | |
| 64 | val error_pri = 7 | |
| 65 | ||
| 66 | val message_pri = Map( | |
| 67 | Markup.STATE -> state_pri, | |
| 68 | Markup.STATE_MESSAGE -> state_pri, | |
| 69 | Markup.WRITELN -> writeln_pri, | |
| 70 | Markup.WRITELN_MESSAGE -> writeln_pri, | |
| 71 | Markup.INFORMATION -> information_pri, | |
| 72 | Markup.INFORMATION_MESSAGE -> information_pri, | |
| 73 | Markup.TRACING -> tracing_pri, | |
| 74 | Markup.TRACING_MESSAGE -> tracing_pri, | |
| 75 | Markup.WARNING -> warning_pri, | |
| 76 | Markup.WARNING_MESSAGE -> warning_pri, | |
| 77 | Markup.LEGACY -> legacy_pri, | |
| 78 | Markup.LEGACY_MESSAGE -> legacy_pri, | |
| 79 | Markup.ERROR -> error_pri, | |
| 65133 | 80 | Markup.ERROR_MESSAGE -> error_pri | 
| 81 | ).withDefaultValue(0) | |
| 64676 | 82 | |
| 65121 | 83 | val message_underline_color = Map( | 
| 84 | writeln_pri -> Color.writeln, | |
| 85 | information_pri -> Color.information, | |
| 86 | warning_pri -> Color.warning, | |
| 87 | legacy_pri -> Color.legacy, | |
| 88 | error_pri -> Color.error) | |
| 89 | ||
| 65124 | 90 | val message_background_color = Map( | 
| 91 | writeln_pri -> Color.writeln_message, | |
| 92 | information_pri -> Color.information_message, | |
| 93 | tracing_pri -> Color.tracing_message, | |
| 94 | warning_pri -> Color.warning_message, | |
| 95 | legacy_pri -> Color.legacy_message, | |
| 96 | error_pri -> Color.error_message) | |
| 97 | ||
| 75840 
f8c412a45af8
more accurate treatment of option "editor_output_state", e.g. when changed via Isabelle/jEdit Plugin Options panel;
 wenzelm parents: 
75419diff
changeset | 98 |   def output_messages(results: Command.Results, output_state: Boolean): List[XML.Elem] = {
 | 
| 65190 | 99 | val (states, other) = | 
| 72727 | 100 | results.iterator.map(_._2).filterNot(Protocol.is_result).toList | 
| 101 | .partition(Protocol.is_state) | |
| 75840 
f8c412a45af8
more accurate treatment of option "editor_output_state", e.g. when changed via Isabelle/jEdit Plugin Options panel;
 wenzelm parents: 
75419diff
changeset | 102 | (if (output_state) states else Nil) ::: other | 
| 65190 | 103 | } | 
| 104 | ||
| 64676 | 105 | |
| 65144 | 106 | /* text color */ | 
| 107 | ||
| 108 | val text_color = Map( | |
| 109 | Markup.KEYWORD1 -> Color.keyword1, | |
| 110 | Markup.KEYWORD2 -> Color.keyword2, | |
| 111 | Markup.KEYWORD3 -> Color.keyword3, | |
| 112 | Markup.QUASI_KEYWORD -> Color.quasi_keyword, | |
| 113 | Markup.IMPROPER -> Color.improper, | |
| 114 | Markup.OPERATOR -> Color.operator, | |
| 65145 | 115 | Markup.STRING -> Color.main, | 
| 116 | Markup.ALT_STRING -> Color.main, | |
| 117 | Markup.CARTOUCHE -> Color.main, | |
| 65144 | 118 | Markup.LITERAL -> Color.keyword1, | 
| 65145 | 119 | Markup.DELIMITER -> Color.main, | 
| 65144 | 120 | Markup.TFREE -> Color.tfree, | 
| 121 | Markup.TVAR -> Color.tvar, | |
| 122 | Markup.FREE -> Color.free, | |
| 123 | Markup.SKOLEM -> Color.skolem, | |
| 124 | Markup.BOUND -> Color.bound, | |
| 65637 | 125 | Markup.VAR -> Color.`var`, | 
| 65144 | 126 | Markup.INNER_STRING -> Color.inner_quoted, | 
| 127 | Markup.INNER_CARTOUCHE -> Color.inner_cartouche, | |
| 128 | Markup.DYNAMIC_FACT -> Color.dynamic, | |
| 129 | Markup.CLASS_PARAMETER -> Color.class_parameter, | |
| 130 | Markup.ANTIQUOTE -> Color.antiquote, | |
| 69965 
da5e7278286b
more markup for various text kinds, notably for nested formal comments;
 wenzelm parents: 
69916diff
changeset | 131 | Markup.RAW_TEXT -> Color.raw_text, | 
| 
da5e7278286b
more markup for various text kinds, notably for nested formal comments;
 wenzelm parents: 
69916diff
changeset | 132 | Markup.PLAIN_TEXT -> Color.plain_text, | 
| 65144 | 133 | Markup.ML_KEYWORD1 -> Color.keyword1, | 
| 134 | Markup.ML_KEYWORD2 -> Color.keyword2, | |
| 135 | Markup.ML_KEYWORD3 -> Color.keyword3, | |
| 65145 | 136 | Markup.ML_DELIMITER -> Color.main, | 
| 65144 | 137 | Markup.ML_NUMERAL -> Color.inner_numeral, | 
| 138 | Markup.ML_CHAR -> Color.inner_quoted, | |
| 139 | Markup.ML_STRING -> Color.inner_quoted, | |
| 69320 | 140 | Markup.ML_COMMENT -> Color.comment1, | 
| 69970 
b5a47478897a
clarified rendering, notably of \<^latex>CARTOUCHE in outer syntax;
 wenzelm parents: 
69965diff
changeset | 141 | Markup.COMMENT -> Color.comment1, | 
| 69320 | 142 | Markup.COMMENT1 -> Color.comment1, | 
| 143 | Markup.COMMENT2 -> Color.comment2, | |
| 144 | Markup.COMMENT3 -> Color.comment3) | |
| 65144 | 145 | |
| 66074 | 146 | val foreground = | 
| 147 | Map( | |
| 148 | Markup.STRING -> Color.quoted, | |
| 149 | Markup.ALT_STRING -> Color.quoted, | |
| 150 | Markup.CARTOUCHE -> Color.quoted, | |
| 151 | Markup.ANTIQUOTED -> Color.antiquoted) | |
| 152 | ||
| 65144 | 153 | |
| 65149 | 154 | /* tooltips */ | 
| 65101 | 155 | |
| 65149 | 156 | val tooltip_descriptions = | 
| 64622 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 157 | Map( | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 158 | Markup.TOKEN_RANGE -> "inner syntax token", | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 159 | Markup.FREE -> "free variable", | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 160 | Markup.SKOLEM -> "skolem variable", | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 161 | Markup.BOUND -> "bound variable", | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 162 | Markup.VAR -> "schematic variable", | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 163 | Markup.TFREE -> "free type variable", | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 164 | Markup.TVAR -> "schematic type variable") | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 165 | |
| 65149 | 166 | |
| 72900 | 167 | /* entity focus */ | 
| 168 | ||
| 75393 | 169 |   object Focus {
 | 
| 72900 | 170 | def apply(ids: Set[Long]): Focus = new Focus(ids) | 
| 171 | val empty: Focus = apply(Set.empty) | |
| 72905 | 172 | def make(args: List[Text.Info[Focus]]): Focus = | 
| 73359 | 173 |       args.foldLeft(empty) { case (focus1, Text.Info(_, focus2)) => focus1 ++ focus2 }
 | 
| 72927 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 174 | |
| 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 175 | val full: Focus = | 
| 75393 | 176 |       new Focus(Set.empty) {
 | 
| 72927 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 177 | override def apply(id: Long): Boolean = true | 
| 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 178 | override def toString: String = "Focus.full" | 
| 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 179 | } | 
| 72900 | 180 | } | 
| 181 | ||
| 75393 | 182 |   sealed class Focus private[Rendering](protected val rep: Set[Long]) {
 | 
| 72900 | 183 | def defined: Boolean = rep.nonEmpty | 
| 184 | def apply(id: Long): Boolean = rep.contains(id) | |
| 185 | def + (id: Long): Focus = if (rep.contains(id)) this else new Focus(rep + id) | |
| 186 | def ++ (other: Focus): Focus = | |
| 187 | if (this eq other) this | |
| 188 | else if (rep.isEmpty) other | |
| 73359 | 189 | else other.rep.iterator.foldLeft(this)(_ + _) | 
| 72900 | 190 |     override def toString: String = rep.mkString("Focus(", ",", ")")
 | 
| 191 | } | |
| 192 | ||
| 193 | ||
| 65149 | 194 | /* markup elements */ | 
| 195 | ||
| 72692 
22aeec526ffd
support for PIDE markup in batch build (inactive due to pide_reports=false);
 wenzelm parents: 
71601diff
changeset | 196 | val position_elements = | 
| 
22aeec526ffd
support for PIDE markup in batch build (inactive due to pide_reports=false);
 wenzelm parents: 
71601diff
changeset | 197 | Markup.Elements(Markup.BINDING, Markup.ENTITY, Markup.REPORT, Markup.POSITION) | 
| 
22aeec526ffd
support for PIDE markup in batch build (inactive due to pide_reports=false);
 wenzelm parents: 
71601diff
changeset | 198 | |
| 66053 | 199 | val semantic_completion_elements = | 
| 200 | Markup.Elements(Markup.COMPLETION, Markup.NO_COMPLETION) | |
| 201 | ||
| 202 | val language_context_elements = | |
| 74887 | 203 | Markup.Elements(Markup.STRING, Markup.ALT_STRING, | 
| 66053 | 204 | Markup.CARTOUCHE, Markup.COMMENT, Markup.LANGUAGE, | 
| 205 | Markup.ML_STRING, Markup.ML_COMMENT) | |
| 206 | ||
| 207 | val language_elements = Markup.Elements(Markup.LANGUAGE) | |
| 208 | ||
| 65149 | 209 | val active_elements = | 
| 69650 | 210 | Markup.Elements(Markup.DIALOG, Markup.BROWSER, Markup.GRAPHVIEW, Markup.THEORY_EXPORTS, | 
| 65149 | 211 | Markup.SENDBACK, Markup.JEDIT_ACTION, Markup.SIMP_TRACE_PANEL) | 
| 212 | ||
| 213 | val background_elements = | |
| 68758 | 214 | Document_Status.Command_Status.proper_elements + Markup.WRITELN_MESSAGE + | 
| 65149 | 215 | Markup.STATE_MESSAGE + Markup.INFORMATION_MESSAGE + | 
| 216 | Markup.TRACING_MESSAGE + Markup.WARNING_MESSAGE + | |
| 217 | Markup.LEGACY_MESSAGE + Markup.ERROR_MESSAGE + | |
| 218 | Markup.BAD + Markup.INTENSIFY + Markup.ENTITY + | |
| 67322 | 219 | Markup.Markdown_Bullet.name ++ active_elements | 
| 65149 | 220 | |
| 66074 | 221 | val foreground_elements = Markup.Elements(foreground.keySet) | 
| 222 | ||
| 223 | val text_color_elements = Markup.Elements(text_color.keySet) | |
| 65149 | 224 | |
| 65129 
06a7c2d316cf
more general tooltips, with uniform info range handling;
 wenzelm parents: 
65126diff
changeset | 225 | val tooltip_elements = | 
| 64622 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 226 | Markup.Elements(Markup.LANGUAGE, Markup.EXPRESSION, Markup.TIMING, Markup.ENTITY, | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 227 | Markup.SORTING, Markup.TYPING, Markup.CLASS_PARAMETER, Markup.ML_TYPING, | 
| 69650 | 228 | Markup.ML_BREAKPOINT, Markup.PATH, Markup.DOC, Markup.URL, | 
| 69648 | 229 | Markup.MARKDOWN_PARAGRAPH, Markup.MARKDOWN_ITEM, Markup.Markdown_List.name) ++ | 
| 67323 
d02208cefbdb
PIDE markup for Markdown items (which may consist of multiple paragraphs or lists);
 wenzelm parents: 
67322diff
changeset | 230 | Markup.Elements(tooltip_descriptions.keySet) | 
| 64622 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 231 | |
| 65129 
06a7c2d316cf
more general tooltips, with uniform info range handling;
 wenzelm parents: 
65126diff
changeset | 232 | val tooltip_message_elements = | 
| 
06a7c2d316cf
more general tooltips, with uniform info range handling;
 wenzelm parents: 
65126diff
changeset | 233 | Markup.Elements(Markup.WRITELN, Markup.INFORMATION, Markup.WARNING, Markup.LEGACY, Markup.ERROR, | 
| 
06a7c2d316cf
more general tooltips, with uniform info range handling;
 wenzelm parents: 
65126diff
changeset | 234 | Markup.BAD) | 
| 
06a7c2d316cf
more general tooltips, with uniform info range handling;
 wenzelm parents: 
65126diff
changeset | 235 | |
| 72858 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 236 | val message_elements = Markup.Elements(message_pri.keySet) | 
| 71499 | 237 | val warning_elements = Markup.Elements(Markup.WARNING, Markup.LEGACY) | 
| 71566 
76b739c0bedd
backed out changeset 7eadccd4392c: too confusing wrt. text overview panel;
 wenzelm parents: 
71555diff
changeset | 238 | val error_elements = Markup.Elements(Markup.ERROR) | 
| 71499 | 239 | |
| 72901 | 240 | val entity_elements = Markup.Elements(Markup.ENTITY) | 
| 67132 | 241 | |
| 242 | val antiquoted_elements = Markup.Elements(Markup.ANTIQUOTED) | |
| 67336 | 243 | |
| 69900 | 244 | val meta_data_elements = | 
| 245 | Markup.Elements(Markup.META_TITLE, Markup.META_CREATOR, Markup.META_CONTRIBUTOR, | |
| 69916 
3235ecdcd884
more meta data from "dcterms" (superset of "dc");
 wenzelm parents: 
69900diff
changeset | 246 | Markup.META_DATE, Markup.META_DESCRIPTION, Markup.META_LICENSE) | 
| 69900 | 247 | |
| 70135 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 248 | val document_tag_elements = | 
| 74782 | 249 | Markup.Elements(Markup.Document_Tag.name) | 
| 70135 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 250 | |
| 67336 | 251 | val markdown_elements = | 
| 252 | Markup.Elements(Markup.MARKDOWN_PARAGRAPH, Markup.MARKDOWN_ITEM, Markup.Markdown_List.name, | |
| 253 | Markup.Markdown_Bullet.name) | |
| 64622 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 254 | } | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 255 | |
| 72856 | 256 | class Rendering( | 
| 64622 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 257 | val snapshot: Document.Snapshot, | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 258 | val options: Options, | 
| 75393 | 259 | val session: Session | 
| 260 | ) {
 | |
| 64622 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 261 |   override def toString: String = "Rendering(" + snapshot.toString + ")"
 | 
| 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 262 | |
| 72856 | 263 | def get_text(range: Text.Range): Option[String] = None | 
| 66114 | 264 | |
| 64622 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 265 | |
| 66117 | 266 | /* caret */ | 
| 267 | ||
| 75393 | 268 |   def before_caret_range(caret: Text.Offset): Text.Range = {
 | 
| 66117 | 269 | val former_caret = snapshot.revert(caret) | 
| 270 | snapshot.convert(Text.Range(former_caret - 1, former_caret)) | |
| 271 | } | |
| 272 | ||
| 273 | ||
| 64877 | 274 | /* completion */ | 
| 275 | ||
| 66054 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 276 | def semantic_completion(completed_range: Option[Text.Range], caret_range: Text.Range) | 
| 64877 | 277 | : Option[Text.Info[Completion.Semantic]] = | 
| 278 | if (snapshot.is_outdated) None | |
| 279 |     else {
 | |
| 66054 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 280 | snapshot.select(caret_range, Rendering.semantic_completion_elements, _ => | 
| 64877 | 281 |         {
 | 
| 282 | case Completion.Semantic.Info(info) => | |
| 283 |             completed_range match {
 | |
| 284 | case Some(range0) if range0.contains(info.range) && range0 != info.range => None | |
| 285 | case _ => Some(info) | |
| 286 | } | |
| 287 | case _ => None | |
| 288 | }).headOption.map(_.info) | |
| 289 | } | |
| 290 | ||
| 66054 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 291 | def semantic_completion_result( | 
| 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 292 | history: Completion.History, | 
| 66055 | 293 | unicode: Boolean, | 
| 66054 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 294 | completed_range: Option[Text.Range], | 
| 75393 | 295 | caret_range: Text.Range | 
| 296 |   ): (Boolean, Option[Completion.Result]) = {
 | |
| 66054 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 297 |     semantic_completion(completed_range, caret_range) match {
 | 
| 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 298 | case Some(Text.Info(_, Completion.No_Completion)) => (true, None) | 
| 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 299 | case Some(Text.Info(range, names: Completion.Names)) => | 
| 72856 | 300 |         get_text(range) match {
 | 
| 66055 | 301 | case Some(original) => (false, names.complete(range, history, unicode, original)) | 
| 66054 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 302 | case None => (false, None) | 
| 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 303 | } | 
| 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 304 | case None => (false, None) | 
| 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 305 | } | 
| 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 306 | } | 
| 
fb0eea226a4d
more uniform syntax_completion + semantic_completion;
 wenzelm parents: 
66053diff
changeset | 307 | |
| 66053 | 308 | def language_context(range: Text.Range): Option[Completion.Language_Context] = | 
| 309 | snapshot.select(range, Rendering.language_context_elements, _ => | |
| 310 |       {
 | |
| 76965 | 311 | case Text.Info(_, XML.Elem(Markup.Language(lang), _)) => | 
| 312 | if (lang.delimited) Some(Completion.Language_Context(lang)) else None | |
| 66053 | 313 | case Text.Info(_, elem) | 
| 314 | if elem.name == Markup.ML_STRING || elem.name == Markup.ML_COMMENT => | |
| 315 | Some(Completion.Language_Context.ML_inner) | |
| 316 | case Text.Info(_, _) => | |
| 317 | Some(Completion.Language_Context.inner) | |
| 318 | }).headOption.map(_.info) | |
| 319 | ||
| 66158 | 320 | |
| 321 | /* file-system path completion */ | |
| 322 | ||
| 72842 
6aae62f55c2b
clarified markup: support more completion, e.g. within ROOTS;
 wenzelm parents: 
72729diff
changeset | 323 | def language_path(range: Text.Range): Option[Text.Info[Boolean]] = | 
| 66053 | 324 | snapshot.select(range, Rendering.language_elements, _ => | 
| 325 |       {
 | |
| 76965 | 326 | case Text.Info(info_range, XML.Elem(Markup.Language(lang), _)) if lang.is_path => | 
| 327 | Some((lang.delimited, snapshot.convert(info_range))) | |
| 66053 | 328 | case _ => None | 
| 72842 
6aae62f55c2b
clarified markup: support more completion, e.g. within ROOTS;
 wenzelm parents: 
72729diff
changeset | 329 |       }).headOption.map({ case Text.Info(_, (delimited, range)) => Text.Info(range, delimited) })
 | 
| 66053 | 330 | |
| 75393 | 331 |   def path_completion(caret: Text.Offset): Option[Completion.Result] = {
 | 
| 332 |     def complete(text: String): List[(String, List[String])] = {
 | |
| 66158 | 333 |       try {
 | 
| 334 | val path = Path.explode(text) | |
| 335 | val (dir, base_name) = | |
| 336 |           if (text == "" || text.endsWith("/")) (path, "")
 | |
| 69366 | 337 | else (path.dir, path.file_name) | 
| 66158 | 338 | |
| 76858 | 339 | val directory = new JFile(session.resources.append_path(snapshot.node_name.master_dir, dir)) | 
| 66158 | 340 | val files = directory.listFiles | 
| 341 | if (files == null) Nil | |
| 342 |         else {
 | |
| 343 | val ignore = | |
| 66923 | 344 |             space_explode(':', options.string("completion_path_ignore")).
 | 
| 66158 | 345 |               map(s => FileSystems.getDefault.getPathMatcher("glob:" + s))
 | 
| 346 |           (for {
 | |
| 347 | file <- files.iterator | |
| 348 | ||
| 349 | name = file.getName | |
| 350 | if name.startsWith(base_name) | |
| 351 | path_name = new JFile(name).toPath | |
| 352 | if !ignore.exists(matcher => matcher.matches(path_name)) | |
| 353 | ||
| 354 | text1 = (dir + Path.basic(name)).implode_short | |
| 355 | if text != text1 | |
| 356 | ||
| 357 | is_dir = new JFile(directory, name).isDirectory | |
| 358 | replacement = text1 + (if (is_dir) "/" else "") | |
| 359 | descr = List(text1, if (is_dir) "(directory)" else "(file)") | |
| 360 |           } yield (replacement, descr)).take(options.int("completion_limit")).toList
 | |
| 361 | } | |
| 362 | } | |
| 363 |       catch { case ERROR(_) => Nil }
 | |
| 364 | } | |
| 365 | ||
| 366 | def is_wrapped(s: String): Boolean = | |
| 367 |       s.startsWith("\"") && s.endsWith("\"") ||
 | |
| 368 | s.startsWith(Symbol.open_decoded) && s.endsWith(Symbol.close_decoded) | |
| 369 | ||
| 370 |     for {
 | |
| 72842 
6aae62f55c2b
clarified markup: support more completion, e.g. within ROOTS;
 wenzelm parents: 
72729diff
changeset | 371 | Text.Info(r1, delimited) <- language_path(before_caret_range(caret)) | 
| 72856 | 372 | s1 <- get_text(r1) | 
| 72842 
6aae62f55c2b
clarified markup: support more completion, e.g. within ROOTS;
 wenzelm parents: 
72729diff
changeset | 373 | (r2, s2) <- | 
| 
6aae62f55c2b
clarified markup: support more completion, e.g. within ROOTS;
 wenzelm parents: 
72729diff
changeset | 374 |         if (is_wrapped(s1)) {
 | 
| 
6aae62f55c2b
clarified markup: support more completion, e.g. within ROOTS;
 wenzelm parents: 
72729diff
changeset | 375 | Some((Text.Range(r1.start + 1, r1.stop - 1), s1.substring(1, s1.length - 1))) | 
| 
6aae62f55c2b
clarified markup: support more completion, e.g. within ROOTS;
 wenzelm parents: 
72729diff
changeset | 376 | } | 
| 
6aae62f55c2b
clarified markup: support more completion, e.g. within ROOTS;
 wenzelm parents: 
72729diff
changeset | 377 | else if (delimited) Some((r1, s1)) | 
| 
6aae62f55c2b
clarified markup: support more completion, e.g. within ROOTS;
 wenzelm parents: 
72729diff
changeset | 378 | else None | 
| 66158 | 379 | if Path.is_valid(s2) | 
| 380 | paths = complete(s2) | |
| 381 | if paths.nonEmpty | |
| 382 | items = paths.map(p => Completion.Item(r2, s2, "", p._2, p._1, 0, false)) | |
| 383 | } yield Completion.Result(r2, s2, false, items) | |
| 384 | } | |
| 66053 | 385 | |
| 64877 | 386 | |
| 65139 | 387 | /* spell checker */ | 
| 388 | ||
| 76233 
f3b23f4eaaac
clarified signature, to support external tools like "isabelle narration";
 wenzelm parents: 
75958diff
changeset | 389 | lazy val spell_checker_include: Markup.Elements = | 
| 67395 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 390 |     Markup.Elements(space_explode(',', options.string("spell_checker_include")): _*)
 | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 391 | |
| 76233 
f3b23f4eaaac
clarified signature, to support external tools like "isabelle narration";
 wenzelm parents: 
75958diff
changeset | 392 | lazy val spell_checker_exclude: Markup.Elements = | 
| 
f3b23f4eaaac
clarified signature, to support external tools like "isabelle narration";
 wenzelm parents: 
75958diff
changeset | 393 |     Markup.Elements(space_explode(',', options.string("spell_checker_exclude")): _*)
 | 
| 
f3b23f4eaaac
clarified signature, to support external tools like "isabelle narration";
 wenzelm parents: 
75958diff
changeset | 394 | |
| 
f3b23f4eaaac
clarified signature, to support external tools like "isabelle narration";
 wenzelm parents: 
75958diff
changeset | 395 | lazy val spell_checker_elements: Markup.Elements = | 
| 
f3b23f4eaaac
clarified signature, to support external tools like "isabelle narration";
 wenzelm parents: 
75958diff
changeset | 396 | spell_checker_include ++ spell_checker_exclude | 
| 65139 | 397 | |
| 75393 | 398 |   def spell_checker(range: Text.Range): List[Text.Info[Text.Range]] = {
 | 
| 67395 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 399 | val result = | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 400 | snapshot.select(range, spell_checker_elements, _ => | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 401 |         {
 | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 402 | case info => | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 403 | Some( | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 404 | if (spell_checker_include(info.info.name)) | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 405 | Some(snapshot.convert(info.range)) | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 406 | else None) | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 407 | }) | 
| 78592 | 408 | for (case Text.Info(range, Some(range1)) <- result) | 
| 67395 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 409 | yield Text.Info(range, range1) | 
| 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 410 | } | 
| 65139 | 411 | |
| 412 | def spell_checker_point(range: Text.Range): Option[Text.Range] = | |
| 67395 
b39d596b77ce
more accurate spell-checking for nested quotations / antiquotations, notably in formal comments;
 wenzelm parents: 
67336diff
changeset | 413 | spell_checker(range).headOption.map(_.info) | 
| 65139 | 414 | |
| 415 | ||
| 65101 | 416 | /* text background */ | 
| 417 | ||
| 75393 | 418 | def background( | 
| 419 | elements: Markup.Elements, | |
| 420 | range: Text.Range, | |
| 421 | focus: Rendering.Focus | |
| 422 |   ) : List[Text.Info[Rendering.Color.Value]] = {
 | |
| 65101 | 423 |     for {
 | 
| 424 | Text.Info(r, result) <- | |
| 425 | snapshot.cumulate[(List[Markup], Option[Rendering.Color.Value])]( | |
| 72906 | 426 | range, (List(Markup.Empty), None), elements, | 
| 65101 | 427 | command_states => | 
| 428 |             {
 | |
| 72925 | 429 | case ((markups, color), Text.Info(_, XML.Elem(markup, _))) | 
| 68758 | 430 | if markups.nonEmpty && Document_Status.Command_Status.proper_elements(markup.name) => | 
| 65101 | 431 | Some((markup :: markups, color)) | 
| 432 | case (_, Text.Info(_, XML.Elem(Markup(Markup.BAD, _), _))) => | |
| 433 | Some((Nil, Some(Rendering.Color.bad))) | |
| 434 | case (_, Text.Info(_, XML.Elem(Markup(Markup.INTENSIFY, _), _))) => | |
| 435 | Some((Nil, Some(Rendering.Color.intensify))) | |
| 72929 | 436 | case (_, Text.Info(_, XML.Elem(Markup.Entity.Occ(i), _))) if focus(i) => | 
| 72903 | 437 | Some((Nil, Some(Rendering.Color.entity))) | 
| 67322 | 438 | case (_, Text.Info(_, XML.Elem(Markup.Markdown_Bullet(depth), _))) => | 
| 65101 | 439 | val color = | 
| 65150 | 440 |                   depth % 4 match {
 | 
| 67322 | 441 | case 1 => Rendering.Color.markdown_bullet1 | 
| 442 | case 2 => Rendering.Color.markdown_bullet2 | |
| 443 | case 3 => Rendering.Color.markdown_bullet3 | |
| 444 | case _ => Rendering.Color.markdown_bullet4 | |
| 65101 | 445 | } | 
| 446 | Some((Nil, Some(color))) | |
| 72907 | 447 | case (_, Text.Info(_, Protocol.Dialog(_, serial, result))) => | 
| 65101 | 448 | command_states.collectFirst( | 
| 449 |                   { case st if st.results.defined(serial) => st.results.get(serial).get }) match
 | |
| 450 |                 {
 | |
| 451 | case Some(Protocol.Dialog_Result(res)) if res == result => | |
| 452 | Some((Nil, Some(Rendering.Color.active_result))) | |
| 453 | case _ => | |
| 454 | Some((Nil, Some(Rendering.Color.active))) | |
| 455 | } | |
| 456 | case (_, Text.Info(_, elem)) => | |
| 457 | if (Rendering.active_elements(elem.name)) | |
| 458 | Some((Nil, Some(Rendering.Color.active))) | |
| 459 | else None | |
| 460 | }) | |
| 461 | color <- | |
| 72925 | 462 |         result match {
 | 
| 65101 | 463 | case (markups, opt_color) if markups.nonEmpty => | 
| 68758 | 464 | val status = Document_Status.Command_Status.make(markups.iterator) | 
| 65101 | 465 | if (status.is_unprocessed) Some(Rendering.Color.unprocessed1) | 
| 466 | else if (status.is_running) Some(Rendering.Color.running1) | |
| 68871 
f5c76072db55
more explicit status for "canceled" command within theory node;
 wenzelm parents: 
68822diff
changeset | 467 | else if (status.is_canceled) Some(Rendering.Color.canceled) | 
| 65101 | 468 | else opt_color | 
| 469 | case (_, opt_color) => opt_color | |
| 72925 | 470 | } | 
| 65101 | 471 | } yield Text.Info(r, color) | 
| 472 | } | |
| 473 | ||
| 474 | ||
| 475 | /* text foreground */ | |
| 476 | ||
| 477 | def foreground(range: Text.Range): List[Text.Info[Rendering.Color.Value]] = | |
| 478 | snapshot.select(range, Rendering.foreground_elements, _ => | |
| 479 |       {
 | |
| 66074 | 480 | case info => Some(Rendering.foreground(info.info.name)) | 
| 65101 | 481 | }) | 
| 482 | ||
| 483 | ||
| 72904 | 484 | /* entity focus */ | 
| 64767 | 485 | |
| 72904 | 486 | def entity_focus_defs(range: Text.Range): Rendering.Focus = | 
| 72905 | 487 | Rendering.Focus.make( | 
| 488 | snapshot.cumulate(range, Rendering.Focus.empty, Rendering.entity_elements, _ => | |
| 72904 | 489 |         {
 | 
| 490 | case (focus, Text.Info(_, XML.Elem(Markup.Entity.Def(i), _))) => Some(focus + i) | |
| 491 | case _ => None | |
| 72905 | 492 | })) | 
| 72904 | 493 | |
| 72927 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 494 | def entity_focus(range: Text.Range, defs_focus: Rendering.Focus): Rendering.Focus = | 
| 72905 | 495 | Rendering.Focus.make( | 
| 496 | snapshot.cumulate(range, Rendering.Focus.empty, Rendering.entity_elements, _ => | |
| 72904 | 497 |         {
 | 
| 498 | case (focus, Text.Info(_, XML.Elem(Markup.Entity.Ref(i), _))) | |
| 72927 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 499 | if defs_focus(i) => Some(focus + i) | 
| 72904 | 500 | case _ => None | 
| 72905 | 501 | })) | 
| 72904 | 502 | |
| 503 | ||
| 504 | /* caret focus */ | |
| 64767 | 505 | |
| 75393 | 506 |   def caret_focus(caret_range: Text.Range, defs_range: Text.Range): Rendering.Focus = {
 | 
| 72904 | 507 | val focus = entity_focus_defs(caret_range) | 
| 508 | if (focus.defined) focus | |
| 72927 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 509 | else if (defs_range == Text.Range.offside) Rendering.Focus.empty | 
| 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 510 |     else {
 | 
| 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 511 | val defs_focus = | 
| 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 512 | if (defs_range == Text.Range.full) Rendering.Focus.full | 
| 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 513 | else entity_focus_defs(defs_range) | 
| 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 514 | entity_focus(caret_range, defs_focus) | 
| 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 515 | } | 
| 64767 | 516 | } | 
| 517 | ||
| 75393 | 518 |   def caret_focus_ranges(caret_range: Text.Range, defs_range: Text.Range): List[Text.Range] = {
 | 
| 72927 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 519 | val focus = caret_focus(caret_range, defs_range) | 
| 72926 | 520 |     if (focus.defined) {
 | 
| 72927 
69f768aff611
clarified caret focus modifier, depending on option "jedit_focus_modifier";
 wenzelm parents: 
72926diff
changeset | 521 | snapshot.cumulate[Boolean](defs_range, false, Rendering.entity_elements, _ => | 
| 72904 | 522 |         {
 | 
| 72929 | 523 | case (_, Text.Info(_, XML.Elem(Markup.Entity.Occ(i), _))) if focus(i) => Some(true) | 
| 72904 | 524 | case _ => None | 
| 525 | }).flatMap(info => if (info.info) Some(info.range) else None) | |
| 64767 | 526 | } | 
| 527 | else Nil | |
| 528 | } | |
| 65121 | 529 | |
| 530 | ||
| 72858 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 531 | /* messages */ | 
| 65121 | 532 | |
| 75393 | 533 | def message_underline_color( | 
| 534 | elements: Markup.Elements, | |
| 535 | range: Text.Range | |
| 536 |   ) : List[Text.Info[Rendering.Color.Value]] = {
 | |
| 65121 | 537 | val results = | 
| 538 | snapshot.cumulate[Int](range, 0, elements, _ => | |
| 539 |         {
 | |
| 540 | case (pri, Text.Info(_, elem)) => Some(pri max Rendering.message_pri(elem.name)) | |
| 541 | }) | |
| 542 |     for {
 | |
| 543 | Text.Info(r, pri) <- results | |
| 544 | color <- Rendering.message_underline_color.get(pri) | |
| 545 | } yield Text.Info(r, color) | |
| 546 | } | |
| 65149 | 547 | |
| 75393 | 548 |   def text_messages(range: Text.Range): List[Text.Info[XML.Elem]] = {
 | 
| 72858 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 549 | val results = | 
| 72872 | 550 | snapshot.cumulate[Vector[Command.Results.Entry]]( | 
| 551 | range, Vector.empty, Rendering.message_elements, command_states => | |
| 72858 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 552 |           {
 | 
| 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 553 | case (res, Text.Info(_, elem)) => | 
| 72872 | 554 | Command.State.get_result_proper(command_states, elem.markup.properties) | 
| 555 | .map(res :+ _) | |
| 72858 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 556 | }) | 
| 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 557 | |
| 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 558 | var seen_serials = Set.empty[Long] | 
| 75393 | 559 |     def seen(i: Long): Boolean = {
 | 
| 72872 | 560 | val b = seen_serials(i) | 
| 561 | seen_serials += i | |
| 562 | b | |
| 563 | } | |
| 72858 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 564 |     for {
 | 
| 72872 | 565 | Text.Info(range, entries) <- results | 
| 566 | (i, elem) <- entries if !seen(i) | |
| 72869 | 567 | } yield Text.Info(range, elem) | 
| 72858 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 568 | } | 
| 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72856diff
changeset | 569 | |
| 65149 | 570 | |
| 571 | /* tooltips */ | |
| 572 | ||
| 69899 | 573 | def timing_threshold: Double = 0.0 | 
| 65149 | 574 | |
| 575 | private sealed case class Tooltip_Info( | |
| 576 | range: Text.Range, | |
| 577 | timing: Timing = Timing.zero, | |
| 72869 | 578 | messages: List[(Long, XML.Tree)] = Nil, | 
| 75393 | 579 | rev_infos: List[(Boolean, XML.Tree)] = Nil | 
| 580 |   ) {
 | |
| 65149 | 581 | def + (t: Timing): Tooltip_Info = copy(timing = timing + t) | 
| 75393 | 582 |     def + (r0: Text.Range, serial: Long, tree: XML.Tree): Tooltip_Info = {
 | 
| 65149 | 583 | val r = snapshot.convert(r0) | 
| 584 | if (range == r) copy(messages = (serial -> tree) :: messages) | |
| 585 | else copy(range = r, messages = List(serial -> tree)) | |
| 586 | } | |
| 75393 | 587 |     def + (r0: Text.Range, important: Boolean, tree: XML.Tree): Tooltip_Info = {
 | 
| 65149 | 588 | val r = snapshot.convert(r0) | 
| 589 | if (range == r) copy(rev_infos = (important -> tree) :: rev_infos) | |
| 590 | else copy (range = r, rev_infos = List(important -> tree)) | |
| 591 | } | |
| 67933 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 592 | |
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 593 | def timing_info(tree: XML.Tree): Option[XML.Tree] = | 
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 594 |       tree match {
 | 
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 595 | case XML.Elem(Markup(Markup.TIMING, _), _) => | 
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 596 | if (timing.elapsed.seconds >= timing_threshold) Some(XML.Text(timing.message)) else None | 
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 597 | case _ => Some(tree) | 
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 598 | } | 
| 65149 | 599 | def infos(important: Boolean): List[XML.Tree] = | 
| 67933 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 600 |       for {
 | 
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 601 | (is_important, tree) <- rev_infos.reverse if is_important == important | 
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 602 | tree1 <- timing_info(tree) | 
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 603 | } yield tree1 | 
| 65149 | 604 | } | 
| 605 | ||
| 65488 | 606 | def perhaps_append_file(node_name: Document.Node.Name, name: String): String = | 
| 76858 | 607 | if (Path.is_valid(name)) session.resources.append_path(node_name.master_dir, Path.explode(name)) | 
| 76663 | 608 | else name | 
| 65487 | 609 | |
| 75393 | 610 |   def tooltips(elements: Markup.Elements, range: Text.Range): Option[Text.Info[List[XML.Tree]]] = {
 | 
| 65149 | 611 | val results = | 
| 67824 
661cd25304ae
more compact markup tree: output messages are already stored in command results (e.g. relevant for  XML data representation);
 wenzelm parents: 
67395diff
changeset | 612 | snapshot.cumulate[Tooltip_Info](range, Tooltip_Info(range), elements, command_states => | 
| 65149 | 613 |         {
 | 
| 614 | case (info, Text.Info(_, XML.Elem(Markup.Timing(t), _))) => Some(info + t) | |
| 615 | ||
| 67824 
661cd25304ae
more compact markup tree: output messages are already stored in command results (e.g. relevant for  XML data representation);
 wenzelm parents: 
67395diff
changeset | 616 | case (info, Text.Info(r0, msg @ XML.Elem(Markup(Markup.BAD, Markup.Serial(i)), body))) | 
| 
661cd25304ae
more compact markup tree: output messages are already stored in command results (e.g. relevant for  XML data representation);
 wenzelm parents: 
67395diff
changeset | 617 | if body.nonEmpty => Some(info + (r0, i, msg)) | 
| 
661cd25304ae
more compact markup tree: output messages are already stored in command results (e.g. relevant for  XML data representation);
 wenzelm parents: 
67395diff
changeset | 618 | |
| 
661cd25304ae
more compact markup tree: output messages are already stored in command results (e.g. relevant for  XML data representation);
 wenzelm parents: 
67395diff
changeset | 619 | case (info, Text.Info(r0, XML.Elem(Markup(name, props), _))) | 
| 
661cd25304ae
more compact markup tree: output messages are already stored in command results (e.g. relevant for  XML data representation);
 wenzelm parents: 
67395diff
changeset | 620 | if Rendering.tooltip_message_elements(name) => | 
| 
661cd25304ae
more compact markup tree: output messages are already stored in command results (e.g. relevant for  XML data representation);
 wenzelm parents: 
67395diff
changeset | 621 | for ((i, tree) <- Command.State.get_result_proper(command_states, props)) | 
| 
661cd25304ae
more compact markup tree: output messages are already stored in command results (e.g. relevant for  XML data representation);
 wenzelm parents: 
67395diff
changeset | 622 | yield (info + (r0, i, tree)) | 
| 65149 | 623 | |
| 624 | case (info, Text.Info(r0, XML.Elem(Markup.Entity(kind, name), _))) | |
| 625 | if kind != "" && kind != Markup.ML_DEF => | |
| 626 |             val kind1 = Word.implode(Word.explode('_', kind))
 | |
| 627 | val txt1 = | |
| 628 | if (name == "") kind1 | |
| 629 | else if (kind1 == "") quote(name) | |
| 630 | else kind1 + " " + quote(name) | |
| 67933 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 631 | val info1 = info + (r0, true, XML.Text(txt1)) | 
| 
604da273e18d
more robust timing info: do not rely on order of markup;
 wenzelm parents: 
67824diff
changeset | 632 | Some(if (kind == Markup.COMMAND) info1 + (r0, true, XML.elem(Markup.TIMING)) else info1) | 
| 65149 | 633 | |
| 634 | case (info, Text.Info(r0, XML.Elem(Markup.Path(name), _))) => | |
| 65488 | 635 | val file = perhaps_append_file(snapshot.node_name, name) | 
| 65149 | 636 | val text = | 
| 637 | if (name == file) "file " + quote(file) | |
| 638 | else "path " + quote(name) + "\nfile " + quote(file) | |
| 639 | Some(info + (r0, true, XML.Text(text))) | |
| 640 | ||
| 641 | case (info, Text.Info(r0, XML.Elem(Markup.Doc(name), _))) => | |
| 642 | val text = "doc " + quote(name) | |
| 643 | Some(info + (r0, true, XML.Text(text))) | |
| 644 | ||
| 645 | case (info, Text.Info(r0, XML.Elem(Markup.Url(name), _))) => | |
| 646 |             Some(info + (r0, true, XML.Text("URL " + quote(name))))
 | |
| 647 | ||
| 648 | case (info, Text.Info(r0, XML.Elem(Markup(name, _), body))) | |
| 649 | if name == Markup.SORTING || name == Markup.TYPING => | |
| 650 |             Some(info + (r0, true, Pretty.block(XML.Text("::") :: Pretty.brk(1) :: body)))
 | |
| 651 | ||
| 652 | case (info, Text.Info(r0, XML.Elem(Markup(Markup.CLASS_PARAMETER, _), body))) => | |
| 75958 | 653 | Some(info + (r0, true, Pretty.block(body, indent = 0))) | 
| 65149 | 654 | |
| 655 | case (info, Text.Info(r0, XML.Elem(Markup(Markup.ML_TYPING, _), body))) => | |
| 656 |             Some(info + (r0, false, Pretty.block(XML.Text("ML:") :: Pretty.brk(1) :: body)))
 | |
| 657 | ||
| 658 | case (info, Text.Info(r0, Protocol.ML_Breakpoint(breakpoint))) => | |
| 65222 
fb8253564483
more robust debugger initialization, e.g. required for GUI components before actual session startup;
 wenzelm parents: 
65213diff
changeset | 659 | val text = | 
| 
fb8253564483
more robust debugger initialization, e.g. required for GUI components before actual session startup;
 wenzelm parents: 
65213diff
changeset | 660 | if (session.debugger.breakpoint_state(breakpoint)) "breakpoint (enabled)" | 
| 
fb8253564483
more robust debugger initialization, e.g. required for GUI components before actual session startup;
 wenzelm parents: 
65213diff
changeset | 661 | else "breakpoint (disabled)" | 
| 
fb8253564483
more robust debugger initialization, e.g. required for GUI components before actual session startup;
 wenzelm parents: 
65213diff
changeset | 662 | Some(info + (r0, true, XML.Text(text))) | 
| 76965 | 663 | case (info, Text.Info(r0, XML.Elem(Markup.Language(lang), _))) => | 
| 664 |             Some(info + (r0, true, XML.Text("language: " + lang.description)))
 | |
| 65149 | 665 | |
| 666 | case (info, Text.Info(r0, XML.Elem(Markup.Expression(kind), _))) => | |
| 667 | val descr = if (kind == "") "expression" else "expression: " + kind | |
| 668 | Some(info + (r0, true, XML.Text(descr))) | |
| 669 | ||
| 670 | case (info, Text.Info(r0, XML.Elem(Markup(Markup.MARKDOWN_PARAGRAPH, _), _))) => | |
| 671 |             Some(info + (r0, true, XML.Text("Markdown: paragraph")))
 | |
| 67323 
d02208cefbdb
PIDE markup for Markdown items (which may consist of multiple paragraphs or lists);
 wenzelm parents: 
67322diff
changeset | 672 | case (info, Text.Info(r0, XML.Elem(Markup(Markup.MARKDOWN_ITEM, _), _))) => | 
| 
d02208cefbdb
PIDE markup for Markdown items (which may consist of multiple paragraphs or lists);
 wenzelm parents: 
67322diff
changeset | 673 |             Some(info + (r0, true, XML.Text("Markdown: item")))
 | 
| 65149 | 674 | case (info, Text.Info(r0, XML.Elem(Markup.Markdown_List(kind), _))) => | 
| 675 |             Some(info + (r0, true, XML.Text("Markdown: " + kind)))
 | |
| 676 | ||
| 677 | case (info, Text.Info(r0, XML.Elem(Markup(name, _), _))) => | |
| 678 | Rendering.tooltip_descriptions.get(name).map(desc => info + (r0, true, XML.Text(desc))) | |
| 679 | }).map(_.info) | |
| 680 | ||
| 681 | if (results.isEmpty) None | |
| 682 |     else {
 | |
| 683 | val r = Text.Range(results.head.range.start, results.last.range.stop) | |
| 684 | val all_tips = | |
| 73359 | 685 | results.flatMap(_.messages).foldLeft(SortedMap.empty[Long, XML.Tree])(_ + _) | 
| 72869 | 686 | .iterator.map(_._2).toList ::: | 
| 65149 | 687 | results.flatMap(res => res.infos(true)) ::: | 
| 688 | results.flatMap(res => res.infos(false)).lastOption.toList | |
| 689 | if (all_tips.isEmpty) None else Some(Text.Info(r, all_tips)) | |
| 690 | } | |
| 691 | } | |
| 65911 | 692 | |
| 693 | ||
| 71499 | 694 | /* messages */ | 
| 695 | ||
| 696 | def warnings(range: Text.Range): List[Text.Markup] = | |
| 697 | snapshot.select(range, Rendering.warning_elements, _ => Some(_)).map(_.info) | |
| 698 | ||
| 699 | def errors(range: Text.Range): List[Text.Markup] = | |
| 700 | snapshot.select(range, Rendering.error_elements, _ => Some(_)).map(_.info) | |
| 701 | ||
| 702 | ||
| 65911 | 703 | /* command status overview */ | 
| 704 | ||
| 75393 | 705 |   def overview_color(range: Text.Range): Option[Rendering.Color.Value] = {
 | 
| 65911 | 706 | if (snapshot.is_outdated) None | 
| 707 |     else {
 | |
| 708 | val results = | |
| 68758 | 709 | snapshot.cumulate[List[Markup]](range, Nil, Document_Status.Command_Status.liberal_elements, | 
| 710 | _ => | |
| 711 |             {
 | |
| 712 | case (status, Text.Info(_, elem)) => Some(elem.markup :: status) | |
| 713 | }, status = true) | |
| 65911 | 714 | if (results.isEmpty) None | 
| 715 |       else {
 | |
| 68758 | 716 | val status = Document_Status.Command_Status.make(results.iterator.flatMap(_.info)) | 
| 65911 | 717 | |
| 718 | if (status.is_running) Some(Rendering.Color.running) | |
| 719 | else if (status.is_failed) Some(Rendering.Color.error) | |
| 720 | else if (status.is_warned) Some(Rendering.Color.warning) | |
| 721 | else if (status.is_unprocessed) Some(Rendering.Color.unprocessed) | |
| 722 | else None | |
| 723 | } | |
| 724 | } | |
| 725 | } | |
| 67132 | 726 | |
| 727 | ||
| 728 | /* antiquoted text */ | |
| 729 | ||
| 730 | def antiquoted(range: Text.Range): Option[Text.Range] = | |
| 731 | snapshot.cumulate[Option[Text.Range]](range, None, Rendering.antiquoted_elements, _ => | |
| 732 |       {
 | |
| 733 | case (res, info) => if (res.isEmpty) Some(Some(info.range)) else None | |
| 734 | }).headOption.flatMap(_.info) | |
| 69900 | 735 | |
| 736 | ||
| 737 | /* meta data */ | |
| 738 | ||
| 75393 | 739 |   def meta_data(range: Text.Range): Properties.T = {
 | 
| 69900 | 740 | val results = | 
| 741 | snapshot.cumulate[Properties.T](range, Nil, Rendering.meta_data_elements, _ => | |
| 742 |         {
 | |
| 743 | case (res, Text.Info(_, elem)) => | |
| 744 | val plain_text = XML.content(elem) | |
| 745 | Some((elem.name -> plain_text) :: res) | |
| 746 | }) | |
| 747 | Library.distinct(results.flatMap(_.info.reverse)) | |
| 748 | } | |
| 70135 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 749 | |
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 750 | |
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 751 | /* document tags */ | 
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 752 | |
| 75393 | 753 |   def document_tags(range: Text.Range): List[String] = {
 | 
| 70135 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 754 | val results = | 
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 755 | snapshot.cumulate[List[String]](range, Nil, Rendering.document_tag_elements, _ => | 
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 756 |         {
 | 
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 757 | case (res, Text.Info(_, XML.Elem(Markup.Document_Tag(name), _))) => Some(name :: res) | 
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 758 | case _ => None | 
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 759 | }) | 
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 760 | Library.distinct(results.flatMap(_.info.reverse)) | 
| 
ad6d4a14adb5
report document tags as seen in the text (not the active tag of Thy_Output.present_thy);
 wenzelm parents: 
69970diff
changeset | 761 | } | 
| 64622 
529bbb8977c7
more uniform rendering for Isabelle/jEdit and Isabelle/VSCode;
 wenzelm parents: diff
changeset | 762 | } |