| author | wenzelm | 
| Sun, 15 Nov 2009 15:14:02 +0100 | |
| changeset 33696 | 2c7c79ca6c23 | 
| parent 33223 | d27956b4d3b4 | 
| child 34206 | c29264a16ad8 | 
| permissions | -rw-r--r-- | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 1 | (* Title: Pure/Isar/isar_document.ML | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 2 | Author: Makarius | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 3 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 4 | Interactive Isar documents. | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 5 | *) | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 6 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 7 | signature ISAR_DOCUMENT = | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 8 | sig | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 9 | type state_id = string | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 10 | type command_id = string | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 11 | type document_id = string | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 12 | val define_command: command_id -> Toplevel.transition -> unit | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 13 | val begin_document: document_id -> Path.T -> unit | 
| 29468 | 14 | val end_document: document_id -> unit | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 15 | val edit_document: document_id -> document_id -> (command_id * command_id option) list -> unit | 
| 32793 | 16 | val init: unit -> unit | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 17 | end; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 18 | |
| 32467 | 19 | structure Isar_Document: ISAR_DOCUMENT = | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 20 | struct | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 21 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 22 | (* unique identifiers *) | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 23 | |
| 29484 | 24 | type state_id = string; | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 25 | type command_id = string; | 
| 29484 | 26 | type document_id = string; | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 27 | |
| 31443 | 28 | fun make_id () = "i" ^ serial_string (); | 
| 29467 | 29 | |
| 30 | fun err_dup kind id = error ("Duplicate " ^ kind ^ ": " ^ quote id);
 | |
| 31 | fun err_undef kind id = error ("Unknown " ^ kind ^ ": " ^ quote id);
 | |
| 32 | ||
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 33 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 34 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 35 | (** documents **) | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 36 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 37 | (* command entries *) | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 38 | |
| 29484 | 39 | datatype entry = Entry of {next: command_id option, state: state_id option};
 | 
| 40 | fun make_entry next state = Entry {next = next, state = state};
 | |
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 41 | |
| 29467 | 42 | fun the_entry entries (id: command_id) = | 
| 43 | (case Symtab.lookup entries id of | |
| 44 | NONE => err_undef "document entry" id | |
| 45 | | SOME (Entry entry) => entry); | |
| 46 | ||
| 47 | fun put_entry (id: command_id, entry: entry) = Symtab.update (id, entry); | |
| 48 | ||
| 29489 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 49 | fun put_entry_state (id: command_id) state entries = | 
| 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 50 |   let val {next, ...} = the_entry entries id
 | 
| 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 51 | in put_entry (id, make_entry next state) entries end; | 
| 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 52 | |
| 29490 | 53 | fun reset_entry_state id = put_entry_state id NONE; | 
| 54 | fun set_entry_state (id, state_id) = put_entry_state id (SOME state_id); | |
| 29489 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 55 | |
| 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 56 | |
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 57 | (* document *) | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 58 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 59 | datatype document = Document of | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 60 |  {dir: Path.T,                    (*master directory*)
 | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 61 | name: string, (*theory name*) | 
| 29467 | 62 | start: command_id, (*empty start command*) | 
| 63 | entries: entry Symtab.table}; (*unique command entries indexed by command_id*) | |
| 64 | ||
| 65 | fun make_document dir name start entries = | |
| 66 |   Document {dir = dir, name = name, start = start, entries = entries};
 | |
| 67 | ||
| 68 | fun map_entries f (Document {dir, name, start, entries}) =
 | |
| 69 | make_document dir name start (f entries); | |
| 70 | ||
| 71 | ||
| 29484 | 72 | (* iterate entries *) | 
| 29468 | 73 | |
| 29507 | 74 | fun fold_entries id0 f (Document {entries, ...}) =
 | 
| 29468 | 75 | let | 
| 76 | fun apply NONE x = x | |
| 29507 | 77 | | apply (SOME id) x = | 
| 78 | let val entry = the_entry entries id | |
| 79 | in apply (#next entry) (f (id, entry) x) end; | |
| 80 | in if Symtab.defined entries id0 then apply (SOME id0) else I end; | |
| 29468 | 81 | |
| 29507 | 82 | fun first_entry P (Document {start, entries, ...}) =
 | 
| 29467 | 83 | let | 
| 29517 | 84 | fun first _ NONE = NONE | 
| 85 | | first prev (SOME id) = | |
| 29507 | 86 | let val entry = the_entry entries id | 
| 29519 | 87 | in if P (id, entry) then SOME (prev, id, entry) else first (SOME id) (#next entry) end; | 
| 29517 | 88 | in first NONE (SOME start) end; | 
| 29468 | 89 | |
| 90 | ||
| 91 | (* modify entries *) | |
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 92 | |
| 29484 | 93 | fun insert_after (id: command_id) (id2: command_id) = map_entries (fn entries => | 
| 94 |   let val {next, state} = the_entry entries id in
 | |
| 95 | entries | |
| 96 | |> put_entry (id, make_entry (SOME id2) state) | |
| 97 | |> put_entry (id2, make_entry next NONE) | |
| 29467 | 98 | end); | 
| 99 | ||
| 29468 | 100 | fun delete_after (id: command_id) = map_entries (fn entries => | 
| 29484 | 101 |   let val {next, state} = the_entry entries id in
 | 
| 102 | (case next of | |
| 103 |       NONE => error ("No next entry to delete: " ^ quote id)
 | |
| 104 | | SOME id2 => | |
| 105 | entries |> | |
| 29467 | 106 | (case #next (the_entry entries id2) of | 
| 29484 | 107 | NONE => put_entry (id, make_entry NONE state) | 
| 29490 | 108 | | SOME id3 => put_entry (id, make_entry (SOME id3) state) #> reset_entry_state id3)) | 
| 29467 | 109 | end); | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 110 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 111 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 112 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 113 | (** global configuration **) | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 114 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 115 | local | 
| 32738 | 116 | val global_states = Unsynchronized.ref (Symtab.empty: Toplevel.state option future Symtab.table); | 
| 117 | val global_commands = Unsynchronized.ref (Symtab.empty: Toplevel.transition Symtab.table); | |
| 118 | val global_documents = Unsynchronized.ref (Symtab.empty: document Symtab.table); | |
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 119 | in | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 120 | |
| 32738 | 121 | fun change_states f = NAMED_CRITICAL "Isar" (fn () => Unsynchronized.change global_states f); | 
| 33223 | 122 | fun get_states () = ! global_states; | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 123 | |
| 32738 | 124 | fun change_commands f = NAMED_CRITICAL "Isar" (fn () => Unsynchronized.change global_commands f); | 
| 33223 | 125 | fun get_commands () = ! global_commands; | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 126 | |
| 32738 | 127 | fun change_documents f = NAMED_CRITICAL "Isar" (fn () => Unsynchronized.change global_documents f); | 
| 33223 | 128 | fun get_documents () = ! global_documents; | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 129 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 130 | fun init () = NAMED_CRITICAL "Isar" (fn () => | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 131 | (global_states := Symtab.empty; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 132 | global_commands := Symtab.empty; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 133 | global_documents := Symtab.empty)); | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 134 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 135 | end; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 136 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 137 | |
| 29520 | 138 | (* state *) | 
| 139 | ||
| 140 | val empty_state = Future.value (SOME Toplevel.toplevel); | |
| 141 | ||
| 142 | fun define_state (id: state_id) = | |
| 143 | change_states (Symtab.update_new (id, empty_state)) | |
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 144 | handle Symtab.DUP dup => err_dup "state" dup; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 145 | |
| 29520 | 146 | fun put_state (id: state_id) state = change_states (Symtab.update (id, state)); | 
| 147 | ||
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 148 | fun the_state (id: state_id) = | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 149 | (case Symtab.lookup (get_states ()) id of | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 150 | NONE => err_undef "state" id | 
| 29484 | 151 | | SOME state => state); | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 152 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 153 | |
| 29520 | 154 | (* command *) | 
| 155 | ||
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 156 | fun define_command id tr = | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 157 | change_commands (Symtab.update_new (id, Toplevel.put_id id tr)) | 
| 29484 | 158 | handle Symtab.DUP dup => err_dup "command" dup; | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 159 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 160 | fun the_command (id: command_id) = | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 161 | (case Symtab.lookup (get_commands ()) id of | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 162 | NONE => err_undef "command" id | 
| 29468 | 163 | | SOME tr => tr); | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 164 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 165 | |
| 29520 | 166 | (* document *) | 
| 167 | ||
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 168 | fun define_document (id: document_id) document = | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 169 | change_documents (Symtab.update_new (id, document)) | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 170 | handle Symtab.DUP dup => err_dup "document" dup; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 171 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 172 | fun the_document (id: document_id) = | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 173 | (case Symtab.lookup (get_documents ()) id of | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 174 | NONE => err_undef "document" id | 
| 29517 | 175 | | SOME document => document); | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 176 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 177 | |
| 29520 | 178 | |
| 179 | (** main operations **) | |
| 180 | ||
| 29468 | 181 | (* begin/end document *) | 
| 29467 | 182 | |
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 183 | fun begin_document (id: document_id) path = | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 184 | let | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 185 | val (dir, name) = ThyLoad.split_thy_path path; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 186 | val _ = define_command id Toplevel.empty; | 
| 29520 | 187 | val _ = define_state id; | 
| 29484 | 188 | val entries = Symtab.make [(id, make_entry NONE (SOME id))]; | 
| 29467 | 189 | val _ = define_document id (make_document dir name id entries); | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 190 | in () end; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 191 | |
| 29519 | 192 | fun end_document (id: document_id) = | 
| 193 | let | |
| 194 |     val document as Document {name, ...} = the_document id;
 | |
| 195 | val end_state = | |
| 196 | the_state (the (#state (#3 (the | |
| 197 |         (first_entry (fn (_, {next, ...}) => is_none next) document)))));
 | |
| 198 | val _ = | |
| 199 | Future.fork_deps [end_state] (fn () => | |
| 200 | (case Future.join end_state of | |
| 201 | SOME st => | |
| 202 | (Toplevel.run_command name (Toplevel.put_id id (Toplevel.commit_exit Position.none)) st; | |
| 203 | ThyInfo.touch_child_thys name; | |
| 204 | ThyInfo.register_thy name) | |
| 29520 | 205 |         | NONE => error ("Failed to finish theory " ^ quote name)));
 | 
| 29519 | 206 | in () end; | 
| 29468 | 207 | |
| 208 | ||
| 209 | (* document editing *) | |
| 210 | ||
| 29507 | 211 | local | 
| 212 | ||
| 213 | fun is_changed entries' (id, {next = _, state}) =
 | |
| 214 | (case try (the_entry entries') id of | |
| 29517 | 215 | NONE => true | 
| 216 |   | SOME {next = _, state = state'} => state' <> state);
 | |
| 29507 | 217 | |
| 29517 | 218 | fun new_state name (id, _) (state_id, updates) = | 
| 29507 | 219 | let | 
| 29520 | 220 | val state_id' = make_id (); | 
| 221 | val _ = define_state state_id'; | |
| 29517 | 222 | val tr = Toplevel.put_id state_id' (the_command id); | 
| 29520 | 223 | fun make_state' () = | 
| 224 | let | |
| 225 | val state = the_state state_id; | |
| 226 | val state' = | |
| 227 | Future.fork_deps [state] (fn () => | |
| 228 | (case Future.join state of | |
| 229 | NONE => NONE | |
| 230 | | SOME st => Toplevel.run_command name tr st)); | |
| 231 | in put_state state_id' state' end; | |
| 232 | in (state_id', ((id, state_id'), make_state') :: updates) end; | |
| 29468 | 233 | |
| 29489 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 234 | fun report_updates _ [] = () | 
| 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 235 | | report_updates (document_id: document_id) updates = | 
| 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 236 | implode (map (fn (id, state_id) => Markup.markup (Markup.edit id state_id) "") updates) | 
| 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 237 | |> Markup.markup (Markup.edits document_id) | 
| 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 238 | |> Output.status; | 
| 
5dfe03f423c4
edit_document: proper edits/edit markup, including the document id;
 wenzelm parents: 
29487diff
changeset | 239 | |
| 29507 | 240 | in | 
| 241 | ||
| 29520 | 242 | fun edit_document (old_id: document_id) (new_id: document_id) edits = | 
| 29468 | 243 | let | 
| 29520 | 244 |     val old_document as Document {name, entries = old_entries, ...} = the_document old_id;
 | 
| 245 |     val new_document as Document {entries = new_entries, ...} = old_document
 | |
| 246 | |> fold (fn (id, SOME id2) => insert_after id id2 | (id, NONE) => delete_after id) edits; | |
| 247 | ||
| 248 | fun cancel_old id = fold_entries id | |
| 249 |       (fn (_, {state = SOME state_id, ...}) => K (Future.cancel (the_state state_id)) | _ => K ())
 | |
| 250 | old_document (); | |
| 251 | ||
| 252 | val (updates, new_document') = | |
| 253 | (case first_entry (is_changed old_entries) new_document of | |
| 254 | NONE => | |
| 255 | (case first_entry (is_changed new_entries) old_document of | |
| 256 | NONE => ([], new_document) | |
| 257 | | SOME (_, id, _) => (cancel_old id; ([], new_document))) | |
| 258 | | SOME (prev, id, _) => | |
| 259 | let | |
| 260 | val _ = cancel_old id; | |
| 261 | val prev_state_id = the (#state (the_entry new_entries (the prev))); | |
| 262 | val (_, updates) = fold_entries id (new_state name) new_document (prev_state_id, []); | |
| 263 | val new_document' = new_document |> map_entries (fold (set_entry_state o #1) updates); | |
| 264 | in (rev updates, new_document') end); | |
| 265 | ||
| 266 | val _ = define_document new_id new_document'; | |
| 267 | val _ = report_updates new_id (map #1 updates); | |
| 268 | val _ = List.app (fn (_, run) => run ()) updates; | |
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 269 | in () end; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 270 | |
| 29507 | 271 | end; | 
| 272 | ||
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 273 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 274 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 275 | (** concrete syntax **) | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 276 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 277 | local structure P = OuterParse structure V = ValueParse in | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 278 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 279 | val _ = | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 280 | OuterSyntax.internal_command "Isar.define_command" | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 281 | (P.string -- P.string >> (fn (id, text) => | 
| 32573 | 282 | Toplevel.position (Position.id_only id) o | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 283 | Toplevel.imperative (fn () => | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 284 | define_command id (OuterSyntax.prepare_command (Position.id id) text)))); | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 285 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 286 | val _ = | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 287 | OuterSyntax.internal_command "Isar.begin_document" | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 288 | (P.string -- P.string >> (fn (id, path) => | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 289 | Toplevel.imperative (fn () => begin_document id (Path.explode path)))); | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 290 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 291 | val _ = | 
| 29468 | 292 | OuterSyntax.internal_command "Isar.end_document" | 
| 293 | (P.string >> (fn id => Toplevel.imperative (fn () => end_document id))); | |
| 294 | ||
| 295 | val _ = | |
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 296 | OuterSyntax.internal_command "Isar.edit_document" | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 297 | (P.string -- P.string -- V.list (P.string -- (P.string >> SOME) || P.string >> rpair NONE) | 
| 29499 
2819ba5f0c32
command 'Isar.edit_document': actually invoke edit_document;
 wenzelm parents: 
29490diff
changeset | 298 | >> (fn ((id, new_id), edits) => Toplevel.imperative (fn () => edit_document id new_id edits))); | 
| 29459 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 299 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 300 | end; | 
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 301 | |
| 
8acad4f0a727
added Isar/isar_document.ML: Interactive Isar documents.
 wenzelm parents: diff
changeset | 302 | end; | 
| 29467 | 303 |