src/Pure/PIDE/document.ML
changeset 47420 0dbe6c69eda2
parent 47415 c486ac962b89
child 47424 57ff63a52c53
equal deleted inserted replaced
47419:c0e8c98ee50e 47420:0dbe6c69eda2
    23     Perspective of command_id list
    23     Perspective of command_id list
    24   type edit = string * node_edit
    24   type edit = string * node_edit
    25   type state
    25   type state
    26   val init_state: state
    26   val init_state: state
    27   val define_command: command_id -> string -> string -> state -> state
    27   val define_command: command_id -> string -> string -> state -> state
       
    28   val remove_versions: version_id list -> state -> state
    28   val discontinue_execution: state -> unit
    29   val discontinue_execution: state -> unit
    29   val cancel_execution: state -> unit
    30   val cancel_execution: state -> unit
    30   val execute: version_id -> state -> state
    31   val start_execution: state -> unit
    31   val update: version_id -> version_id -> edit list -> state ->
    32   val update: version_id -> version_id -> edit list -> state ->
    32     (command_id * exec_id option) list * state
    33     (command_id * exec_id option) list * state
    33   val remove_versions: version_id list -> state -> state
       
    34   val state: unit -> state
    34   val state: unit -> state
    35   val change_state: (state -> state) -> unit
    35   val change_state: (state -> state) -> unit
    36 end;
    36 end;
    37 
    37 
    38 structure Document: DOCUMENT =
    38 structure Document: DOCUMENT =
   142 fun the_entry (Node {entries, ...}) id =
   142 fun the_entry (Node {entries, ...}) id =
   143   (case Entries.lookup entries id of
   143   (case Entries.lookup entries id of
   144     NONE => err_undef "command entry" id
   144     NONE => err_undef "command entry" id
   145   | SOME (exec, _) => exec);
   145   | SOME (exec, _) => exec);
   146 
   146 
   147 fun the_default_entry node (SOME id) = (id, (the_default (no_id, no_exec) (the_entry node id)))
   147 fun the_default_entry node (SOME id) = (id, the_default (no_id, no_exec) (the_entry node id))
   148   | the_default_entry _ NONE = (no_id, (no_id, no_exec));
   148   | the_default_entry _ NONE = (no_id, (no_id, no_exec));
   149 
   149 
   150 fun update_entry id exec =
   150 fun update_entry id exec =
   151   map_entries (Entries.update (id, exec));
   151   map_entries (Entries.update (id, exec));
   152 
   152 
   218 
   218 
   219 val init_state =
   219 val init_state =
   220   make_state (Inttab.make [(no_id, empty_version)], Inttab.empty,
   220   make_state (Inttab.make [(no_id, empty_version)], Inttab.empty,
   221     (no_id, Future.new_group NONE, Unsynchronized.ref false));
   221     (no_id, Future.new_group NONE, Unsynchronized.ref false));
   222 
   222 
       
   223 fun execution_of (State {execution, ...}) = execution;
       
   224 
   223 
   225 
   224 (* document versions *)
   226 (* document versions *)
   225 
   227 
   226 fun define_version (id: version_id) version =
   228 fun define_version (id: version_id) version =
   227   map_state (fn (versions, commands, execution) =>
   229   map_state (fn (versions, commands, _) =>
   228     let val versions' = Inttab.update_new (id, version) versions
   230     let
   229       handle Inttab.DUP dup => err_dup "document version" dup
   231       val versions' = Inttab.update_new (id, version) versions
   230     in (versions', commands, execution) end);
   232         handle Inttab.DUP dup => err_dup "document version" dup;
       
   233       val execution' = (id, Future.new_group NONE, Unsynchronized.ref true);
       
   234     in (versions', commands, execution') end);
   231 
   235 
   232 fun the_version (State {versions, ...}) (id: version_id) =
   236 fun the_version (State {versions, ...}) (id: version_id) =
   233   (case Inttab.lookup versions id of
   237   (case Inttab.lookup versions id of
   234     NONE => err_undef "document version" id
   238     NONE => err_undef "document version" id
   235   | SOME version => version);
   239   | SOME version => version);
   260 fun the_command (State {commands, ...}) (id: command_id) =
   264 fun the_command (State {commands, ...}) (id: command_id) =
   261   (case Inttab.lookup commands id of
   265   (case Inttab.lookup commands id of
   262     NONE => err_undef "command" id
   266     NONE => err_undef "command" id
   263   | SOME command => command);
   267   | SOME command => command);
   264 
   268 
   265 
       
   266 (* document execution *)
       
   267 
       
   268 fun discontinue_execution (State {execution = (_, _, running), ...}) = running := false;
       
   269 
       
   270 fun cancel_execution (State {execution = (_, group, _), ...}) = Future.cancel_group group;
       
   271 fun execution_tasks (State {execution = (_, group, _), ...}) = Future.group_tasks group;
       
   272 
       
   273 end;
   269 end;
   274 
   270 
   275 
   271 fun remove_versions ids state = state |> map_state (fn (versions, _, execution) =>
   276 
   272   let
   277 (** edit operations **)
   273     val _ = member (op =) ids (#1 execution) andalso
   278 
   274       error ("Attempt to remove execution version " ^ print_id (#1 execution));
   279 (* execute *)
   275 
   280 
   276     val versions' = fold delete_version ids versions;
   281 local
   277     val commands' =
   282 
   278       (versions', Inttab.empty) |->
   283 fun finished_theory node =
   279         Inttab.fold (fn (_, version) => nodes_of version |>
   284   (case Exn.capture (Command.memo_result o the) (get_result node) of
   280           Graph.fold (fn (_, (node, _)) => node |>
   285     Exn.Res (st, _) => can (Toplevel.end_theory Position.none) st
   281             iterate_entries (fn ((_, id), _) =>
   286   | _ => false);
   282               SOME o Inttab.insert (K true) (id, the_command state id))));
   287 
   283   in (versions', commands', execution) end);
   288 in
   284 
   289 
   285 
   290 fun execute version_id state =
   286 
   291   state |> map_state (fn (versions, commands, _) =>
   287 (** document execution **)
   292     let
   288 
   293       val version = the_version state version_id;
   289 val discontinue_execution = execution_of #> (fn (_, _, running) => running := false);
   294 
   290 
   295       fun run node command_id exec =
   291 val cancel_execution = execution_of #> (fn (_, group, _) => Future.cancel_group group);
   296         let
   292 
   297           val (_, print) = Command.memo_eval exec;
   293 fun terminate_execution state =
   298           val _ =
   294   let
   299             if visible_command node command_id
   295     val (_, group, _) = execution_of state;
   300             then ignore (Lazy.future Future.default_params print)
   296     val _ = Future.cancel_group group;
   301             else ();
   297   in Future.join_tasks (Future.group_tasks group) end;
   302         in () end;
   298 
   303 
   299 fun start_execution state =
   304       val group = Future.new_group NONE;
   300   let
   305       val running = Unsynchronized.ref true;
   301     fun finished_theory node =
   306 
   302       (case Exn.capture (Command.memo_result o the) (get_result node) of
   307       val _ =
   303         Exn.Res (st, _) => can (Toplevel.end_theory Position.none) st
   308         nodes_of version |> Graph.schedule
   304       | _ => false);
   309           (fn deps => fn (name, node) =>
   305 
   310             if not (visible_node node) andalso finished_theory node then
   306     fun run node command_id exec =
   311               Future.value ()
   307       let
   312             else
   308         val (_, print) = Command.memo_eval exec;
   313               (singleton o Future.forks)
   309         val _ =
   314                 {name = "theory:" ^ name, group = SOME (Future.new_group (SOME group)),
   310           if visible_command node command_id
   315                   deps = map (Future.task_of o #2) deps, pri = ~2, interrupts = false}
   311           then ignore (Lazy.future Future.default_params print)
   316                 (fn () =>
   312           else ();
   317                   iterate_entries (fn ((_, id), opt_exec) => fn () =>
   313       in () end;
   318                     (case opt_exec of
   314 
   319                       SOME (_, exec) => if ! running then SOME (run node id exec) else NONE
   315     val (version_id, group, running) = execution_of state;
   320                     | NONE => NONE)) node ()));
   316     val _ =
   321 
   317       nodes_of (the_version state version_id) |> Graph.schedule
   322     in (versions, commands, (version_id, group, running)) end);
   318         (fn deps => fn (name, node) =>
   323 
   319           if not (visible_node node) andalso finished_theory node then
   324 end;
   320             Future.value ()
   325 
   321           else
   326 
   322             (singleton o Future.forks)
   327 (* update *)
   323               {name = "theory:" ^ name, group = SOME (Future.new_group (SOME group)),
       
   324                 deps = map (Future.task_of o #2) deps, pri = ~2, interrupts = false}
       
   325               (fn () =>
       
   326                 iterate_entries (fn ((_, id), opt_exec) => fn () =>
       
   327                   (case opt_exec of
       
   328                     SOME (_, exec) => if ! running then SOME (run node id exec) else NONE
       
   329                   | NONE => NONE)) node ()));
       
   330   in () end;
       
   331 
       
   332 
       
   333 
       
   334 (** document update **)
   328 
   335 
   329 local
   336 local
   330 
   337 
   331 fun stable_finished_theory node =
   338 fun stable_finished_theory node =
   332   is_some (Exn.get_res (Exn.capture (fn () =>
   339   is_some (Exn.get_res (Exn.capture (fn () =>
   444     val new_version = fold edit_nodes edits old_version;
   451     val new_version = fold edit_nodes edits old_version;
   445 
   452 
   446     val nodes = nodes_of new_version;
   453     val nodes = nodes_of new_version;
   447     val is_required = make_required nodes;
   454     val is_required = make_required nodes;
   448 
   455 
   449     val _ = Future.join_tasks (execution_tasks state);
   456     val _ = terminate_execution state;
   450     val updated =
   457     val updated =
   451       nodes |> Graph.schedule
   458       nodes |> Graph.schedule
   452         (fn deps => fn (name, node) =>
   459         (fn deps => fn (name, node) =>
   453           (singleton o Future.forks)
   460           (singleton o Future.forks)
   454             {name = "Document.update", group = NONE,
   461             {name = "Document.update", group = NONE,
   517   in (command_execs, state') end;
   524   in (command_execs, state') end;
   518 
   525 
   519 end;
   526 end;
   520 
   527 
   521 
   528 
   522 (* remove versions *)
       
   523 
       
   524 fun remove_versions ids state = state |> map_state (fn (versions, _, execution) =>
       
   525   let
       
   526     val _ = member (op =) ids (#1 execution) andalso
       
   527       error ("Attempt to remove execution version " ^ print_id (#1 execution));
       
   528 
       
   529     val versions' = fold delete_version ids versions;
       
   530     val commands' =
       
   531       (versions', Inttab.empty) |->
       
   532         Inttab.fold (fn (_, version) => nodes_of version |>
       
   533           Graph.fold (fn (_, (node, _)) => node |>
       
   534             iterate_entries (fn ((_, id), _) =>
       
   535               SOME o Inttab.insert (K true) (id, the_command state id))));
       
   536   in (versions', commands', execution) end);
       
   537 
       
   538 
       
   539 
   529 
   540 (** global state **)
   530 (** global state **)
   541 
   531 
   542 val global_state = Synchronized.var "Document" init_state;
   532 val global_state = Synchronized.var "Document" init_state;
   543 
   533