1 /* Title: Pure/PIDE/isar_document.scala
4 Protocol message formats for interactive Isar documents.
12 /* document editing */
15 def unapply(msg: XML.Tree)
16 : Option[(Document.Version_ID, List[(Document.Command_ID, Document.Exec_ID)])] =
18 case XML.Elem(Markup(Markup.ASSIGN, List((Markup.VERSION, Document.ID(id)))), edits) =>
19 val id_edits = edits.map(Edit.unapply)
20 if (id_edits.forall(_.isDefined)) Some((id, id_edits.map(_.get)))
27 def unapply(msg: XML.Tree): Option[(Document.Command_ID, Document.Exec_ID)] =
31 List((Markup.ID, Document.ID(i)), (Markup.EXEC, Document.ID(j)))), Nil) => Some((i, j))
37 /* toplevel transactions */
39 sealed abstract class Status
40 case class Forked(forks: Int) extends Status
41 case object Unprocessed extends Status
42 case object Finished extends Status
43 case object Failed extends Status
45 def command_status(markup: List[Markup]): Status =
47 val forks = (0 /: markup) {
48 case (i, Markup(Markup.FORKED, _)) => i + 1
49 case (i, Markup(Markup.JOINED, _)) => i - 1
52 if (forks != 0) Forked(forks)
53 else if (markup.exists(_.name == Markup.FAILED)) Failed
54 else if (markup.exists(_.name == Markup.FINISHED)) Finished
61 def clean_message(body: XML.Body): XML.Body =
62 body filter { case XML.Elem(Markup(Markup.NO_REPORT, _), _) => false case _ => true } map
63 { case XML.Elem(markup, ts) => XML.Elem(markup, clean_message(ts)) case t => t }
65 def message_reports(msg: XML.Tree): List[XML.Elem] =
67 case elem @ XML.Elem(Markup(Markup.REPORT, _), _) => List(elem)
68 case XML.Elem(_, body) => body.flatMap(message_reports)
69 case XML.Text(_) => Nil
73 /* specific messages */
75 def is_ready(msg: XML.Tree): Boolean =
77 case XML.Elem(Markup(Markup.STATUS, _),
78 List(XML.Elem(Markup(Markup.READY, _), _))) => true
82 def is_tracing(msg: XML.Tree): Boolean =
84 case XML.Elem(Markup(Markup.TRACING, _), _) => true
88 def is_warning(msg: XML.Tree): Boolean =
90 case XML.Elem(Markup(Markup.WARNING, _), _) => true
94 def is_error(msg: XML.Tree): Boolean =
96 case XML.Elem(Markup(Markup.ERROR, _), _) => true
100 def is_state(msg: XML.Tree): Boolean =
102 case XML.Elem(Markup(Markup.WRITELN, _),
103 List(XML.Elem(Markup(Markup.STATE, _), _))) => true
108 /* reported positions */
110 private val include_pos =
111 Set(Markup.BINDING, Markup.ENTITY, Markup.REPORT, Markup.POSITION)
113 def message_positions(command: Command, message: XML.Elem): Set[Text.Range] =
115 def positions(set: Set[Text.Range], tree: XML.Tree): Set[Text.Range] =
117 case XML.Elem(Markup(name, Position.Id_Range(id, raw_range)), body)
118 if include_pos(name) && id == command.id =>
119 val range = command.decode(raw_range).restrict(command.range)
120 body.foldLeft(if (range.is_singularity) set else set + range)(positions)
121 case XML.Elem(Markup(name, _), body) => body.foldLeft(set)(positions)
124 val set = positions(Set.empty, message)
125 if (set.isEmpty && !is_state(message))
126 set ++ Position.Range.unapply(message.markup.properties).map(command.decode(_))
132 trait Isar_Document extends Isabelle_Process
136 def define_command(id: Document.Command_ID, text: String): Unit =
137 input("Isar_Document.define_command", Document.ID(id), text)
140 /* document versions */
142 def edit_version(old_id: Document.Version_ID, new_id: Document.Version_ID,
143 edits: List[Document.Edit_Command_ID])
146 { import XML.Encode._
147 def encode: T[List[Document.Edit_Command_ID]] =
150 { case Document.Node.Remove() => (Nil, Nil) },
151 { case Document.Node.Edits(a) => (Nil, list(pair(option(long), option(long)))(a)) },
152 { case Document.Node.Update_Header(
153 Document.Node.Header(_, Exn.Res(Thy_Header.Header(a, b, c)))) =>
154 (Nil, triple(string, list(string), list(string))(a, b, c)) },
155 { case Document.Node.Update_Header(
156 Document.Node.Header(_, Exn.Exn(e))) => (List(Exn.message(e)), Nil) }))))
157 YXML.string_of_body(encode(edits)) }
159 input("Isar_Document.edit_version", Document.ID(old_id), Document.ID(new_id), edits_yxml)
163 /* method invocation service */
165 def invoke_scala(id: String, tag: Invoke_Scala.Tag.Value, res: String)
167 input("Isar_Document.invoke_scala", id, tag.toString, res)