src/Pure/PIDE/protocol.scala
author wenzelm
Mon Oct 16 14:32:09 2017 +0200 (23 months ago)
changeset 66873 9953ae603a23
parent 66717 67dbf5cdc056
child 67219 81e9804b2014
permissions -rw-r--r--
provide theory timing information, similar to command timing but always considered relevant;
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@44866
   149
  }
wenzelm@44613
   150
wenzelm@44613
   151
  def node_status(
wenzelm@66410
   152
    state: Document.State,
wenzelm@66410
   153
    version: Document.Version,
wenzelm@66410
   154
    name: Document.Node.Name,
wenzelm@66410
   155
    node: Document.Node): Node_Status =
wenzelm@44613
   156
  {
wenzelm@44613
   157
    var unprocessed = 0
wenzelm@44613
   158
    var running = 0
wenzelm@46688
   159
    var warned = 0
wenzelm@44613
   160
    var failed = 0
wenzelm@56474
   161
    var finished = 0
wenzelm@56356
   162
    for (command <- node.commands.iterator) {
wenzelm@56355
   163
      val states = state.command_states(version, command)
wenzelm@56359
   164
      val status = Status.merge(states.iterator.map(_.protocol_status))
wenzelm@56355
   165
wenzelm@56299
   166
      if (status.is_running) running += 1
wenzelm@57843
   167
      else if (status.is_failed) failed += 1
wenzelm@56395
   168
      else if (status.is_warned) warned += 1
wenzelm@56395
   169
      else if (status.is_finished) finished += 1
wenzelm@56299
   170
      else unprocessed += 1
wenzelm@56299
   171
    }
wenzelm@66410
   172
    val consolidated = state.node_consolidated(version, name)
wenzelm@66410
   173
wenzelm@66410
   174
    Node_Status(unprocessed, running, warned, failed, finished, consolidated)
wenzelm@44613
   175
  }
wenzelm@44613
   176
wenzelm@38887
   177
wenzelm@51533
   178
  /* node timing */
wenzelm@51533
   179
wenzelm@51533
   180
  sealed case class Node_Timing(total: Double, commands: Map[Command, Double])
wenzelm@51533
   181
wenzelm@51533
   182
  val empty_node_timing = Node_Timing(0.0, Map.empty)
wenzelm@51533
   183
wenzelm@51533
   184
  def node_timing(
wenzelm@51533
   185
    state: Document.State,
wenzelm@51533
   186
    version: Document.Version,
wenzelm@51533
   187
    node: Document.Node,
wenzelm@51533
   188
    threshold: Double): Node_Timing =
wenzelm@51533
   189
  {
wenzelm@51533
   190
    var total = 0.0
wenzelm@51533
   191
    var commands = Map.empty[Command, Double]
wenzelm@51533
   192
    for {
wenzelm@51533
   193
      command <- node.commands.iterator
wenzelm@56299
   194
      st <- state.command_states(version, command)
wenzelm@56356
   195
    } {
wenzelm@56356
   196
      val command_timing =
wenzelm@51533
   197
        (0.0 /: st.status)({
wenzelm@51533
   198
          case (timing, Markup.Timing(t)) => timing + t.elapsed.seconds
wenzelm@51533
   199
          case (timing, _) => timing
wenzelm@51533
   200
        })
wenzelm@51533
   201
      total += command_timing
wenzelm@51533
   202
      if (command_timing >= threshold) commands += (command -> command_timing)
wenzelm@51533
   203
    }
wenzelm@51533
   204
    Node_Timing(total, commands)
wenzelm@51533
   205
  }
wenzelm@51533
   206
wenzelm@51533
   207
wenzelm@39441
   208
  /* result messages */
wenzelm@39439
   209
wenzelm@50500
   210
  def is_result(msg: XML.Tree): Boolean =
wenzelm@50500
   211
    msg match {
wenzelm@50500
   212
      case XML.Elem(Markup(Markup.RESULT, _), _) => true
wenzelm@50500
   213
      case _ => false
wenzelm@50500
   214
    }
wenzelm@50500
   215
wenzelm@50157
   216
  def is_tracing(msg: XML.Tree): Boolean =
wenzelm@39622
   217
    msg match {
wenzelm@50201
   218
      case XML.Elem(Markup(Markup.TRACING, _), _) => true
wenzelm@50201
   219
      case XML.Elem(Markup(Markup.TRACING_MESSAGE, _), _) => true
wenzelm@39622
   220
      case _ => false
wenzelm@39622
   221
    }
wenzelm@39622
   222
wenzelm@59184
   223
  def is_state(msg: XML.Tree): Boolean =
wenzelm@50500
   224
    msg match {
wenzelm@59184
   225
      case XML.Elem(Markup(Markup.STATE, _), _) => true
wenzelm@59184
   226
      case XML.Elem(Markup(Markup.STATE_MESSAGE, _), _) => true
wenzelm@59184
   227
      case _ => false
wenzelm@59184
   228
    }
wenzelm@59184
   229
wenzelm@59184
   230
  def is_information(msg: XML.Tree): Boolean =
wenzelm@59184
   231
    msg match {
wenzelm@59184
   232
      case XML.Elem(Markup(Markup.INFORMATION, _), _) => true
wenzelm@59184
   233
      case XML.Elem(Markup(Markup.INFORMATION_MESSAGE, _), _) => true
wenzelm@50500
   234
      case _ => false
wenzelm@50500
   235
    }
wenzelm@50500
   236
wenzelm@39511
   237
  def is_warning(msg: XML.Tree): Boolean =
wenzelm@39511
   238
    msg match {
wenzelm@50201
   239
      case XML.Elem(Markup(Markup.WARNING, _), _) => true
wenzelm@50201
   240
      case XML.Elem(Markup(Markup.WARNING_MESSAGE, _), _) => true
wenzelm@39511
   241
      case _ => false
wenzelm@39511
   242
    }
wenzelm@39511
   243
wenzelm@59203
   244
  def is_legacy(msg: XML.Tree): Boolean =
wenzelm@59203
   245
    msg match {
wenzelm@59203
   246
      case XML.Elem(Markup(Markup.LEGACY, _), _) => true
wenzelm@59203
   247
      case XML.Elem(Markup(Markup.LEGACY_MESSAGE, _), _) => true
wenzelm@59203
   248
      case _ => false
wenzelm@59203
   249
    }
wenzelm@59203
   250
wenzelm@39511
   251
  def is_error(msg: XML.Tree): Boolean =
wenzelm@39511
   252
    msg match {
wenzelm@50201
   253
      case XML.Elem(Markup(Markup.ERROR, _), _) => true
wenzelm@50201
   254
      case XML.Elem(Markup(Markup.ERROR_MESSAGE, _), _) => true
wenzelm@39511
   255
      case _ => false
wenzelm@39511
   256
    }
wenzelm@38887
   257
wenzelm@56495
   258
  def is_inlined(msg: XML.Tree): Boolean =
wenzelm@56495
   259
    !(is_result(msg) || is_tracing(msg) || is_state(msg))
wenzelm@56495
   260
wenzelm@50500
   261
wenzelm@60882
   262
  /* breakpoints */
wenzelm@60882
   263
wenzelm@60882
   264
  object ML_Breakpoint
wenzelm@60882
   265
  {
wenzelm@60882
   266
    def unapply(tree: XML.Tree): Option[Long] =
wenzelm@60882
   267
    tree match {
wenzelm@60882
   268
      case XML.Elem(Markup(Markup.ML_BREAKPOINT, Markup.Serial(breakpoint)), _) => Some(breakpoint)
wenzelm@60882
   269
      case _ => None
wenzelm@60882
   270
    }
wenzelm@60882
   271
  }
wenzelm@60882
   272
wenzelm@60882
   273
wenzelm@50500
   274
  /* dialogs */
wenzelm@50500
   275
wenzelm@50500
   276
  object Dialog_Args
wenzelm@50500
   277
  {
wenzelm@52531
   278
    def unapply(props: Properties.T): Option[(Document_ID.Generic, Long, String)] =
wenzelm@50500
   279
      (props, props, props) match {
wenzelm@50500
   280
        case (Position.Id(id), Markup.Serial(serial), Markup.Result(result)) =>
wenzelm@50500
   281
          Some((id, serial, result))
wenzelm@50500
   282
        case _ => None
wenzelm@50500
   283
      }
wenzelm@50500
   284
  }
wenzelm@50500
   285
wenzelm@50500
   286
  object Dialog
wenzelm@50500
   287
  {
wenzelm@52531
   288
    def unapply(tree: XML.Tree): Option[(Document_ID.Generic, Long, String)] =
wenzelm@50500
   289
      tree match {
wenzelm@50500
   290
        case XML.Elem(Markup(Markup.DIALOG, Dialog_Args(id, serial, result)), _) =>
wenzelm@50500
   291
          Some((id, serial, result))
wenzelm@50500
   292
        case _ => None
wenzelm@50500
   293
      }
wenzelm@50500
   294
  }
wenzelm@50500
   295
wenzelm@50500
   296
  object Dialog_Result
wenzelm@50500
   297
  {
wenzelm@52531
   298
    def apply(id: Document_ID.Generic, serial: Long, result: String): XML.Elem =
wenzelm@50501
   299
    {
wenzelm@50501
   300
      val props = Position.Id(id) ::: Markup.Serial(serial)
wenzelm@50501
   301
      XML.Elem(Markup(Markup.RESULT, props), List(XML.Text(result)))
wenzelm@50501
   302
    }
wenzelm@50500
   303
wenzelm@50501
   304
    def unapply(tree: XML.Tree): Option[String] =
wenzelm@50500
   305
      tree match {
wenzelm@50501
   306
        case XML.Elem(Markup(Markup.RESULT, _), List(XML.Text(result))) => Some(result)
wenzelm@50500
   307
        case _ => None
wenzelm@50500
   308
      }
wenzelm@50500
   309
  }
wenzelm@38412
   310
}
wenzelm@38412
   311
wenzelm@38412
   312
wenzelm@57916
   313
trait Protocol
wenzelm@38412
   314
{
wenzelm@57916
   315
  /* protocol commands */
wenzelm@57916
   316
wenzelm@57916
   317
  def protocol_command_bytes(name: String, args: Bytes*): Unit
wenzelm@57916
   318
  def protocol_command(name: String, args: String*): Unit
wenzelm@57916
   319
wenzelm@57916
   320
wenzelm@56387
   321
  /* options */
wenzelm@56387
   322
wenzelm@56387
   323
  def options(opts: Options): Unit =
wenzelm@65345
   324
    protocol_command("Prover.options", Symbol.encode_yxml(opts.encode))
wenzelm@56387
   325
wenzelm@56387
   326
wenzelm@65470
   327
  /* session base */
wenzelm@65470
   328
wenzelm@65470
   329
  private def encode_table(table: List[(String, String)]): String =
wenzelm@65470
   330
  {
wenzelm@65470
   331
    import XML.Encode._
wenzelm@65470
   332
    Symbol.encode_yxml(list(pair(string, string))(table))
wenzelm@65470
   333
  }
wenzelm@65470
   334
wenzelm@66712
   335
  private def encode_list(lst: List[String]): String =
wenzelm@66712
   336
  {
wenzelm@66712
   337
    import XML.Encode._
wenzelm@66712
   338
    Symbol.encode_yxml(list(string)(lst))
wenzelm@66712
   339
  }
wenzelm@66712
   340
wenzelm@66668
   341
  def session_base(resources: Resources)
wenzelm@66668
   342
  {
wenzelm@66668
   343
    val base = resources.session_base.standard_path
wenzelm@65470
   344
    protocol_command("Prover.session_base",
wenzelm@66668
   345
      encode_table(base.global_theories.toList),
wenzelm@66717
   346
      encode_list(base.loaded_theories.keys),
wenzelm@66668
   347
      encode_table(base.dest_known_theories))
wenzelm@66668
   348
  }
wenzelm@65470
   349
wenzelm@65470
   350
wenzelm@56387
   351
  /* interned items */
wenzelm@54519
   352
wenzelm@56335
   353
  def define_blob(digest: SHA1.Digest, bytes: Bytes): Unit =
wenzelm@56387
   354
    protocol_command_bytes("Document.define_blob", Bytes(digest.toString), bytes)
wenzelm@38412
   355
wenzelm@59671
   356
  def define_command(command: Command)
wenzelm@54519
   357
  {
wenzelm@54519
   358
    val blobs_yxml =
wenzelm@61376
   359
    {
wenzelm@61376
   360
      import XML.Encode._
wenzelm@54519
   361
      val encode_blob: T[Command.Blob] =
wenzelm@54519
   362
        variant(List(
wenzelm@54526
   363
          { case Exn.Res((a, b)) =>
wenzelm@65345
   364
              (Nil, pair(string, option(string))((a.node, b.map(p => p._1.toString)))) },
wenzelm@65345
   365
          { case Exn.Exn(e) => (Nil, string(Exn.message(e))) }))
wenzelm@59085
   366
wenzelm@65345
   367
      Symbol.encode_yxml(pair(list(encode_blob), int)(command.blobs, command.blobs_index))
wenzelm@54519
   368
    }
wenzelm@59085
   369
wenzelm@59085
   370
    val toks = command.span.content
wenzelm@59085
   371
    val toks_yxml =
wenzelm@61376
   372
    {
wenzelm@61376
   373
      import XML.Encode._
wenzelm@64616
   374
      val encode_tok: T[Token] = (tok => pair(int, int)((tok.kind.id, Symbol.length(tok.source))))
wenzelm@65345
   375
      Symbol.encode_yxml(list(encode_tok)(toks))
wenzelm@59085
   376
    }
wenzelm@59085
   377
wenzelm@52582
   378
    protocol_command("Document.define_command",
wenzelm@65345
   379
      (Document_ID(command.id) :: Symbol.encode(command.span.name) :: blobs_yxml :: toks_yxml ::
wenzelm@65345
   380
        toks.map(tok => Symbol.encode(tok.source))): _*)
wenzelm@54519
   381
  }
wenzelm@38412
   382
wenzelm@38412
   383
wenzelm@52931
   384
  /* execution */
wenzelm@52931
   385
wenzelm@66379
   386
  def consolidate_execution(): Unit =
wenzelm@66379
   387
    protocol_command("Document.consolidate_execution")
wenzelm@66379
   388
wenzelm@52931
   389
  def discontinue_execution(): Unit =
wenzelm@52931
   390
    protocol_command("Document.discontinue_execution")
wenzelm@38412
   391
wenzelm@52931
   392
  def cancel_exec(id: Document_ID.Exec): Unit =
wenzelm@52931
   393
    protocol_command("Document.cancel_exec", Document_ID(id))
wenzelm@52931
   394
wenzelm@52931
   395
wenzelm@52931
   396
  /* document versions */
wenzelm@47343
   397
wenzelm@52530
   398
  def update(old_id: Document_ID.Version, new_id: Document_ID.Version,
wenzelm@44383
   399
    edits: List[Document.Edit_Command])
wenzelm@38412
   400
  {
wenzelm@44157
   401
    val edits_yxml =
wenzelm@61376
   402
    {
wenzelm@61376
   403
      import XML.Encode._
wenzelm@44383
   404
      def id: T[Command] = (cmd => long(cmd.id))
wenzelm@46737
   405
      def encode_edit(name: Document.Node.Name)
wenzelm@52849
   406
          : T[Document.Node.Edit[Command.Edit, Command.Perspective]] =
wenzelm@44979
   407
        variant(List(
wenzelm@44979
   408
          { case Document.Node.Edits(a) => (Nil, list(pair(option(id), option(id)))(a)) },
wenzelm@48707
   409
          { case Document.Node.Deps(header) =>
wenzelm@60992
   410
              val master_dir = File.standard_url(name.master_dir)
wenzelm@59695
   411
              val imports = header.imports.map({ case (a, _) => a.node })
wenzelm@65384
   412
              val keywords =
wenzelm@65384
   413
                header.keywords.map({ case (a, Keyword.Spec(b, c, d)) => (a, ((b, c), d)) })
wenzelm@44979
   414
              (Nil,
wenzelm@65345
   415
                pair(string, pair(string, pair(list(string), pair(list(pair(string,
wenzelm@65345
   416
                    pair(pair(string, list(string)), list(string)))), list(string)))))(
wenzelm@65445
   417
                (master_dir, (name.theory, (imports, (keywords, header.errors)))))) },
wenzelm@52849
   418
          { case Document.Node.Perspective(a, b, c) =>
wenzelm@52849
   419
              (bool_atom(a) :: b.commands.map(cmd => long_atom(cmd.id)),
wenzelm@65345
   420
                list(pair(id, pair(string, list(string))))(c.dest)) }))
wenzelm@48705
   421
      def encode_edits: T[List[Document.Edit_Command]] = list((node_edit: Document.Edit_Command) =>
wenzelm@44979
   422
      {
wenzelm@44979
   423
        val (name, edit) = node_edit
wenzelm@65345
   424
        pair(string, encode_edit(name))(name.node, edit)
wenzelm@44979
   425
      })
wenzelm@65345
   426
      Symbol.encode_yxml(encode_edits(edits)) }
wenzelm@52582
   427
    protocol_command("Document.update", Document_ID(old_id), Document_ID(new_id), edits_yxml)
wenzelm@38412
   428
  }
wenzelm@43748
   429
wenzelm@44673
   430
  def remove_versions(versions: List[Document.Version])
wenzelm@44673
   431
  {
wenzelm@44673
   432
    val versions_yxml =
wenzelm@59364
   433
    { import XML.Encode._
wenzelm@65345
   434
      Symbol.encode_yxml(list(long)(versions.map(_.id))) }
wenzelm@52582
   435
    protocol_command("Document.remove_versions", versions_yxml)
wenzelm@44673
   436
  }
wenzelm@44673
   437
wenzelm@43748
   438
wenzelm@50498
   439
  /* dialog via document content */
wenzelm@50498
   440
wenzelm@52931
   441
  def dialog_result(serial: Long, result: String): Unit =
wenzelm@63805
   442
    protocol_command("Document.dialog_result", Value.Long(serial), result)
wenzelm@38412
   443
}