| author | wenzelm | 
| Sun, 24 May 2020 10:36:42 +0200 | |
| changeset 71875 | aaa984499d36 | 
| parent 71631 | 3f02bc5a5a03 | 
| child 72692 | 22aeec526ffd | 
| permissions | -rw-r--r-- | 
| 59713 | 1 | /* Title: Pure/PIDE/protocol_message.scala | 
| 2 | Author: Makarius | |
| 3 | ||
| 4 | Auxiliary operations on protocol messages. | |
| 5 | */ | |
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 10 | object Protocol_Message | |
| 11 | {
 | |
| 71620 | 12 | /* message markers */ | 
| 13 | ||
| 14 | object Marker | |
| 15 |   {
 | |
| 16 | def apply(a: String): Marker = | |
| 17 |       new Marker { override def name: String = a }
 | |
| 71623 
b3bddebe44ca
clarified signature: more explicit type Protocol_Message.Marker;
 wenzelm parents: 
71620diff
changeset | 18 | |
| 
b3bddebe44ca
clarified signature: more explicit type Protocol_Message.Marker;
 wenzelm parents: 
71620diff
changeset | 19 |     def test(line: String): Boolean = line.startsWith("\f")
 | 
| 71620 | 20 | } | 
| 21 | ||
| 22 | abstract class Marker private | |
| 23 |   {
 | |
| 24 | def name: String | |
| 25 | val prefix: String = "\f" + name + " = " | |
| 26 | ||
| 27 | def apply(text: String): String = prefix + Library.encode_lines(text) | |
| 28 | def apply(props: Properties.T): String = apply(YXML.string_of_body(XML.Encode.properties(props))) | |
| 29 | ||
| 30 | def test(line: String): Boolean = line.startsWith(prefix) | |
| 31 | def test_yxml(line: String): Boolean = test(line) && YXML.detect(line) | |
| 32 | ||
| 33 | def unapply(line: String): Option[String] = | |
| 34 | Library.try_unprefix(prefix, line).map(Library.decode_lines) | |
| 35 | ||
| 36 |     override def toString: String = "Marker(" + quote(name) + ")"
 | |
| 37 | } | |
| 38 | ||
| 39 | ||
| 59713 | 40 | /* inlined reports */ | 
| 41 | ||
| 42 | private val report_elements = | |
| 43 | Markup.Elements(Markup.REPORT, Markup.NO_REPORT) | |
| 44 | ||
| 45 | def clean_reports(body: XML.Body): XML.Body = | |
| 46 |     body filter {
 | |
| 47 | case XML.Wrapped_Elem(Markup(name, _), _, _) => !report_elements(name) | |
| 48 | case XML.Elem(Markup(name, _), _) => !report_elements(name) | |
| 49 | case _ => true | |
| 50 |     } map {
 | |
| 51 | case XML.Wrapped_Elem(markup, body, ts) => XML.Wrapped_Elem(markup, body, clean_reports(ts)) | |
| 52 | case XML.Elem(markup, ts) => XML.Elem(markup, clean_reports(ts)) | |
| 53 | case t => t | |
| 54 | } | |
| 55 | ||
| 71631 | 56 | def expose_no_reports(body: XML.Body): XML.Body = | 
| 57 |     body flatMap {
 | |
| 58 | case XML.Wrapped_Elem(markup, body, ts) => List(XML.Wrapped_Elem(markup, body, expose_no_reports(ts))) | |
| 59 | case XML.Elem(Markup(Markup.NO_REPORT, _), ts) => ts | |
| 60 | case XML.Elem(markup, ts) => List(XML.Elem(markup, expose_no_reports(ts))) | |
| 61 | case t => List(t) | |
| 62 | } | |
| 63 | ||
| 59713 | 64 | def reports(props: Properties.T, body: XML.Body): List[XML.Elem] = | 
| 65 |     body flatMap {
 | |
| 66 | case XML.Wrapped_Elem(Markup(Markup.REPORT, ps), body, ts) => | |
| 67 | List(XML.Wrapped_Elem(Markup(Markup.REPORT, props ::: ps), body, ts)) | |
| 68 | case XML.Elem(Markup(Markup.REPORT, ps), ts) => | |
| 69 | List(XML.Elem(Markup(Markup.REPORT, props ::: ps), ts)) | |
| 70 | case XML.Wrapped_Elem(_, _, ts) => reports(props, ts) | |
| 71 | case XML.Elem(_, ts) => reports(props, ts) | |
| 72 | case XML.Text(_) => Nil | |
| 73 | } | |
| 74 | ||
| 75 | ||
| 76 | /* reported positions */ | |
| 77 | ||
| 78 | private val position_elements = | |
| 79 | Markup.Elements(Markup.BINDING, Markup.ENTITY, Markup.REPORT, Markup.POSITION) | |
| 80 | ||
| 81 | def positions( | |
| 82 | self_id: Document_ID.Generic => Boolean, | |
| 83 | command_position: Position.T, | |
| 84 | chunk_name: Symbol.Text_Chunk.Name, | |
| 85 | chunk: Symbol.Text_Chunk, | |
| 86 | message: XML.Elem): Set[Text.Range] = | |
| 87 |   {
 | |
| 88 | def elem(props: Properties.T, set: Set[Text.Range]): Set[Text.Range] = | |
| 89 |       props match {
 | |
| 90 | case Position.Identified(id, name) if self_id(id) && name == chunk_name => | |
| 91 | val opt_range = | |
| 92 |             Position.Range.unapply(props) orElse {
 | |
| 93 | if (name == Symbol.Text_Chunk.Default) | |
| 94 | Position.Range.unapply(command_position) | |
| 95 | else None | |
| 96 | } | |
| 97 |           opt_range match {
 | |
| 98 | case Some(symbol_range) => | |
| 99 |               chunk.incorporate(symbol_range) match {
 | |
| 100 | case Some(range) => set + range | |
| 101 | case _ => set | |
| 102 | } | |
| 103 | case None => set | |
| 104 | } | |
| 105 | case _ => set | |
| 106 | } | |
| 107 | def tree(set: Set[Text.Range], t: XML.Tree): Set[Text.Range] = | |
| 108 |       t match {
 | |
| 109 | case XML.Wrapped_Elem(Markup(name, props), _, body) => | |
| 110 | body.foldLeft(if (position_elements(name)) elem(props, set) else set)(tree) | |
| 111 | case XML.Elem(Markup(name, props), body) => | |
| 112 | body.foldLeft(if (position_elements(name)) elem(props, set) else set)(tree) | |
| 113 | case XML.Text(_) => set | |
| 114 | } | |
| 115 | ||
| 116 | val set = tree(Set.empty, message) | |
| 117 | if (set.isEmpty) elem(message.markup.properties, set) | |
| 118 | else set | |
| 119 | } | |
| 120 | } |