| author | huffman | 
| Mon, 02 Apr 2012 09:18:16 +0200 | |
| changeset 47268 | 262d96552e50 | 
| parent 47012 | 0e246130486b | 
| child 47346 | cd3ab7625519 | 
| permissions | -rw-r--r-- | 
| 34268 | 1 | /* Title: Pure/Thy/thy_syntax.scala | 
| 2 | Author: Makarius | |
| 3 | ||
| 38374 | 4 | Superficial theory syntax: tokens and spans. | 
| 34268 | 5 | */ | 
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 38239 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 10 | import scala.collection.mutable | 
| 38374 | 11 | import scala.annotation.tailrec | 
| 38239 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 12 | |
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 13 | |
| 34303 | 14 | object Thy_Syntax | 
| 34268 | 15 | {
 | 
| 40454 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 16 | /** nested structure **/ | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 17 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 18 | object Structure | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 19 |   {
 | 
| 40478 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 20 |     sealed abstract class Entry { def length: Int }
 | 
| 40454 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 21 | case class Block(val name: String, val body: List[Entry]) extends Entry | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 22 |     {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 23 | val length: Int = (0 /: body)(_ + _.length) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 24 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 25 | case class Atom(val command: Command) extends Entry | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 26 |     {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 27 | def length: Int = command.length | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 28 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 29 | |
| 46811 
03a2dc9e0624
clarified command span: include trailing whitespace/comments and thus reduce number of ignored spans with associated transactions and states (factor 2);
 wenzelm parents: 
46749diff
changeset | 30 | def parse(syntax: Outer_Syntax, node_name: Document.Node.Name, text: CharSequence): Entry = | 
| 40454 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 31 |     {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 32 | /* stack operations */ | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 33 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 34 | def buffer(): mutable.ListBuffer[Entry] = new mutable.ListBuffer[Entry] | 
| 44615 | 35 | var stack: List[(Int, String, mutable.ListBuffer[Entry])] = | 
| 36 | List((0, "theory " + node_name.theory, buffer())) | |
| 40454 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 37 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 38 | @tailrec def close(level: Int => Boolean) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 39 |       {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 40 |         stack match {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 41 | case (lev, name, body) :: (_, _, body2) :: rest if level(lev) => | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 42 | body2 += Block(name, body.toList) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 43 | stack = stack.tail | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 44 | close(level) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 45 | case _ => | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 46 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 47 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 48 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 49 | def result(): Entry = | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 50 |       {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 51 | close(_ => true) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 52 | val (_, name, body) = stack.head | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 53 | Block(name, body.toList) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 54 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 55 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 56 | def add(command: Command) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 57 |       {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 58 |         syntax.heading_level(command) match {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 59 | case Some(i) => | 
| 46969 | 60 | close(_ > i) | 
| 61 | stack = (i + 1, command.source, buffer()) :: stack | |
| 40454 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 62 | case None => | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 63 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 64 | stack.head._3 += Atom(command) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 65 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 66 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 67 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 68 | /* result structure */ | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 69 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 70 | val spans = parse_spans(syntax.scan(text)) | 
| 47012 
0e246130486b
clarified command span classification: strict Command.is_command, permissive Command.name;
 wenzelm parents: 
46969diff
changeset | 71 | spans.foreach(span => add(Command(Document.no_id, node_name, span))) | 
| 40454 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 72 | result() | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 73 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 74 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 75 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 76 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 77 | |
| 38374 | 78 | /** parse spans **/ | 
| 79 | ||
| 38373 | 80 | def parse_spans(toks: List[Token]): List[List[Token]] = | 
| 34268 | 81 |   {
 | 
| 38373 | 82 | val result = new mutable.ListBuffer[List[Token]] | 
| 38239 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 83 | val span = new mutable.ListBuffer[Token] | 
| 34268 | 84 | |
| 46811 
03a2dc9e0624
clarified command span: include trailing whitespace/comments and thus reduce number of ignored spans with associated transactions and states (factor 2);
 wenzelm parents: 
46749diff
changeset | 85 |     def flush() { if (!span.isEmpty) { result += span.toList; span.clear } }
 | 
| 
03a2dc9e0624
clarified command span: include trailing whitespace/comments and thus reduce number of ignored spans with associated transactions and states (factor 2);
 wenzelm parents: 
46749diff
changeset | 86 |     for (tok <- toks) { if (tok.is_command) flush(); span += tok }
 | 
| 
03a2dc9e0624
clarified command span: include trailing whitespace/comments and thus reduce number of ignored spans with associated transactions and states (factor 2);
 wenzelm parents: 
46749diff
changeset | 87 | flush() | 
| 38239 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 88 | result.toList | 
| 34268 | 89 | } | 
| 38374 | 90 | |
| 91 | ||
| 92 | ||
| 44436 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 93 | /** perspective **/ | 
| 44388 | 94 | |
| 95 | def command_perspective(node: Document.Node, perspective: Text.Perspective): Command.Perspective = | |
| 96 |   {
 | |
| 44474 | 97 | if (perspective.is_empty) Command.Perspective.empty | 
| 44388 | 98 |     else {
 | 
| 99 | val result = new mutable.ListBuffer[Command] | |
| 100 | @tailrec | |
| 101 | def check_ranges(ranges: List[Text.Range], commands: Stream[(Command, Text.Offset)]) | |
| 102 |       {
 | |
| 103 |         (ranges, commands) match {
 | |
| 104 | case (range :: more_ranges, (command, offset) #:: more_commands) => | |
| 105 | val command_range = command.range + offset | |
| 106 |             range compare command_range match {
 | |
| 107 | case -1 => check_ranges(more_ranges, commands) | |
| 108 | case 0 => | |
| 109 | result += command | |
| 110 | check_ranges(ranges, more_commands) | |
| 111 | case 1 => check_ranges(ranges, more_commands) | |
| 112 | } | |
| 113 | case _ => | |
| 114 | } | |
| 115 | } | |
| 44473 | 116 | check_ranges(perspective.ranges, node.command_range(perspective.range).toStream) | 
| 44474 | 117 | Command.Perspective(result.toList) | 
| 44388 | 118 | } | 
| 119 | } | |
| 120 | ||
| 44615 | 121 | def update_perspective(nodes: Document.Nodes, | 
| 122 | name: Document.Node.Name, text_perspective: Text.Perspective) | |
| 44436 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 123 | : (Command.Perspective, Option[Document.Nodes]) = | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 124 |   {
 | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 125 | val node = nodes(name) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 126 | val perspective = command_perspective(node, text_perspective) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 127 | val new_nodes = | 
| 44474 | 128 | if (node.perspective same perspective) None | 
| 46680 | 129 | else Some(nodes + (name -> node.update_perspective(perspective))) | 
| 44436 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 130 | (perspective, new_nodes) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 131 | } | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 132 | |
| 44615 | 133 | def edit_perspective(previous: Document.Version, | 
| 134 | name: Document.Node.Name, text_perspective: Text.Perspective) | |
| 44436 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 135 | : (Command.Perspective, Document.Version) = | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 136 |   {
 | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 137 | val nodes = previous.nodes | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 138 | val (perspective, new_nodes) = update_perspective(nodes, name, text_perspective) | 
| 46941 | 139 | val version = Document.Version.make(previous.syntax, new_nodes getOrElse nodes) | 
| 44436 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 140 | (perspective, version) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 141 | } | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 142 | |
| 44388 | 143 | |
| 144 | ||
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 145 | /** header edits: structure and outer syntax **/ | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 146 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 147 | private def header_edits( | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 148 | base_syntax: Outer_Syntax, | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 149 | previous: Document.Version, | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 150 | edits: List[Document.Edit_Text]) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 151 | : (Outer_Syntax, List[Document.Node.Name], Document.Nodes, List[Document.Edit_Command]) = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 152 |   {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 153 | var rebuild_syntax = previous.is_init | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 154 | var nodes = previous.nodes | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 155 | val doc_edits = new mutable.ListBuffer[Document.Edit_Command] | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 156 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 157 |     edits foreach {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 158 | case (name, Document.Node.Header(header)) => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 159 | val node = nodes(name) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 160 | val update_header = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 161 |           (node.header, header) match {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 162 | case (Exn.Res(deps0), Exn.Res(deps)) => deps0 != deps | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 163 | case _ => true | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 164 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 165 |         if (update_header) {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 166 | val node1 = node.update_header(header) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 167 | rebuild_syntax = rebuild_syntax || (node.keywords != node1.keywords) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 168 | nodes += (name -> node1) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 169 | doc_edits += (name -> Document.Node.Header(header)) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 170 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 171 | case _ => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 172 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 173 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 174 | val syntax = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 175 | if (rebuild_syntax) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 176 |         (base_syntax /: nodes.entries)({ case (syn, (_, node)) => (syn /: node.keywords)(_ + _) })
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 177 | else previous.syntax | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 178 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 179 | val reparse = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 180 | if (rebuild_syntax) nodes.descendants(doc_edits.iterator.map(_._1).toList) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 181 | else Nil | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 182 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 183 | (syntax, reparse, nodes, doc_edits.toList) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 184 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 185 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 186 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 187 | |
| 38374 | 188 | /** text edits **/ | 
| 189 | ||
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 190 | /* phase 1: edit individual command source */ | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 191 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 192 | @tailrec private def edit_text(eds: List[Text.Edit], commands: Linear_Set[Command]) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 193 | : Linear_Set[Command] = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 194 |   {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 195 |     eds match {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 196 | case e :: es => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 197 |         Document.Node.command_starts(commands.iterator).find {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 198 | case (cmd, cmd_start) => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 199 | e.can_edit(cmd.source, cmd_start) || | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 200 | e.is_insert && e.start == cmd_start + cmd.length | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 201 |         } match {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 202 | case Some((cmd, cmd_start)) if e.can_edit(cmd.source, cmd_start) => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 203 | val (rest, text) = e.edit(cmd.source, cmd_start) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 204 | val new_commands = commands.insert_after(Some(cmd), Command.unparsed(text)) - cmd | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 205 | edit_text(rest.toList ::: es, new_commands) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 206 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 207 | case Some((cmd, cmd_start)) => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 208 | edit_text(es, commands.insert_after(Some(cmd), Command.unparsed(e.text))) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 209 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 210 | case None => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 211 | require(e.is_insert && e.start == 0) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 212 | edit_text(es, commands.insert_after(None, Command.unparsed(e.text))) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 213 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 214 | case Nil => commands | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 215 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 216 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 217 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 218 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 219 | /* phase 2: recover command spans */ | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 220 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 221 | @tailrec private def recover_spans( | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 222 | syntax: Outer_Syntax, | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 223 | node_name: Document.Node.Name, | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 224 | commands: Linear_Set[Command]): Linear_Set[Command] = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 225 |   {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 226 |     commands.iterator.find(cmd => !cmd.is_defined) match {
 | 
| 47012 
0e246130486b
clarified command span classification: strict Command.is_command, permissive Command.name;
 wenzelm parents: 
46969diff
changeset | 227 | case Some(first_undefined) => | 
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 228 | val first = | 
| 47012 
0e246130486b
clarified command span classification: strict Command.is_command, permissive Command.name;
 wenzelm parents: 
46969diff
changeset | 229 | commands.reverse_iterator(first_undefined). | 
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 230 | dropWhile(_.newlines == 0).find(_.is_command) getOrElse commands.head | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 231 | val last = | 
| 47012 
0e246130486b
clarified command span classification: strict Command.is_command, permissive Command.name;
 wenzelm parents: 
46969diff
changeset | 232 | commands.iterator(first_undefined). | 
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 233 | dropWhile(_.newlines == 0).find(_.is_command) getOrElse commands.last | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 234 | val range = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 235 | commands.iterator(first).takeWhile(_ != last).toList ::: List(last) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 236 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 237 | val spans0 = parse_spans(syntax.scan(range.map(_.source).mkString)) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 238 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 239 | val (before_edit, spans1) = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 240 | if (!spans0.isEmpty && first.is_command && first.span == spans0.head) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 241 | (Some(first), spans0.tail) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 242 | else (commands.prev(first), spans0) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 243 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 244 | val (after_edit, spans2) = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 245 | if (!spans1.isEmpty && last.is_command && last.span == spans1.last) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 246 | (Some(last), spans1.take(spans1.length - 1)) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 247 | else (commands.next(last), spans1) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 248 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 249 | val inserted = spans2.map(span => Command(Document.new_id(), node_name, span)) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 250 | val new_commands = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 251 | commands.delete_between(before_edit, after_edit).append_after(before_edit, inserted) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 252 | recover_spans(syntax, node_name, new_commands) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 253 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 254 | case None => commands | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 255 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 256 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 257 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 258 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 259 | /* phase 3: full reparsing after syntax change */ | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 260 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 261 | private def reparse_spans( | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 262 | syntax: Outer_Syntax, | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 263 | node_name: Document.Node.Name, | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 264 | commands: Linear_Set[Command]): Linear_Set[Command] = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 265 |   {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 266 | val cmds = commands.toList | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 267 | val spans1 = parse_spans(syntax.scan(cmds.map(_.source).mkString)) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 268 | if (cmds.map(_.span) == spans1) commands | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 269 | else Linear_Set(spans1.map(span => Command(Document.new_id(), node_name, span)): _*) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 270 | } | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 271 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 272 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 273 | /* main phase */ | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 274 | |
| 43722 | 275 | def text_edits( | 
| 46942 
f5c2d66faa04
basic support for outer syntax keywords in theory header;
 wenzelm parents: 
46941diff
changeset | 276 | base_syntax: Outer_Syntax, | 
| 43722 | 277 | previous: Document.Version, | 
| 44157 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 278 | edits: List[Document.Edit_Text]) | 
| 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 279 | : (List[Document.Edit_Command], Document.Version) = | 
| 38374 | 280 |   {
 | 
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 281 | val (syntax, reparse, nodes0, doc_edits0) = header_edits(base_syntax, previous, edits) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 282 | val reparse_set = reparse.toSet | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 283 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 284 | var nodes = nodes0 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 285 | val doc_edits = new mutable.ListBuffer[Document.Edit_Command]; doc_edits ++= doc_edits0 | 
| 38374 | 286 | |
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 287 |     (edits ::: reparse.map((_, Document.Node.Edits(Nil)))) foreach {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 288 | case (name, Document.Node.Clear()) => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 289 | doc_edits += (name -> Document.Node.Clear()) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 290 | nodes += (name -> nodes(name).clear) | 
| 38374 | 291 | |
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 292 | case (name, Document.Node.Edits(text_edits)) => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 293 | val node = nodes(name) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 294 | val commands0 = node.commands | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 295 | val commands1 = edit_text(text_edits, commands0) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 296 | val commands2 = recover_spans(syntax, name, commands1) // FIXME somewhat slow | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 297 | val commands3 = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 298 | if (reparse_set.contains(name)) reparse_spans(syntax, name, commands2) // slow | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 299 | else commands2 | 
| 38374 | 300 | |
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 301 | val removed_commands = commands0.iterator.filter(!commands3.contains(_)).toList | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 302 | val inserted_commands = commands3.iterator.filter(!commands0.contains(_)).toList | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 303 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 304 | val cmd_edits = | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 305 | removed_commands.reverse.map(cmd => (commands0.prev(cmd), None)) ::: | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 306 | inserted_commands.map(cmd => (commands3.prev(cmd), Some(cmd))) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 307 | |
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 308 | doc_edits += (name -> Document.Node.Edits(cmd_edits)) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 309 | nodes += (name -> node.update_commands(commands3)) | 
| 38374 | 310 | |
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 311 | case (name, Document.Node.Header(_)) => | 
| 38374 | 312 | |
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 313 | case (name, Document.Node.Perspective(text_perspective)) => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 314 |         update_perspective(nodes, name, text_perspective) match {
 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 315 | case (_, None) => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 316 | case (perspective, Some(nodes1)) => | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 317 | doc_edits += (name -> Document.Node.Perspective(perspective)) | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 318 | nodes = nodes1 | 
| 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 319 | } | 
| 38374 | 320 | } | 
| 46946 
acc8ebf980ca
more explicit header_edits before main text_edits;
 wenzelm parents: 
46942diff
changeset | 321 | (doc_edits.toList, Document.Version.make(syntax, nodes)) | 
| 38374 | 322 | } | 
| 34268 | 323 | } |