11 import scala.collection.mutable |
11 import scala.collection.mutable |
12 |
12 |
13 |
13 |
14 object Document |
14 object Document |
15 { |
15 { |
16 /* formal identifiers */ |
|
17 |
|
18 type ID = Long |
|
19 val ID = Properties.Value.Long |
|
20 |
|
21 type Version_ID = ID |
|
22 type Command_ID = ID |
|
23 type Exec_ID = ID |
|
24 |
|
25 val no_id: ID = 0 |
|
26 val new_id = Counter() |
|
27 |
|
28 |
|
29 |
|
30 /** document structure **/ |
16 /** document structure **/ |
31 |
17 |
32 /* individual nodes */ |
18 /* individual nodes */ |
33 |
19 |
34 type Edit[A, B] = (Node.Name, Node.Edit[A, B]) |
20 type Edit[A, B] = (Node.Name, Node.Edit[A, B]) |
200 object Version |
186 object Version |
201 { |
187 { |
202 val init: Version = new Version() |
188 val init: Version = new Version() |
203 |
189 |
204 def make(syntax: Outer_Syntax, nodes: Nodes): Version = |
190 def make(syntax: Outer_Syntax, nodes: Nodes): Version = |
205 new Version(new_id(), syntax, nodes) |
191 new Version(Document_ID.make(), syntax, nodes) |
206 } |
192 } |
207 |
193 |
208 final class Version private( |
194 final class Version private( |
209 val id: Version_ID = no_id, |
195 val id: Document_ID.Version = Document_ID.none, |
210 val syntax: Outer_Syntax = Outer_Syntax.empty, |
196 val syntax: Outer_Syntax = Outer_Syntax.empty, |
211 val nodes: Nodes = Nodes.empty) |
197 val nodes: Nodes = Nodes.empty) |
212 { |
198 { |
213 def is_init: Boolean = id == no_id |
199 def is_init: Boolean = id == Document_ID.none |
214 } |
200 } |
215 |
201 |
216 |
202 |
217 /* changes of plain text, eventually resulting in document edits */ |
203 /* changes of plain text, eventually resulting in document edits */ |
218 |
204 |
287 range: Text.Range, |
273 range: Text.Range, |
288 elements: Option[Set[String]], |
274 elements: Option[Set[String]], |
289 result: Command.State => PartialFunction[Text.Markup, A]): Stream[Text.Info[A]] |
275 result: Command.State => PartialFunction[Text.Markup, A]): Stream[Text.Info[A]] |
290 } |
276 } |
291 |
277 |
292 type Assign = List[(Document.Command_ID, List[Document.Exec_ID])] // exec state assignment |
278 type Assign = List[(Document_ID.Command, List[Document_ID.Exec])] // exec state assignment |
293 |
279 |
294 object State |
280 object State |
295 { |
281 { |
296 class Fail(state: State) extends Exception |
282 class Fail(state: State) extends Exception |
297 |
283 |
299 { |
285 { |
300 val init: Assignment = new Assignment() |
286 val init: Assignment = new Assignment() |
301 } |
287 } |
302 |
288 |
303 final class Assignment private( |
289 final class Assignment private( |
304 val command_execs: Map[Command_ID, List[Exec_ID]] = Map.empty, |
290 val command_execs: Map[Document_ID.Command, List[Document_ID.Exec]] = Map.empty, |
305 val is_finished: Boolean = false) |
291 val is_finished: Boolean = false) |
306 { |
292 { |
307 def check_finished: Assignment = { require(is_finished); this } |
293 def check_finished: Assignment = { require(is_finished); this } |
308 def unfinished: Assignment = new Assignment(command_execs, false) |
294 def unfinished: Assignment = new Assignment(command_execs, false) |
309 |
295 |
310 def assign(add_command_execs: List[(Command_ID, List[Exec_ID])]): Assignment = |
296 def assign( |
|
297 add_command_execs: List[(Document_ID.Command, List[Document_ID.Exec])]): Assignment = |
311 { |
298 { |
312 require(!is_finished) |
299 require(!is_finished) |
313 val command_execs1 = |
300 val command_execs1 = |
314 (command_execs /: add_command_execs) { |
301 (command_execs /: add_command_execs) { |
315 case (res, (command_id, Nil)) => res - command_id |
302 case (res, (command_id, Nil)) => res - command_id |
322 val init: State = |
309 val init: State = |
323 State().define_version(Version.init, Assignment.init).assign(Version.init.id)._2 |
310 State().define_version(Version.init, Assignment.init).assign(Version.init.id)._2 |
324 } |
311 } |
325 |
312 |
326 final case class State private( |
313 final case class State private( |
327 val versions: Map[Version_ID, Version] = Map.empty, |
314 val versions: Map[Document_ID.Version, Version] = Map.empty, |
328 val commands: Map[Command_ID, Command.State] = Map.empty, // static markup from define_command |
315 val commands: Map[Document_ID.Command, Command.State] = Map.empty, // static markup from define_command |
329 val execs: Map[Exec_ID, Command.State] = Map.empty, // dynamic markup from execution |
316 val execs: Map[Document_ID.Exec, Command.State] = Map.empty, // dynamic markup from execution |
330 val assignments: Map[Version_ID, State.Assignment] = Map.empty, |
317 val assignments: Map[Document_ID.Version, State.Assignment] = Map.empty, |
331 val history: History = History.init) |
318 val history: History = History.init) |
332 { |
319 { |
333 private def fail[A]: A = throw new State.Fail(this) |
320 private def fail[A]: A = throw new State.Fail(this) |
334 |
321 |
335 def define_version(version: Version, assignment: State.Assignment): State = |
322 def define_version(version: Version, assignment: State.Assignment): State = |
343 { |
330 { |
344 val id = command.id |
331 val id = command.id |
345 copy(commands = commands + (id -> command.init_state)) |
332 copy(commands = commands + (id -> command.init_state)) |
346 } |
333 } |
347 |
334 |
348 def defined_command(id: Command_ID): Boolean = commands.isDefinedAt(id) |
335 def defined_command(id: Document_ID.Command): Boolean = commands.isDefinedAt(id) |
349 |
336 |
350 def find_command(version: Version, id: ID): Option[(Node, Command)] = |
337 def find_command(version: Version, id: Document_ID.ID): Option[(Node, Command)] = |
351 commands.get(id) orElse execs.get(id) match { |
338 commands.get(id) orElse execs.get(id) match { |
352 case None => None |
339 case None => None |
353 case Some(st) => |
340 case Some(st) => |
354 val command = st.command |
341 val command = st.command |
355 val node = version.nodes(command.node_name) |
342 val node = version.nodes(command.node_name) |
356 Some((node, command)) |
343 Some((node, command)) |
357 } |
344 } |
358 |
345 |
359 def the_version(id: Version_ID): Version = versions.getOrElse(id, fail) |
346 def the_version(id: Document_ID.Version): Version = versions.getOrElse(id, fail) |
360 def the_read_state(id: Command_ID): Command.State = commands.getOrElse(id, fail) |
347 def the_read_state(id: Document_ID.Command): Command.State = commands.getOrElse(id, fail) |
361 def the_exec_state(id: Exec_ID): Command.State = execs.getOrElse(id, fail) |
348 def the_exec_state(id: Document_ID.Exec): Command.State = execs.getOrElse(id, fail) |
362 def the_assignment(version: Version): State.Assignment = |
349 def the_assignment(version: Version): State.Assignment = |
363 assignments.getOrElse(version.id, fail) |
350 assignments.getOrElse(version.id, fail) |
364 |
351 |
365 def accumulate(id: ID, message: XML.Elem): (Command.State, State) = |
352 def accumulate(id: Document_ID.ID, message: XML.Elem): (Command.State, State) = |
366 execs.get(id) match { |
353 execs.get(id) match { |
367 case Some(st) => |
354 case Some(st) => |
368 val new_st = st + (id, message) |
355 val new_st = st + (id, message) |
369 (new_st, copy(execs = execs + (id -> new_st))) |
356 (new_st, copy(execs = execs + (id -> new_st))) |
370 case None => |
357 case None => |
374 (new_st, copy(commands = commands + (id -> new_st))) |
361 (new_st, copy(commands = commands + (id -> new_st))) |
375 case None => fail |
362 case None => fail |
376 } |
363 } |
377 } |
364 } |
378 |
365 |
379 def assign(id: Version_ID, command_execs: Assign = Nil): (List[Command], State) = |
366 def assign(id: Document_ID.Version, command_execs: Assign = Nil): (List[Command], State) = |
380 { |
367 { |
381 val version = the_version(id) |
368 val version = the_version(id) |
382 |
369 |
383 val (changed_commands, new_execs) = |
370 val (changed_commands, new_execs) = |
384 ((Nil: List[Command], execs) /: command_execs) { |
371 ((Nil: List[Command], execs) /: command_execs) { |
435 (dropped_versions, state1) |
422 (dropped_versions, state1) |
436 case None => fail |
423 case None => fail |
437 } |
424 } |
438 } |
425 } |
439 |
426 |
440 def removed_versions(removed: List[Version_ID]): State = |
427 def removed_versions(removed: List[Document_ID.Version]): State = |
441 { |
428 { |
442 val versions1 = versions -- removed |
429 val versions1 = versions -- removed |
443 val assignments1 = assignments -- removed |
430 val assignments1 = assignments -- removed |
444 var commands1 = Map.empty[Command_ID, Command.State] |
431 var commands1 = Map.empty[Document_ID.Command, Command.State] |
445 var execs1 = Map.empty[Exec_ID, Command.State] |
432 var execs1 = Map.empty[Document_ID.Exec, Command.State] |
446 for { |
433 for { |
447 (version_id, version) <- versions1.iterator |
434 (version_id, version) <- versions1.iterator |
448 command_execs = assignments1(version_id).command_execs |
435 command_execs = assignments1(version_id).command_execs |
449 (_, node) <- version.nodes.entries |
436 (_, node) <- version.nodes.entries |
450 command <- node.commands.iterator |
437 command <- node.commands.iterator |