src/Pure/PIDE/protocol.scala
author wenzelm
Fri Mar 16 18:42:35 2018 +0100 (18 months ago)
changeset 67883 171e7735ce25
parent 67493 c4e9e0c50487
child 67915 d827728b74b3
permissions -rw-r--r--
support for "use_theories";
wenzelm@45709
     1
/*  Title:      Pure/PIDE/protocol.scala
wenzelm@38412
     2
    Author:     Makarius
wenzelm@38412
     3
wenzelm@45709
     4
Protocol message formats for interactive proof documents.
wenzelm@38412
     5
*/
wenzelm@38412
     6
wenzelm@38412
     7
package isabelle
wenzelm@38412
     8
wenzelm@38412
     9
wenzelm@45709
    10
object Protocol
wenzelm@38412
    11
{
wenzelm@38567
    12
  /* document editing */
wenzelm@38412
    13
wenzelm@52563
    14
  object Assign_Update
wenzelm@44476
    15
  {
wenzelm@52563
    16
    def unapply(text: String): Option[(Document_ID.Version, Document.Assign_Update)] =
wenzelm@44661
    17
      try {
wenzelm@44661
    18
        import XML.Decode._
wenzelm@65345
    19
        Some(pair(long, list(pair(long, list(long))))(Symbol.decode_yxml(text)))
wenzelm@44661
    20
      }
wenzelm@44661
    21
      catch {
wenzelm@44661
    22
        case ERROR(_) => None
wenzelm@51987
    23
        case _: XML.Error => None
wenzelm@38412
    24
      }
wenzelm@38412
    25
  }
wenzelm@38567
    26
wenzelm@44676
    27
  object Removed
wenzelm@44676
    28
  {
wenzelm@52530
    29
    def unapply(text: String): Option[List[Document_ID.Version]] =
wenzelm@44676
    30
      try {
wenzelm@44676
    31
        import XML.Decode._
wenzelm@65345
    32
        Some(list(long)(Symbol.decode_yxml(text)))
wenzelm@44676
    33
      }
wenzelm@44676
    34
      catch {
wenzelm@44676
    35
        case ERROR(_) => None
wenzelm@51987
    36
        case _: XML.Error => None
wenzelm@44676
    37
      }
wenzelm@44676
    38
  }
wenzelm@44676
    39
wenzelm@38567
    40
wenzelm@46209
    41
  /* command status */
wenzelm@38567
    42
wenzelm@56359
    43
  object Status
wenzelm@56359
    44
  {
wenzelm@56359
    45
    def make(markup_iterator: Iterator[Markup]): Status =
wenzelm@56359
    46
    {
wenzelm@56359
    47
      var touched = false
wenzelm@56359
    48
      var accepted = false
wenzelm@56395
    49
      var warned = false
wenzelm@56359
    50
      var failed = false
wenzelm@56359
    51
      var forks = 0
wenzelm@56359
    52
      var runs = 0
wenzelm@56359
    53
      for (markup <- markup_iterator) {
wenzelm@56359
    54
        markup.name match {
wenzelm@56359
    55
          case Markup.ACCEPTED => accepted = true
wenzelm@56359
    56
          case Markup.FORKED => touched = true; forks += 1
wenzelm@56359
    57
          case Markup.JOINED => forks -= 1
wenzelm@56359
    58
          case Markup.RUNNING => touched = true; runs += 1
wenzelm@56359
    59
          case Markup.FINISHED => runs -= 1
wenzelm@59203
    60
          case Markup.WARNING | Markup.LEGACY => warned = true
wenzelm@56395
    61
          case Markup.FAILED | Markup.ERROR => failed = true
wenzelm@56359
    62
          case _ =>
wenzelm@56359
    63
        }
wenzelm@56359
    64
      }
wenzelm@56395
    65
      Status(touched, accepted, warned, failed, forks, runs)
wenzelm@56359
    66
    }
wenzelm@56359
    67
wenzelm@56359
    68
    val empty = make(Iterator.empty)
wenzelm@56359
    69
wenzelm@56359
    70
    def merge(status_iterator: Iterator[Status]): Status =
wenzelm@56359
    71
      if (status_iterator.hasNext) {
wenzelm@56359
    72
        val status0 = status_iterator.next
wenzelm@56359
    73
        (status0 /: status_iterator)(_ + _)
wenzelm@56359
    74
      }
wenzelm@56359
    75
      else empty
wenzelm@56359
    76
  }
wenzelm@56359
    77
wenzelm@46166
    78
  sealed case class Status(
wenzelm@56352
    79
    private val touched: Boolean,
wenzelm@56352
    80
    private val accepted: Boolean,
wenzelm@56395
    81
    private val warned: Boolean,
wenzelm@56352
    82
    private val failed: Boolean,
wenzelm@56352
    83
    forks: Int,
wenzelm@56352
    84
    runs: Int)
wenzelm@38567
    85
  {
wenzelm@56359
    86
    def + (that: Status): Status =
wenzelm@56395
    87
      Status(
wenzelm@56395
    88
        touched || that.touched,
wenzelm@56395
    89
        accepted || that.accepted,
wenzelm@56395
    90
        warned || that.warned,
wenzelm@56395
    91
        failed || that.failed,
wenzelm@56395
    92
        forks + that.forks,
wenzelm@56395
    93
        runs + that.runs)
wenzelm@56359
    94
wenzelm@49036
    95
    def is_unprocessed: Boolean = accepted && !failed && (!touched || (forks != 0 && runs == 0))
wenzelm@49036
    96
    def is_running: Boolean = runs != 0
wenzelm@56474
    97
    def is_warned: Boolean = warned
wenzelm@56474
    98
    def is_failed: Boolean = failed
wenzelm@49039
    99
    def is_finished: Boolean = !failed && touched && forks == 0 && runs == 0
wenzelm@46166
   100
  }
wenzelm@46166
   101
wenzelm@56395
   102
  val proper_status_elements =
wenzelm@56743
   103
    Markup.Elements(Markup.ACCEPTED, Markup.FORKED, Markup.JOINED, Markup.RUNNING,
wenzelm@55646
   104
      Markup.FINISHED, Markup.FAILED)
wenzelm@55646
   105
wenzelm@56395
   106
  val liberal_status_elements =
wenzelm@59203
   107
    proper_status_elements + Markup.WARNING + Markup.LEGACY + Markup.ERROR
wenzelm@55646
   108
wenzelm@46209
   109
wenzelm@51818
   110
  /* command timing */
wenzelm@51818
   111
wenzelm@51818
   112
  object Command_Timing
wenzelm@51818
   113
  {
wenzelm@52531
   114
    def unapply(props: Properties.T): Option[(Document_ID.Generic, isabelle.Timing)] =
wenzelm@51818
   115
      props match {
wenzelm@66873
   116
        case Markup.COMMAND_TIMING :: args =>
wenzelm@51818
   117
          (args, args) match {
wenzelm@51818
   118
            case (Position.Id(id), Markup.Timing_Properties(timing)) => Some((id, timing))
wenzelm@51818
   119
            case _ => None
wenzelm@51818
   120
          }
wenzelm@51818
   121
        case _ => None
wenzelm@51818
   122
      }
wenzelm@51818
   123
  }
wenzelm@51818
   124
wenzelm@51818
   125
wenzelm@66873
   126
  /* theory timing */
wenzelm@66873
   127
wenzelm@66873
   128
  object Theory_Timing
wenzelm@66873
   129
  {
wenzelm@66873
   130
    def unapply(props: Properties.T): Option[(String, isabelle.Timing)] =
wenzelm@66873
   131
      props match {
wenzelm@66873
   132
        case Markup.THEORY_TIMING :: args =>
wenzelm@66873
   133
          (args, args) match {
wenzelm@66873
   134
            case (Markup.Name(name), Markup.Timing_Properties(timing)) => Some((name, timing))
wenzelm@66873
   135
            case _ => None
wenzelm@66873
   136
          }
wenzelm@66873
   137
        case _ => None
wenzelm@66873
   138
      }
wenzelm@66873
   139
  }
wenzelm@66873
   140
wenzelm@66873
   141
wenzelm@46209
   142
  /* node status */
wenzelm@46209
   143
wenzelm@46688
   144
  sealed case class Node_Status(
wenzelm@66410
   145
    unprocessed: Int, running: Int, warned: Int, failed: Int, finished: Int, consolidated: Boolean)
wenzelm@44866
   146
  {
wenzelm@56474
   147
    def total: Int = unprocessed + running + warned + failed + finished
wenzelm@66411
   148
    def ok: Boolean = failed == 0
wenzelm@67883
   149
wenzelm@67883
   150
    def json: JSON.Object.T =
wenzelm@67883
   151
      JSON.Object("unprocessed" -> unprocessed, "running" -> running, "warned" -> warned,
wenzelm@67883
   152
        "failed" -> failed, "finished" -> finished, "consolidated" -> consolidated,
wenzelm@67883
   153
        "total" -> total, "ok" -> ok)
wenzelm@44866
   154
  }
wenzelm@44613
   155
wenzelm@44613
   156
  def node_status(
wenzelm@66410
   157
    state: Document.State,
wenzelm@66410
   158
    version: Document.Version,
wenzelm@66410
   159
    name: Document.Node.Name,
wenzelm@66410
   160
    node: Document.Node): Node_Status =
wenzelm@44613
   161
  {
wenzelm@44613
   162
    var unprocessed = 0
wenzelm@44613
   163
    var running = 0
wenzelm@46688
   164
    var warned = 0
wenzelm@44613
   165
    var failed = 0
wenzelm@56474
   166
    var finished = 0
wenzelm@56356
   167
    for (command <- node.commands.iterator) {
wenzelm@56355
   168
      val states = state.command_states(version, command)
wenzelm@56359
   169
      val status = Status.merge(states.iterator.map(_.protocol_status))
wenzelm@56355
   170
wenzelm@56299
   171
      if (status.is_running) running += 1
wenzelm@57843
   172
      else if (status.is_failed) failed += 1
wenzelm@56395
   173
      else if (status.is_warned) warned += 1
wenzelm@56395
   174
      else if (status.is_finished) finished += 1
wenzelm@56299
   175
      else unprocessed += 1
wenzelm@56299
   176
    }
wenzelm@66410
   177
    val consolidated = state.node_consolidated(version, name)
wenzelm@66410
   178
wenzelm@66410
   179
    Node_Status(unprocessed, running, warned, failed, finished, consolidated)
wenzelm@44613
   180
  }
wenzelm@44613
   181
wenzelm@38887
   182
wenzelm@51533
   183
  /* node timing */
wenzelm@51533
   184
wenzelm@51533
   185
  sealed case class Node_Timing(total: Double, commands: Map[Command, Double])
wenzelm@51533
   186
wenzelm@51533
   187
  val empty_node_timing = Node_Timing(0.0, Map.empty)
wenzelm@51533
   188
wenzelm@51533
   189
  def node_timing(
wenzelm@51533
   190
    state: Document.State,
wenzelm@51533
   191
    version: Document.Version,
wenzelm@51533
   192
    node: Document.Node,
wenzelm@51533
   193
    threshold: Double): Node_Timing =
wenzelm@51533
   194
  {
wenzelm@51533
   195
    var total = 0.0
wenzelm@51533
   196
    var commands = Map.empty[Command, Double]
wenzelm@51533
   197
    for {
wenzelm@51533
   198
      command <- node.commands.iterator
wenzelm@56299
   199
      st <- state.command_states(version, command)
wenzelm@56356
   200
    } {
wenzelm@56356
   201
      val command_timing =
wenzelm@51533
   202
        (0.0 /: st.status)({
wenzelm@51533
   203
          case (timing, Markup.Timing(t)) => timing + t.elapsed.seconds
wenzelm@51533
   204
          case (timing, _) => timing
wenzelm@51533
   205
        })
wenzelm@51533
   206
      total += command_timing
wenzelm@51533
   207
      if (command_timing >= threshold) commands += (command -> command_timing)
wenzelm@51533
   208
    }
wenzelm@51533
   209
    Node_Timing(total, commands)
wenzelm@51533
   210
  }
wenzelm@51533
   211
wenzelm@51533
   212
wenzelm@39441
   213
  /* result messages */
wenzelm@39439
   214
wenzelm@50500
   215
  def is_result(msg: XML.Tree): Boolean =
wenzelm@50500
   216
    msg match {
wenzelm@50500
   217
      case XML.Elem(Markup(Markup.RESULT, _), _) => true
wenzelm@50500
   218
      case _ => false
wenzelm@50500
   219
    }
wenzelm@50500
   220
wenzelm@50157
   221
  def is_tracing(msg: XML.Tree): Boolean =
wenzelm@39622
   222
    msg match {
wenzelm@50201
   223
      case XML.Elem(Markup(Markup.TRACING, _), _) => true
wenzelm@50201
   224
      case XML.Elem(Markup(Markup.TRACING_MESSAGE, _), _) => true
wenzelm@39622
   225
      case _ => false
wenzelm@39622
   226
    }
wenzelm@39622
   227
wenzelm@59184
   228
  def is_state(msg: XML.Tree): Boolean =
wenzelm@50500
   229
    msg match {
wenzelm@59184
   230
      case XML.Elem(Markup(Markup.STATE, _), _) => true
wenzelm@59184
   231
      case XML.Elem(Markup(Markup.STATE_MESSAGE, _), _) => true
wenzelm@59184
   232
      case _ => false
wenzelm@59184
   233
    }
wenzelm@59184
   234
wenzelm@59184
   235
  def is_information(msg: XML.Tree): Boolean =
wenzelm@59184
   236
    msg match {
wenzelm@59184
   237
      case XML.Elem(Markup(Markup.INFORMATION, _), _) => true
wenzelm@59184
   238
      case XML.Elem(Markup(Markup.INFORMATION_MESSAGE, _), _) => true
wenzelm@50500
   239
      case _ => false
wenzelm@50500
   240
    }
wenzelm@50500
   241
wenzelm@39511
   242
  def is_warning(msg: XML.Tree): Boolean =
wenzelm@39511
   243
    msg match {
wenzelm@50201
   244
      case XML.Elem(Markup(Markup.WARNING, _), _) => true
wenzelm@50201
   245
      case XML.Elem(Markup(Markup.WARNING_MESSAGE, _), _) => true
wenzelm@39511
   246
      case _ => false
wenzelm@39511
   247
    }
wenzelm@39511
   248
wenzelm@59203
   249
  def is_legacy(msg: XML.Tree): Boolean =
wenzelm@59203
   250
    msg match {
wenzelm@59203
   251
      case XML.Elem(Markup(Markup.LEGACY, _), _) => true
wenzelm@59203
   252
      case XML.Elem(Markup(Markup.LEGACY_MESSAGE, _), _) => true
wenzelm@59203
   253
      case _ => false
wenzelm@59203
   254
    }
wenzelm@59203
   255
wenzelm@39511
   256
  def is_error(msg: XML.Tree): Boolean =
wenzelm@39511
   257
    msg match {
wenzelm@50201
   258
      case XML.Elem(Markup(Markup.ERROR, _), _) => true
wenzelm@50201
   259
      case XML.Elem(Markup(Markup.ERROR_MESSAGE, _), _) => true
wenzelm@39511
   260
      case _ => false
wenzelm@39511
   261
    }
wenzelm@38887
   262
wenzelm@56495
   263
  def is_inlined(msg: XML.Tree): Boolean =
wenzelm@56495
   264
    !(is_result(msg) || is_tracing(msg) || is_state(msg))
wenzelm@56495
   265
wenzelm@50500
   266
wenzelm@60882
   267
  /* breakpoints */
wenzelm@60882
   268
wenzelm@60882
   269
  object ML_Breakpoint
wenzelm@60882
   270
  {
wenzelm@60882
   271
    def unapply(tree: XML.Tree): Option[Long] =
wenzelm@60882
   272
    tree match {
wenzelm@60882
   273
      case XML.Elem(Markup(Markup.ML_BREAKPOINT, Markup.Serial(breakpoint)), _) => Some(breakpoint)
wenzelm@60882
   274
      case _ => None
wenzelm@60882
   275
    }
wenzelm@60882
   276
  }
wenzelm@60882
   277
wenzelm@60882
   278
wenzelm@50500
   279
  /* dialogs */
wenzelm@50500
   280
wenzelm@50500
   281
  object Dialog_Args
wenzelm@50500
   282
  {
wenzelm@52531
   283
    def unapply(props: Properties.T): Option[(Document_ID.Generic, Long, String)] =
wenzelm@50500
   284
      (props, props, props) match {
wenzelm@50500
   285
        case (Position.Id(id), Markup.Serial(serial), Markup.Result(result)) =>
wenzelm@50500
   286
          Some((id, serial, result))
wenzelm@50500
   287
        case _ => None
wenzelm@50500
   288
      }
wenzelm@50500
   289
  }
wenzelm@50500
   290
wenzelm@50500
   291
  object Dialog
wenzelm@50500
   292
  {
wenzelm@52531
   293
    def unapply(tree: XML.Tree): Option[(Document_ID.Generic, Long, String)] =
wenzelm@50500
   294
      tree match {
wenzelm@50500
   295
        case XML.Elem(Markup(Markup.DIALOG, Dialog_Args(id, serial, result)), _) =>
wenzelm@50500
   296
          Some((id, serial, result))
wenzelm@50500
   297
        case _ => None
wenzelm@50500
   298
      }
wenzelm@50500
   299
  }
wenzelm@50500
   300
wenzelm@50500
   301
  object Dialog_Result
wenzelm@50500
   302
  {
wenzelm@52531
   303
    def apply(id: Document_ID.Generic, serial: Long, result: String): XML.Elem =
wenzelm@50501
   304
    {
wenzelm@50501
   305
      val props = Position.Id(id) ::: Markup.Serial(serial)
wenzelm@50501
   306
      XML.Elem(Markup(Markup.RESULT, props), List(XML.Text(result)))
wenzelm@50501
   307
    }
wenzelm@50500
   308
wenzelm@50501
   309
    def unapply(tree: XML.Tree): Option[String] =
wenzelm@50500
   310
      tree match {
wenzelm@50501
   311
        case XML.Elem(Markup(Markup.RESULT, _), List(XML.Text(result))) => Some(result)
wenzelm@50500
   312
        case _ => None
wenzelm@50500
   313
      }
wenzelm@50500
   314
  }
wenzelm@38412
   315
}
wenzelm@38412
   316
wenzelm@38412
   317
wenzelm@57916
   318
trait Protocol
wenzelm@38412
   319
{
wenzelm@57916
   320
  /* protocol commands */
wenzelm@57916
   321
wenzelm@57916
   322
  def protocol_command_bytes(name: String, args: Bytes*): Unit
wenzelm@57916
   323
  def protocol_command(name: String, args: String*): Unit
wenzelm@57916
   324
wenzelm@57916
   325
wenzelm@56387
   326
  /* options */
wenzelm@56387
   327
wenzelm@56387
   328
  def options(opts: Options): Unit =
wenzelm@65345
   329
    protocol_command("Prover.options", Symbol.encode_yxml(opts.encode))
wenzelm@56387
   330
wenzelm@56387
   331
wenzelm@65470
   332
  /* session base */
wenzelm@65470
   333
wenzelm@65470
   334
  private def encode_table(table: List[(String, String)]): String =
wenzelm@65470
   335
  {
wenzelm@65470
   336
    import XML.Encode._
wenzelm@65470
   337
    Symbol.encode_yxml(list(pair(string, string))(table))
wenzelm@65470
   338
  }
wenzelm@65470
   339
wenzelm@66712
   340
  private def encode_list(lst: List[String]): String =
wenzelm@66712
   341
  {
wenzelm@66712
   342
    import XML.Encode._
wenzelm@66712
   343
    Symbol.encode_yxml(list(string)(lst))
wenzelm@66712
   344
  }
wenzelm@66712
   345
wenzelm@67493
   346
  private def encode_sessions(lst: List[(String, Position.T)]): String =
wenzelm@67493
   347
  {
wenzelm@67493
   348
    import XML.Encode._
wenzelm@67493
   349
    Symbol.encode_yxml(list(pair(string, properties))(lst))
wenzelm@67493
   350
  }
wenzelm@67493
   351
wenzelm@66668
   352
  def session_base(resources: Resources)
wenzelm@66668
   353
  {
wenzelm@66668
   354
    val base = resources.session_base.standard_path
wenzelm@67219
   355
    protocol_command("Prover.init_session_base",
wenzelm@67493
   356
      encode_sessions(base.known.sessions.toList),
wenzelm@67471
   357
      encode_list(base.doc_names),
wenzelm@66668
   358
      encode_table(base.global_theories.toList),
wenzelm@66717
   359
      encode_list(base.loaded_theories.keys),
wenzelm@66668
   360
      encode_table(base.dest_known_theories))
wenzelm@66668
   361
  }
wenzelm@65470
   362
wenzelm@65470
   363
wenzelm@56387
   364
  /* interned items */
wenzelm@54519
   365
wenzelm@56335
   366
  def define_blob(digest: SHA1.Digest, bytes: Bytes): Unit =
wenzelm@56387
   367
    protocol_command_bytes("Document.define_blob", Bytes(digest.toString), bytes)
wenzelm@38412
   368
wenzelm@59671
   369
  def define_command(command: Command)
wenzelm@54519
   370
  {
wenzelm@54519
   371
    val blobs_yxml =
wenzelm@61376
   372
    {
wenzelm@61376
   373
      import XML.Encode._
wenzelm@54519
   374
      val encode_blob: T[Command.Blob] =
wenzelm@54519
   375
        variant(List(
wenzelm@54526
   376
          { case Exn.Res((a, b)) =>
wenzelm@65345
   377
              (Nil, pair(string, option(string))((a.node, b.map(p => p._1.toString)))) },
wenzelm@65345
   378
          { case Exn.Exn(e) => (Nil, string(Exn.message(e))) }))
wenzelm@59085
   379
wenzelm@65345
   380
      Symbol.encode_yxml(pair(list(encode_blob), int)(command.blobs, command.blobs_index))
wenzelm@54519
   381
    }
wenzelm@59085
   382
wenzelm@59085
   383
    val toks = command.span.content
wenzelm@59085
   384
    val toks_yxml =
wenzelm@61376
   385
    {
wenzelm@61376
   386
      import XML.Encode._
wenzelm@64616
   387
      val encode_tok: T[Token] = (tok => pair(int, int)((tok.kind.id, Symbol.length(tok.source))))
wenzelm@65345
   388
      Symbol.encode_yxml(list(encode_tok)(toks))
wenzelm@59085
   389
    }
wenzelm@59085
   390
wenzelm@52582
   391
    protocol_command("Document.define_command",
wenzelm@65345
   392
      (Document_ID(command.id) :: Symbol.encode(command.span.name) :: blobs_yxml :: toks_yxml ::
wenzelm@65345
   393
        toks.map(tok => Symbol.encode(tok.source))): _*)
wenzelm@54519
   394
  }
wenzelm@38412
   395
wenzelm@38412
   396
wenzelm@52931
   397
  /* execution */
wenzelm@52931
   398
wenzelm@66379
   399
  def consolidate_execution(): Unit =
wenzelm@66379
   400
    protocol_command("Document.consolidate_execution")
wenzelm@66379
   401
wenzelm@52931
   402
  def discontinue_execution(): Unit =
wenzelm@52931
   403
    protocol_command("Document.discontinue_execution")
wenzelm@38412
   404
wenzelm@52931
   405
  def cancel_exec(id: Document_ID.Exec): Unit =
wenzelm@52931
   406
    protocol_command("Document.cancel_exec", Document_ID(id))
wenzelm@52931
   407
wenzelm@52931
   408
wenzelm@52931
   409
  /* document versions */
wenzelm@47343
   410
wenzelm@52530
   411
  def update(old_id: Document_ID.Version, new_id: Document_ID.Version,
wenzelm@44383
   412
    edits: List[Document.Edit_Command])
wenzelm@38412
   413
  {
wenzelm@44157
   414
    val edits_yxml =
wenzelm@61376
   415
    {
wenzelm@61376
   416
      import XML.Encode._
wenzelm@44383
   417
      def id: T[Command] = (cmd => long(cmd.id))
wenzelm@46737
   418
      def encode_edit(name: Document.Node.Name)
wenzelm@52849
   419
          : T[Document.Node.Edit[Command.Edit, Command.Perspective]] =
wenzelm@44979
   420
        variant(List(
wenzelm@44979
   421
          { case Document.Node.Edits(a) => (Nil, list(pair(option(id), option(id)))(a)) },
wenzelm@48707
   422
          { case Document.Node.Deps(header) =>
wenzelm@60992
   423
              val master_dir = File.standard_url(name.master_dir)
wenzelm@59695
   424
              val imports = header.imports.map({ case (a, _) => a.node })
wenzelm@65384
   425
              val keywords =
wenzelm@65384
   426
                header.keywords.map({ case (a, Keyword.Spec(b, c, d)) => (a, ((b, c), d)) })
wenzelm@44979
   427
              (Nil,
wenzelm@65345
   428
                pair(string, pair(string, pair(list(string), pair(list(pair(string,
wenzelm@65345
   429
                    pair(pair(string, list(string)), list(string)))), list(string)))))(
wenzelm@65445
   430
                (master_dir, (name.theory, (imports, (keywords, header.errors)))))) },
wenzelm@52849
   431
          { case Document.Node.Perspective(a, b, c) =>
wenzelm@52849
   432
              (bool_atom(a) :: b.commands.map(cmd => long_atom(cmd.id)),
wenzelm@65345
   433
                list(pair(id, pair(string, list(string))))(c.dest)) }))
wenzelm@48705
   434
      def encode_edits: T[List[Document.Edit_Command]] = list((node_edit: Document.Edit_Command) =>
wenzelm@44979
   435
      {
wenzelm@44979
   436
        val (name, edit) = node_edit
wenzelm@65345
   437
        pair(string, encode_edit(name))(name.node, edit)
wenzelm@44979
   438
      })
wenzelm@65345
   439
      Symbol.encode_yxml(encode_edits(edits)) }
wenzelm@52582
   440
    protocol_command("Document.update", Document_ID(old_id), Document_ID(new_id), edits_yxml)
wenzelm@38412
   441
  }
wenzelm@43748
   442
wenzelm@44673
   443
  def remove_versions(versions: List[Document.Version])
wenzelm@44673
   444
  {
wenzelm@44673
   445
    val versions_yxml =
wenzelm@59364
   446
    { import XML.Encode._
wenzelm@65345
   447
      Symbol.encode_yxml(list(long)(versions.map(_.id))) }
wenzelm@52582
   448
    protocol_command("Document.remove_versions", versions_yxml)
wenzelm@44673
   449
  }
wenzelm@44673
   450
wenzelm@43748
   451
wenzelm@50498
   452
  /* dialog via document content */
wenzelm@50498
   453
wenzelm@52931
   454
  def dialog_result(serial: Long, result: String): Unit =
wenzelm@63805
   455
    protocol_command("Document.dialog_result", Value.Long(serial), result)
wenzelm@38412
   456
}