| author | huffman | 
| Thu, 25 Aug 2011 16:50:55 -0700 | |
| changeset 44530 | adb18b07b341 | 
| parent 44443 | 35d67b2056cc | 
| child 44473 | 4f264fdf8d0e | 
| 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 | |
| 40792 | 30 | def parse(syntax: Outer_Syntax, root_name: String, 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] | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 35 | var stack: List[(Int, String, mutable.ListBuffer[Entry])] = List((0, root_name, buffer())) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 36 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 37 | @tailrec def close(level: Int => Boolean) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 38 |       {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 39 |         stack match {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 40 | case (lev, name, body) :: (_, _, body2) :: rest if level(lev) => | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 41 | body2 += Block(name, body.toList) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 42 | stack = stack.tail | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 43 | close(level) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 44 | case _ => | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 45 | } | 
| 
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 | def result(): Entry = | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 49 |       {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 50 | close(_ => true) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 51 | val (_, name, body) = stack.head | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 52 | Block(name, body.toList) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 53 | } | 
| 
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 | def add(command: Command) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 56 |       {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 57 |         syntax.heading_level(command) match {
 | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 58 | case Some(i) => | 
| 40457 | 59 | close(_ >= i) | 
| 40454 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 60 | stack = (i, command.source, buffer()) :: stack | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 61 | case None => | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 62 | } | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 63 | stack.head._3 += Atom(command) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 64 | } | 
| 
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 | /* result structure */ | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 68 | |
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 69 | val spans = parse_spans(syntax.scan(text)) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 70 | spans.foreach(span => add(Command.span(span))) | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 71 | result() | 
| 
2516ea25a54b
some support for nested source structure, based on section headings;
 wenzelm parents: 
38878diff
changeset | 72 | } | 
| 
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 | |
| 38374 | 77 | /** parse spans **/ | 
| 78 | ||
| 38373 | 79 | def parse_spans(toks: List[Token]): List[List[Token]] = | 
| 34268 | 80 |   {
 | 
| 38373 | 81 | val result = new mutable.ListBuffer[List[Token]] | 
| 38239 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 82 | val span = new mutable.ListBuffer[Token] | 
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 83 | val whitespace = new mutable.ListBuffer[Token] | 
| 34268 | 84 | |
| 38239 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 85 | def flush(buffer: mutable.ListBuffer[Token]) | 
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 86 |     {
 | 
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 87 |       if (!buffer.isEmpty) { result += buffer.toList; buffer.clear }
 | 
| 34268 | 88 | } | 
| 38239 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 89 |     for (tok <- toks) {
 | 
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 90 |       if (tok.is_command) { flush(span); flush(whitespace); span += tok }
 | 
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 91 | else if (tok.is_ignored) whitespace += tok | 
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 92 |       else { span ++= whitespace; whitespace.clear; span += tok }
 | 
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 93 | } | 
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 94 | flush(span); flush(whitespace) | 
| 
89a4d1028fb3
parse_spans: somewhat faster low-level implementation;
 wenzelm parents: 
36956diff
changeset | 95 | result.toList | 
| 34268 | 96 | } | 
| 38374 | 97 | |
| 98 | ||
| 99 | ||
| 44436 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 100 | /** perspective **/ | 
| 44388 | 101 | |
| 102 | def command_perspective(node: Document.Node, perspective: Text.Perspective): Command.Perspective = | |
| 103 |   {
 | |
| 104 | if (perspective.isEmpty) Nil | |
| 105 |     else {
 | |
| 106 | val result = new mutable.ListBuffer[Command] | |
| 107 | @tailrec | |
| 108 | def check_ranges(ranges: List[Text.Range], commands: Stream[(Command, Text.Offset)]) | |
| 109 |       {
 | |
| 110 |         (ranges, commands) match {
 | |
| 111 | case (range :: more_ranges, (command, offset) #:: more_commands) => | |
| 112 | val command_range = command.range + offset | |
| 113 |             range compare command_range match {
 | |
| 114 | case -1 => check_ranges(more_ranges, commands) | |
| 115 | case 0 => | |
| 116 | result += command | |
| 117 | check_ranges(ranges, more_commands) | |
| 118 | case 1 => check_ranges(ranges, more_commands) | |
| 119 | } | |
| 120 | case _ => | |
| 121 | } | |
| 122 | } | |
| 123 | val perspective_range = Text.Range(perspective.head.start, perspective.last.stop) | |
| 124 | check_ranges(perspective, node.command_range(perspective_range).toStream) | |
| 125 | result.toList | |
| 126 | } | |
| 127 | } | |
| 128 | ||
| 44436 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 129 | def update_perspective(nodes: Document.Nodes, name: String, text_perspective: Text.Perspective) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 130 | : (Command.Perspective, Option[Document.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 | val node = nodes(name) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 133 | val perspective = command_perspective(node, text_perspective) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 134 | val new_nodes = | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 135 | if (Command.equal_perspective(node.perspective, perspective)) None | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 136 | else Some(nodes + (name -> node.copy(perspective = perspective))) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 137 | (perspective, new_nodes) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 138 | } | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 139 | |
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 140 | def edit_perspective(previous: Document.Version, name: String, text_perspective: Text.Perspective) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 141 | : (Command.Perspective, Document.Version) = | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 142 |   {
 | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 143 | val nodes = previous.nodes | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 144 | val (perspective, new_nodes) = update_perspective(nodes, name, text_perspective) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 145 | val version = Document.Version(Document.new_id(), new_nodes getOrElse nodes) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 146 | (perspective, version) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 147 | } | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 148 | |
| 44388 | 149 | |
| 150 | ||
| 38374 | 151 | /** text edits **/ | 
| 152 | ||
| 43722 | 153 | def text_edits( | 
| 154 | syntax: Outer_Syntax, | |
| 155 | previous: Document.Version, | |
| 44157 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 156 | edits: List[Document.Edit_Text]) | 
| 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 157 | : (List[Document.Edit_Command], Document.Version) = | 
| 38374 | 158 |   {
 | 
| 159 | /* phase 1: edit individual command source */ | |
| 160 | ||
| 38425 | 161 | @tailrec def edit_text(eds: List[Text.Edit], commands: Linear_Set[Command]) | 
| 38374 | 162 | : Linear_Set[Command] = | 
| 163 |     {
 | |
| 164 |       eds match {
 | |
| 165 | case e :: es => | |
| 166 |           Document.Node.command_starts(commands.iterator).find {
 | |
| 167 | case (cmd, cmd_start) => | |
| 168 | e.can_edit(cmd.source, cmd_start) || | |
| 169 | e.is_insert && e.start == cmd_start + cmd.length | |
| 170 |           } match {
 | |
| 171 | case Some((cmd, cmd_start)) if e.can_edit(cmd.source, cmd_start) => | |
| 172 | val (rest, text) = e.edit(cmd.source, cmd_start) | |
| 173 | val new_commands = commands.insert_after(Some(cmd), Command.unparsed(text)) - cmd | |
| 174 | edit_text(rest.toList ::: es, new_commands) | |
| 175 | ||
| 176 | case Some((cmd, cmd_start)) => | |
| 177 | edit_text(es, commands.insert_after(Some(cmd), Command.unparsed(e.text))) | |
| 178 | ||
| 179 | case None => | |
| 180 | require(e.is_insert && e.start == 0) | |
| 181 | edit_text(es, commands.insert_after(None, Command.unparsed(e.text))) | |
| 182 | } | |
| 183 | case Nil => commands | |
| 184 | } | |
| 185 | } | |
| 186 | ||
| 187 | ||
| 188 | /* phase 2: recover command spans */ | |
| 189 | ||
| 190 | @tailrec def recover_spans(commands: Linear_Set[Command]): Linear_Set[Command] = | |
| 191 |     {
 | |
| 44385 
e7fdb008aa7d
propagate editor perspective through document model;
 wenzelm parents: 
44185diff
changeset | 192 |       commands.iterator.find(cmd => !cmd.is_defined) match {
 | 
| 38374 | 193 | case Some(first_unparsed) => | 
| 194 | val first = | |
| 38878 
1d5b3175fd30
text_edits/recover_spans: reparse at least until line boundary -- increases chance of recovery for bad ML text, for example;
 wenzelm parents: 
38569diff
changeset | 195 | commands.reverse_iterator(first_unparsed). | 
| 
1d5b3175fd30
text_edits/recover_spans: reparse at least until line boundary -- increases chance of recovery for bad ML text, for example;
 wenzelm parents: 
38569diff
changeset | 196 | dropWhile(_.newlines == 0).find(_.is_command) getOrElse commands.head | 
| 38374 | 197 | val last = | 
| 38878 
1d5b3175fd30
text_edits/recover_spans: reparse at least until line boundary -- increases chance of recovery for bad ML text, for example;
 wenzelm parents: 
38569diff
changeset | 198 | commands.iterator(first_unparsed). | 
| 
1d5b3175fd30
text_edits/recover_spans: reparse at least until line boundary -- increases chance of recovery for bad ML text, for example;
 wenzelm parents: 
38569diff
changeset | 199 | dropWhile(_.newlines == 0).find(_.is_command) getOrElse commands.last | 
| 38374 | 200 | val range = | 
| 201 | commands.iterator(first).takeWhile(_ != last).toList ::: List(last) | |
| 202 | ||
| 203 | val sources = range.flatMap(_.span.map(_.source)) | |
| 43647 | 204 | val spans0 = parse_spans(syntax.scan(sources.mkString)) | 
| 38374 | 205 | |
| 206 | val (before_edit, spans1) = | |
| 207 | if (!spans0.isEmpty && first.is_command && first.span == spans0.head) | |
| 208 | (Some(first), spans0.tail) | |
| 209 | else (commands.prev(first), spans0) | |
| 210 | ||
| 211 | val (after_edit, spans2) = | |
| 212 | if (!spans1.isEmpty && last.is_command && last.span == spans1.last) | |
| 213 | (Some(last), spans1.take(spans1.length - 1)) | |
| 214 | else (commands.next(last), spans1) | |
| 215 | ||
| 43662 
e3175ec00311
Document.no_id/new_id as in ML (new_id *could* be session-specific but it isn't right now);
 wenzelm parents: 
43660diff
changeset | 216 | val inserted = spans2.map(span => new Command(Document.new_id(), span)) | 
| 38374 | 217 | val new_commands = | 
| 218 | commands.delete_between(before_edit, after_edit).append_after(before_edit, inserted) | |
| 219 | recover_spans(new_commands) | |
| 220 | ||
| 221 | case None => commands | |
| 222 | } | |
| 223 | } | |
| 224 | ||
| 225 | ||
| 226 | /* resulting document edits */ | |
| 227 | ||
| 228 |     {
 | |
| 40479 | 229 | val doc_edits = new mutable.ListBuffer[Document.Edit_Command] | 
| 38417 | 230 | var nodes = previous.nodes | 
| 38374 | 231 | |
| 40478 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 232 |       edits foreach {
 | 
| 44185 | 233 | case (name, Document.Node.Clear()) => | 
| 234 | doc_edits += (name -> Document.Node.Clear()) | |
| 44443 
35d67b2056cc
clarified Document.Node.clear -- retain header (cf. ML version);
 wenzelm parents: 
44436diff
changeset | 235 | nodes += (name -> nodes(name).clear) | 
| 40478 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 236 | |
| 44156 | 237 | case (name, Document.Node.Edits(text_edits)) => | 
| 43697 
77ce24aa1770
explicit Document.Node.Header, with master_dir and thy_name;
 wenzelm parents: 
43662diff
changeset | 238 | val node = nodes(name) | 
| 
77ce24aa1770
explicit Document.Node.Header, with master_dir and thy_name;
 wenzelm parents: 
43662diff
changeset | 239 | val commands0 = node.commands | 
| 40478 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 240 | val commands1 = edit_text(text_edits, commands0) | 
| 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 241 | val commands2 = recover_spans(commands1) // FIXME somewhat slow | 
| 38374 | 242 | |
| 40478 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 243 | val removed_commands = commands0.iterator.filter(!commands2.contains(_)).toList | 
| 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 244 | val inserted_commands = commands2.iterator.filter(!commands0.contains(_)).toList | 
| 38374 | 245 | |
| 40478 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 246 | val cmd_edits = | 
| 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 247 | removed_commands.reverse.map(cmd => (commands0.prev(cmd), None)) ::: | 
| 
4bae781b8f7c
replaced Document.Node_Text_Edit by Document.Text_Edit, with treatment of deleted nodes;
 wenzelm parents: 
40457diff
changeset | 248 | inserted_commands.map(cmd => (commands2.prev(cmd), Some(cmd))) | 
| 38374 | 249 | |
| 44156 | 250 | doc_edits += (name -> Document.Node.Edits(cmd_edits)) | 
| 44157 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 251 | nodes += (name -> node.copy(commands = commands2)) | 
| 43722 | 252 | |
| 44182 | 253 | case (name, Document.Node.Header(header)) => | 
| 44157 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 254 | val node = nodes(name) | 
| 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 255 | val update_header = | 
| 44182 | 256 |             (node.header, header) match {
 | 
| 257 | case (Exn.Res(thy_header0), Exn.Res(thy_header)) => thy_header0 != thy_header | |
| 44160 
8848867501fb
clarified document model header: master_dir (native wrt. editor, potentially URL) and node_name (full canonical path);
 wenzelm parents: 
44157diff
changeset | 258 | case _ => true | 
| 44157 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 259 | } | 
| 44180 | 260 |           if (update_header) {
 | 
| 44182 | 261 | doc_edits += (name -> Document.Node.Header(header)) | 
| 44180 | 262 | nodes += (name -> node.copy(header = header)) | 
| 263 | } | |
| 44385 
e7fdb008aa7d
propagate editor perspective through document model;
 wenzelm parents: 
44185diff
changeset | 264 | |
| 
e7fdb008aa7d
propagate editor perspective through document model;
 wenzelm parents: 
44185diff
changeset | 265 | case (name, Document.Node.Perspective(text_perspective)) => | 
| 44436 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 266 |           update_perspective(nodes, name, text_perspective) match {
 | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 267 | case (_, None) => | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 268 | case (perspective, Some(nodes1)) => | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 269 | doc_edits += (name -> Document.Node.Perspective(perspective)) | 
| 
546adfa8a6fc
update_perspective without actual edits, bypassing the full state assignment protocol;
 wenzelm parents: 
44388diff
changeset | 270 | nodes = nodes1 | 
| 44385 
e7fdb008aa7d
propagate editor perspective through document model;
 wenzelm parents: 
44185diff
changeset | 271 | } | 
| 38374 | 272 | } | 
| 44157 
a21d3e1e64fd
uniform treatment of header edits as document edits;
 wenzelm parents: 
44156diff
changeset | 273 | (doc_edits.toList, Document.Version(Document.new_id(), nodes)) | 
| 38374 | 274 | } | 
| 275 | } | |
| 34268 | 276 | } |