25 |
25 |
26 fun err_dup kind id = error ("Duplicate " ^ kind ^ ": " ^ Document.print_id id); |
26 fun err_dup kind id = error ("Duplicate " ^ kind ^ ": " ^ Document.print_id id); |
27 fun err_undef kind id = error ("Undefined " ^ kind ^ ": " ^ Document.print_id id); |
27 fun err_undef kind id = error ("Undefined " ^ kind ^ ": " ^ Document.print_id id); |
28 |
28 |
29 |
29 |
30 (** documents **) |
30 (** document versions **) |
31 |
31 |
32 datatype entry = Entry of {next: Document.command_id option, exec: Document.exec_id option}; |
32 datatype entry = Entry of {next: Document.command_id option, exec: Document.exec_id option}; |
33 type node = entry Inttab.table; (*unique command entries indexed by command_id, start with no_id*) |
33 type node = entry Inttab.table; (*unique command entries indexed by command_id, start with no_id*) |
34 type document = node Graph.T; (*development graph via static imports*) |
34 type version = node Graph.T; (*development graph via static imports*) |
35 |
35 |
36 |
36 |
37 (* command entries *) |
37 (* command entries *) |
38 |
38 |
39 fun make_entry next exec = Entry {next = next, exec = exec}; |
39 fun make_entry next exec = Entry {next = next, exec = exec}; |
95 |
95 |
96 (* node operations *) |
96 (* node operations *) |
97 |
97 |
98 val empty_node: node = Inttab.make [(Document.no_id, make_entry NONE (SOME Document.no_id))]; |
98 val empty_node: node = Inttab.make [(Document.no_id, make_entry NONE (SOME Document.no_id))]; |
99 |
99 |
100 fun the_node (document: document) name = |
100 fun the_node (version: version) name = |
101 Graph.get_node document name handle Graph.UNDEF _ => empty_node; |
101 Graph.get_node version name handle Graph.UNDEF _ => empty_node; |
102 |
102 |
103 fun edit_node (id, SOME id2) = insert_after id id2 |
103 fun edit_node (id, SOME id2) = insert_after id id2 |
104 | edit_node (id, NONE) = delete_after id; |
104 | edit_node (id, NONE) = delete_after id; |
105 |
105 |
106 fun edit_nodes (name, SOME edits) = |
106 fun edit_nodes (name, SOME edits) = |
164 |
164 |
165 (* document versions *) |
165 (* document versions *) |
166 |
166 |
167 local |
167 local |
168 |
168 |
169 val global_documents = Unsynchronized.ref (Inttab.make [(Document.no_id, Graph.empty: document)]); |
169 val global_versions = Unsynchronized.ref (Inttab.make [(Document.no_id, Graph.empty: version)]); |
170 |
170 |
171 in |
171 in |
172 |
172 |
173 fun define_document (id: Document.version_id) document = |
173 fun define_version (id: Document.version_id) version = |
174 NAMED_CRITICAL "Isar" (fn () => |
174 NAMED_CRITICAL "Isar" (fn () => |
175 Unsynchronized.change global_documents (Inttab.update_new (id, document)) |
175 Unsynchronized.change global_versions (Inttab.update_new (id, version)) |
176 handle Inttab.DUP dup => err_dup "document" dup); |
176 handle Inttab.DUP dup => err_dup "version" dup); |
177 |
177 |
178 fun the_document (id: Document.version_id) = |
178 fun the_version (id: Document.version_id) = |
179 (case Inttab.lookup (! global_documents) id of |
179 (case Inttab.lookup (! global_versions) id of |
180 NONE => err_undef "document" id |
180 NONE => err_undef "version" id |
181 | SOME document => document); |
181 | SOME version => version); |
182 |
182 |
183 end; |
183 end; |
184 |
184 |
185 |
185 |
186 |
186 |
195 fun force_exec NONE = () |
195 fun force_exec NONE = () |
196 | force_exec (SOME exec_id) = ignore (Lazy.force (the_exec exec_id)); |
196 | force_exec (SOME exec_id) = ignore (Lazy.force (the_exec exec_id)); |
197 |
197 |
198 in |
198 in |
199 |
199 |
200 fun execute document = |
200 fun execute version = |
201 NAMED_CRITICAL "Isar" (fn () => |
201 NAMED_CRITICAL "Isar" (fn () => |
202 let |
202 let |
203 val old_execution = ! execution; |
203 val old_execution = ! execution; |
204 val _ = List.app Future.cancel old_execution; |
204 val _ = List.app Future.cancel old_execution; |
205 fun await_cancellation () = uninterruptible (K Future.join_results) old_execution; |
205 fun await_cancellation () = uninterruptible (K Future.join_results) old_execution; |
206 (* FIXME proper node deps *) |
206 (* FIXME proper node deps *) |
207 val new_execution = Graph.keys document |> map (fn name => |
207 val new_execution = Graph.keys version |> map (fn name => |
208 Future.fork_pri 1 (fn () => |
208 Future.fork_pri 1 (fn () => |
209 let |
209 let |
210 val _ = await_cancellation (); |
210 val _ = await_cancellation (); |
211 val exec = |
211 val exec = |
212 fold_entries Document.no_id (fn (_, {exec, ...}) => fn () => force_exec exec) |
212 fold_entries Document.no_id (fn (_, {exec, ...}) => fn () => force_exec exec) |
213 (the_node document name); |
213 (the_node version name); |
214 in exec () end)); |
214 in exec () end)); |
215 in execution := new_execution end); |
215 in execution := new_execution end); |
216 |
216 |
217 end; |
217 end; |
218 |
218 |
247 in |
247 in |
248 |
248 |
249 fun edit_document (old_id: Document.version_id) (new_id: Document.version_id) edits = |
249 fun edit_document (old_id: Document.version_id) (new_id: Document.version_id) edits = |
250 NAMED_CRITICAL "Isar" (fn () => |
250 NAMED_CRITICAL "Isar" (fn () => |
251 let |
251 let |
252 val old_document = the_document old_id; |
252 val old_version = the_version old_id; |
253 val new_document = fold edit_nodes edits old_document; |
253 val new_version = fold edit_nodes edits old_version; |
254 |
254 |
255 fun update_node name node = |
255 fun update_node name node = |
256 (case first_entry (is_changed (the_node old_document name)) node of |
256 (case first_entry (is_changed (the_node old_version name)) node of |
257 NONE => ([], node) |
257 NONE => ([], node) |
258 | SOME (prev, id, _) => |
258 | SOME (prev, id, _) => |
259 let |
259 let |
260 val prev_exec_id = the (#exec (the_entry node (the prev))); |
260 val prev_exec_id = the (#exec (the_entry node (the prev))); |
261 val (_, updates) = fold_entries id (new_exec name o #1) node (prev_exec_id, []); |
261 val (_, updates) = fold_entries id (new_exec name o #1) node (prev_exec_id, []); |
262 val node' = fold set_entry_exec updates node; |
262 val node' = fold set_entry_exec updates node; |
263 in (rev updates, node') end); |
263 in (rev updates, node') end); |
264 |
264 |
265 (* FIXME proper node deps *) |
265 (* FIXME proper node deps *) |
266 val (updatess, new_document') = |
266 val (updatess, new_version') = |
267 (Graph.keys new_document, new_document) |
267 (Graph.keys new_version, new_version) |
268 |-> fold_map (fn name => Graph.map_node_yield name (update_node name)); |
268 |-> fold_map (fn name => Graph.map_node_yield name (update_node name)); |
269 |
269 |
270 val _ = define_document new_id new_document'; |
270 val _ = define_version new_id new_version'; |
271 val _ = updates_status new_id (flat updatess); |
271 val _ = updates_status new_id (flat updatess); |
272 val _ = execute new_document'; |
272 val _ = execute new_version'; |
273 in () end); |
273 in () end); |
274 |
274 |
275 end; |
275 end; |
276 |
276 |
277 |
277 |
281 val _ = |
281 val _ = |
282 Isabelle_Process.add_command "Isar_Document.define_command" |
282 Isabelle_Process.add_command "Isar_Document.define_command" |
283 (fn [id, text] => define_command (Document.parse_id id) text); |
283 (fn [id, text] => define_command (Document.parse_id id) text); |
284 |
284 |
285 val _ = |
285 val _ = |
286 Isabelle_Process.add_command "Isar_Document.edit_document" |
286 Isabelle_Process.add_command "Isar_Document.edit_version" |
287 (fn [old_id, new_id, edits] => |
287 (fn [old_id, new_id, edits] => |
288 edit_document (Document.parse_id old_id) (Document.parse_id new_id) |
288 edit_document (Document.parse_id old_id) (Document.parse_id new_id) |
289 (XML_Data.dest_list (XML_Data.dest_pair XML_Data.dest_string |
289 (XML_Data.dest_list (XML_Data.dest_pair XML_Data.dest_string |
290 (XML_Data.dest_option (XML_Data.dest_list |
290 (XML_Data.dest_option (XML_Data.dest_list |
291 (XML_Data.dest_pair XML_Data.dest_int |
291 (XML_Data.dest_pair XML_Data.dest_int |