src/Pure/PIDE/protocol.scala
author wenzelm
Fri Jan 19 14:55:46 2018 +0100 (20 months ago)
changeset 67471 bddfa23a4ea9
parent 67219 81e9804b2014
child 67493 c4e9e0c50487
permissions -rw-r--r--
formal treatment of documentation names;
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@67219
   344
    protocol_command("Prover.init_session_base",
wenzelm@67219
   345
      encode_list(base.known.sessions.toList),
wenzelm@67471
   346
      encode_list(base.doc_names),
wenzelm@66668
   347
      encode_table(base.global_theories.toList),
wenzelm@66717
   348
      encode_list(base.loaded_theories.keys),
wenzelm@66668
   349
      encode_table(base.dest_known_theories))
wenzelm@66668
   350
  }
wenzelm@65470
   351
wenzelm@65470
   352
wenzelm@56387
   353
  /* interned items */
wenzelm@54519
   354
wenzelm@56335
   355
  def define_blob(digest: SHA1.Digest, bytes: Bytes): Unit =
wenzelm@56387
   356
    protocol_command_bytes("Document.define_blob", Bytes(digest.toString), bytes)
wenzelm@38412
   357
wenzelm@59671
   358
  def define_command(command: Command)
wenzelm@54519
   359
  {
wenzelm@54519
   360
    val blobs_yxml =
wenzelm@61376
   361
    {
wenzelm@61376
   362
      import XML.Encode._
wenzelm@54519
   363
      val encode_blob: T[Command.Blob] =
wenzelm@54519
   364
        variant(List(
wenzelm@54526
   365
          { case Exn.Res((a, b)) =>
wenzelm@65345
   366
              (Nil, pair(string, option(string))((a.node, b.map(p => p._1.toString)))) },
wenzelm@65345
   367
          { case Exn.Exn(e) => (Nil, string(Exn.message(e))) }))
wenzelm@59085
   368
wenzelm@65345
   369
      Symbol.encode_yxml(pair(list(encode_blob), int)(command.blobs, command.blobs_index))
wenzelm@54519
   370
    }
wenzelm@59085
   371
wenzelm@59085
   372
    val toks = command.span.content
wenzelm@59085
   373
    val toks_yxml =
wenzelm@61376
   374
    {
wenzelm@61376
   375
      import XML.Encode._
wenzelm@64616
   376
      val encode_tok: T[Token] = (tok => pair(int, int)((tok.kind.id, Symbol.length(tok.source))))
wenzelm@65345
   377
      Symbol.encode_yxml(list(encode_tok)(toks))
wenzelm@59085
   378
    }
wenzelm@59085
   379
wenzelm@52582
   380
    protocol_command("Document.define_command",
wenzelm@65345
   381
      (Document_ID(command.id) :: Symbol.encode(command.span.name) :: blobs_yxml :: toks_yxml ::
wenzelm@65345
   382
        toks.map(tok => Symbol.encode(tok.source))): _*)
wenzelm@54519
   383
  }
wenzelm@38412
   384
wenzelm@38412
   385
wenzelm@52931
   386
  /* execution */
wenzelm@52931
   387
wenzelm@66379
   388
  def consolidate_execution(): Unit =
wenzelm@66379
   389
    protocol_command("Document.consolidate_execution")
wenzelm@66379
   390
wenzelm@52931
   391
  def discontinue_execution(): Unit =
wenzelm@52931
   392
    protocol_command("Document.discontinue_execution")
wenzelm@38412
   393
wenzelm@52931
   394
  def cancel_exec(id: Document_ID.Exec): Unit =
wenzelm@52931
   395
    protocol_command("Document.cancel_exec", Document_ID(id))
wenzelm@52931
   396
wenzelm@52931
   397
wenzelm@52931
   398
  /* document versions */
wenzelm@47343
   399
wenzelm@52530
   400
  def update(old_id: Document_ID.Version, new_id: Document_ID.Version,
wenzelm@44383
   401
    edits: List[Document.Edit_Command])
wenzelm@38412
   402
  {
wenzelm@44157
   403
    val edits_yxml =
wenzelm@61376
   404
    {
wenzelm@61376
   405
      import XML.Encode._
wenzelm@44383
   406
      def id: T[Command] = (cmd => long(cmd.id))
wenzelm@46737
   407
      def encode_edit(name: Document.Node.Name)
wenzelm@52849
   408
          : T[Document.Node.Edit[Command.Edit, Command.Perspective]] =
wenzelm@44979
   409
        variant(List(
wenzelm@44979
   410
          { case Document.Node.Edits(a) => (Nil, list(pair(option(id), option(id)))(a)) },
wenzelm@48707
   411
          { case Document.Node.Deps(header) =>
wenzelm@60992
   412
              val master_dir = File.standard_url(name.master_dir)
wenzelm@59695
   413
              val imports = header.imports.map({ case (a, _) => a.node })
wenzelm@65384
   414
              val keywords =
wenzelm@65384
   415
                header.keywords.map({ case (a, Keyword.Spec(b, c, d)) => (a, ((b, c), d)) })
wenzelm@44979
   416
              (Nil,
wenzelm@65345
   417
                pair(string, pair(string, pair(list(string), pair(list(pair(string,
wenzelm@65345
   418
                    pair(pair(string, list(string)), list(string)))), list(string)))))(
wenzelm@65445
   419
                (master_dir, (name.theory, (imports, (keywords, header.errors)))))) },
wenzelm@52849
   420
          { case Document.Node.Perspective(a, b, c) =>
wenzelm@52849
   421
              (bool_atom(a) :: b.commands.map(cmd => long_atom(cmd.id)),
wenzelm@65345
   422
                list(pair(id, pair(string, list(string))))(c.dest)) }))
wenzelm@48705
   423
      def encode_edits: T[List[Document.Edit_Command]] = list((node_edit: Document.Edit_Command) =>
wenzelm@44979
   424
      {
wenzelm@44979
   425
        val (name, edit) = node_edit
wenzelm@65345
   426
        pair(string, encode_edit(name))(name.node, edit)
wenzelm@44979
   427
      })
wenzelm@65345
   428
      Symbol.encode_yxml(encode_edits(edits)) }
wenzelm@52582
   429
    protocol_command("Document.update", Document_ID(old_id), Document_ID(new_id), edits_yxml)
wenzelm@38412
   430
  }
wenzelm@43748
   431
wenzelm@44673
   432
  def remove_versions(versions: List[Document.Version])
wenzelm@44673
   433
  {
wenzelm@44673
   434
    val versions_yxml =
wenzelm@59364
   435
    { import XML.Encode._
wenzelm@65345
   436
      Symbol.encode_yxml(list(long)(versions.map(_.id))) }
wenzelm@52582
   437
    protocol_command("Document.remove_versions", versions_yxml)
wenzelm@44673
   438
  }
wenzelm@44673
   439
wenzelm@43748
   440
wenzelm@50498
   441
  /* dialog via document content */
wenzelm@50498
   442
wenzelm@52931
   443
  def dialog_result(serial: Long, result: String): Unit =
wenzelm@63805
   444
    protocol_command("Document.dialog_result", Value.Long(serial), result)
wenzelm@38412
   445
}