--- a/src/HOL/HOLCF/IOA/ABP/Check.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/HOL/HOLCF/IOA/ABP/Check.ML Tue Aug 23 17:12:54 2011 +0200
@@ -112,21 +112,21 @@
------------------------------------*)
fun print_list (lpar, rpar, pre: 'a -> unit) (lll : 'a list) =
- let fun prec x = (Output.raw_stdout ","; pre x)
+ let fun prec x = (Output.physical_stdout ","; pre x)
in
(case lll of
- [] => (Output.raw_stdout lpar; Output.raw_stdout rpar)
- | x::lll => (Output.raw_stdout lpar; pre x; List.app prec lll; Output.raw_stdout rpar))
+ [] => (Output.physical_stdout lpar; Output.physical_stdout rpar)
+ | x::lll => (Output.physical_stdout lpar; pre x; List.app prec lll; Output.physical_stdout rpar))
end;
-fun pr_bool true = Output.raw_stdout "true"
-| pr_bool false = Output.raw_stdout "false";
+fun pr_bool true = Output.physical_stdout "true"
+| pr_bool false = Output.physical_stdout "false";
-fun pr_msg m = Output.raw_stdout "m"
-| pr_msg n = Output.raw_stdout "n"
-| pr_msg l = Output.raw_stdout "l";
+fun pr_msg m = Output.physical_stdout "m"
+| pr_msg n = Output.physical_stdout "n"
+| pr_msg l = Output.physical_stdout "l";
-fun pr_act a = Output.raw_stdout (case a of
+fun pr_act a = Output.physical_stdout (case a of
Next => "Next"|
S_msg(ma) => "S_msg(ma)" |
R_msg(ma) => "R_msg(ma)" |
@@ -135,17 +135,17 @@
S_ack(b) => "S_ack(b)" |
R_ack(b) => "R_ack(b)");
-fun pr_pkt (b,ma) = (Output.raw_stdout "<"; pr_bool b;Output.raw_stdout ", "; pr_msg ma; Output.raw_stdout ">");
+fun pr_pkt (b,ma) = (Output.physical_stdout "<"; pr_bool b;Output.physical_stdout ", "; pr_msg ma; Output.physical_stdout ">");
val pr_bool_list = print_list("[","]",pr_bool);
val pr_msg_list = print_list("[","]",pr_msg);
val pr_pkt_list = print_list("[","]",pr_pkt);
fun pr_tuple (env,p,a,q,b,ch1,ch2) =
- (Output.raw_stdout "{"; pr_bool env; Output.raw_stdout ", "; pr_msg_list p; Output.raw_stdout ", ";
- pr_bool a; Output.raw_stdout ", "; pr_msg_list q; Output.raw_stdout ", ";
- pr_bool b; Output.raw_stdout ", "; pr_pkt_list ch1; Output.raw_stdout ", ";
- pr_bool_list ch2; Output.raw_stdout "}");
+ (Output.physical_stdout "{"; pr_bool env; Output.physical_stdout ", "; pr_msg_list p; Output.physical_stdout ", ";
+ pr_bool a; Output.physical_stdout ", "; pr_msg_list q; Output.physical_stdout ", ";
+ pr_bool b; Output.physical_stdout ", "; pr_pkt_list ch1; Output.physical_stdout ", ";
+ pr_bool_list ch2; Output.physical_stdout "}");
--- a/src/HOL/Library/FuncSet.thy Tue Aug 23 16:37:23 2011 +0200
+++ b/src/HOL/Library/FuncSet.thy Tue Aug 23 17:12:54 2011 +0200
@@ -72,7 +72,7 @@
by (auto simp: Pi_def)
lemma funcset_id [simp]: "(\<lambda>x. x) \<in> A \<rightarrow> A"
- by (auto intro: Pi_I)
+ by auto
lemma funcset_mem: "[|f \<in> A -> B; x \<in> A|] ==> f x \<in> B"
by (simp add: Pi_def)
@@ -257,7 +257,7 @@
where "extensional_funcset S T = (S -> T) \<inter> (extensional S)"
lemma extensional_empty[simp]: "extensional {} = {%x. undefined}"
-unfolding extensional_def by (auto intro: ext)
+unfolding extensional_def by auto
lemma extensional_funcset_empty_domain: "extensional_funcset {} T = {%x. undefined}"
unfolding extensional_funcset_def by simp
--- a/src/Pure/Concurrent/future.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/Concurrent/future.ML Tue Aug 23 17:12:54 2011 +0200
@@ -51,12 +51,12 @@
val task_of: 'a future -> task
val peek: 'a future -> 'a Exn.result option
val is_finished: 'a future -> bool
- val get_finished: 'a future -> 'a
val interruptible_task: ('a -> 'b) -> 'a -> 'b
val cancel_group: group -> task list
val cancel: 'a future -> task list
type fork_params =
{name: string, group: group option, deps: task list, pri: int, interrupts: bool}
+ val default_params: fork_params
val forks: fork_params -> (unit -> 'a) list -> 'a future list
val fork_pri: int -> (unit -> 'a) -> 'a future
val fork: (unit -> 'a) -> 'a future
@@ -125,11 +125,6 @@
fun peek x = Single_Assignment.peek (result_of x);
fun is_finished x = is_some (peek x);
-fun get_finished x =
- (case peek x of
- SOME res => Exn.release res
- | NONE => raise Fail "Unfinished future evaluation");
-
(** scheduling **)
@@ -467,6 +462,9 @@
type fork_params =
{name: string, group: group option, deps: task list, pri: int, interrupts: bool};
+val default_params: fork_params =
+ {name = "", group = NONE, deps = [], pri = 0, interrupts = true};
+
fun forks ({name, group, deps, pri, interrupts}: fork_params) es =
if null es then []
else
--- a/src/Pure/Concurrent/lazy.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/Concurrent/lazy.ML Tue Aug 23 17:12:54 2011 +0200
@@ -11,11 +11,12 @@
type 'a lazy
val peek: 'a lazy -> 'a Exn.result option
val is_finished: 'a lazy -> bool
- val get_finished: 'a lazy -> 'a
val lazy: (unit -> 'a) -> 'a lazy
val value: 'a -> 'a lazy
val force_result: 'a lazy -> 'a Exn.result
val force: 'a lazy -> 'a
+ val map: ('a -> 'b) -> 'a lazy -> 'b lazy
+ val future: Future.fork_params -> 'a lazy -> 'a future
end;
structure Lazy: LAZY =
@@ -40,11 +41,6 @@
fun is_finished x = is_some (peek x);
-fun get_finished x =
- (case peek x of
- SOME res => Exn.release res
- | NONE => raise Fail "Unfinished lazy evaluation");
-
(* force result *)
@@ -77,9 +73,19 @@
| NONE => Exn.capture (restore_attributes (fn () => Future.join x)) ())
end) ());
-fun force r = Exn.release (force_result r);
end;
+
+fun force r = Exn.release (force_result r);
+fun map f x = lazy (fn () => f (force x));
+
+
+(* future evaluation *)
+
+fun future params x =
+ if is_finished x then Future.value_result (force_result x)
+ else (singleton o Future.forks) params (fn () => force x);
+
end;
type 'a lazy = 'a Lazy.lazy;
--- a/src/Pure/Concurrent/lazy_sequential.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/Concurrent/lazy_sequential.ML Tue Aug 23 17:12:54 2011 +0200
@@ -27,11 +27,6 @@
fun is_finished x = is_some (peek x);
-fun get_finished x =
- (case peek x of
- SOME res => Exn.release res
- | NONE => raise Fail "Unfinished lazy evaluation");
-
(* force result *)
@@ -45,6 +40,14 @@
in result end;
fun force r = Exn.release (force_result r);
+fun map f x = lazy (fn () => f (force x));
+
+
+(* future evaluation *)
+
+fun future params x =
+ if is_finished x then Future.value_result (force_result x)
+ else (singleton o Future.forks) params (fn () => force x);
end;
end;
--- a/src/Pure/General/output.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/General/output.ML Tue Aug 23 17:12:54 2011 +0200
@@ -22,9 +22,9 @@
val output_width: string -> output * int
val output: string -> output
val escape: output -> string
- val raw_stdout: output -> unit
- val raw_stderr: output -> unit
- val raw_writeln: output -> unit
+ val physical_stdout: output -> unit
+ val physical_stderr: output -> unit
+ val physical_writeln: output -> unit
structure Private_Hooks:
sig
val writeln_fn: (output -> unit) Unsynchronized.ref
@@ -78,24 +78,24 @@
(* raw output primitives -- not to be used in user-space *)
-fun raw_stdout s = (TextIO.output (TextIO.stdOut, s); TextIO.flushOut TextIO.stdOut);
-fun raw_stderr s = (TextIO.output (TextIO.stdErr, s); TextIO.flushOut TextIO.stdErr);
+fun physical_stdout s = (TextIO.output (TextIO.stdOut, s); TextIO.flushOut TextIO.stdOut);
+fun physical_stderr s = (TextIO.output (TextIO.stdErr, s); TextIO.flushOut TextIO.stdErr);
-fun raw_writeln "" = ()
- | raw_writeln s = raw_stdout (suffix "\n" s); (*atomic output!*)
+fun physical_writeln "" = ()
+ | physical_writeln s = physical_stdout (suffix "\n" s); (*atomic output!*)
(* Isabelle output channels *)
structure Private_Hooks =
struct
- val writeln_fn = Unsynchronized.ref raw_writeln;
+ val writeln_fn = Unsynchronized.ref physical_writeln;
val urgent_message_fn = Unsynchronized.ref (fn s => ! writeln_fn s);
val tracing_fn = Unsynchronized.ref (fn s => ! writeln_fn s);
- val warning_fn = Unsynchronized.ref (raw_stdout o suffix "\n" o prefix_lines "### ");
+ val warning_fn = Unsynchronized.ref (physical_stdout o suffix "\n" o prefix_lines "### ");
val error_fn =
- Unsynchronized.ref (fn (_: serial, s) => raw_stdout (suffix "\n" (prefix_lines "*** " s)));
- val prompt_fn = Unsynchronized.ref raw_stdout;
+ Unsynchronized.ref (fn (_: serial, s) => physical_stdout (suffix "\n" (prefix_lines "*** " s)));
+ val prompt_fn = Unsynchronized.ref physical_stdout;
val status_fn = Unsynchronized.ref (fn _: output => ());
val report_fn = Unsynchronized.ref (fn _: output => ());
val raw_message_fn: (Properties.T -> output -> unit) Unsynchronized.ref =
--- a/src/Pure/PIDE/command.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/PIDE/command.scala Tue Aug 23 17:12:54 2011 +0200
@@ -84,6 +84,19 @@
def span(toks: List[Token]): Command =
new Command(Document.no_id, toks)
+
+
+ /* perspective */
+
+ type Perspective = List[Command] // visible commands in canonical order
+
+ def equal_perspective(p1: Perspective, p2: Perspective): Boolean =
+ {
+ require(p1.forall(_.is_defined))
+ require(p2.forall(_.is_defined))
+ p1.length == p2.length &&
+ (p1.iterator zip p2.iterator).forall({ case (c1, c2) => c1.id == c2.id })
+ }
}
@@ -93,12 +106,12 @@
{
/* classification */
+ def is_defined: Boolean = id != Document.no_id
+
def is_command: Boolean = !span.isEmpty && span.head.is_command
def is_ignored: Boolean = span.forall(_.is_ignored)
def is_malformed: Boolean = !is_command && !is_ignored
- def is_unparsed = id == Document.no_id
-
def name: String = if (is_command) span.head.content else ""
override def toString =
id + "/" + (if (is_command) name else if (is_ignored) "IGNORED" else "MALFORMED")
--- a/src/Pure/PIDE/document.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/PIDE/document.ML Tue Aug 23 17:12:54 2011 +0200
@@ -19,7 +19,8 @@
datatype node_edit =
Clear |
Edits of (command_id option * command_id option) list |
- Header of node_header
+ Header of node_header |
+ Perspective of command_id list
type edit = string * node_edit
type state
val init_state: state
@@ -56,34 +57,54 @@
(** document structure **)
type node_header = (string * string list * (string * bool) list) Exn.result;
+type perspective = (command_id -> bool) * command_id list; (*visible commands, canonical order*)
structure Entries = Linear_Set(type key = command_id val ord = int_ord);
abstype node = Node of
{header: node_header,
+ perspective: perspective,
entries: exec_id option Entries.T, (*command entries with excecutions*)
result: Toplevel.state lazy}
and version = Version of node Graph.T (*development graph wrt. static imports*)
with
-fun make_node (header, entries, result) =
- Node {header = header, entries = entries, result = result};
+fun make_node (header, perspective, entries, result) =
+ Node {header = header, perspective = perspective, entries = entries, result = result};
+
+fun map_node f (Node {header, perspective, entries, result}) =
+ make_node (f (header, perspective, entries, result));
-fun map_node f (Node {header, entries, result}) =
- make_node (f (header, entries, result));
+val no_perspective: perspective = (K false, []);
+val no_print = Lazy.value ();
+val no_result = Lazy.value Toplevel.toplevel;
+
+val empty_node =
+ make_node (Exn.Exn (ERROR "Bad theory header"), no_perspective, Entries.empty, no_result);
+
+val clear_node =
+ map_node (fn (header, _, _, _) => (header, no_perspective, Entries.empty, no_result));
+
+
+(* basic components *)
fun get_header (Node {header, ...}) = header;
-fun set_header header = map_node (fn (_, entries, result) => (header, entries, result));
+fun set_header header =
+ map_node (fn (_, perspective, entries, result) => (header, perspective, entries, result));
-fun map_entries f (Node {header, entries, result}) = make_node (header, f entries, result);
+fun get_perspective (Node {perspective, ...}) = perspective;
+fun set_perspective perspective =
+ let val pred = Inttab.defined (Inttab.make (map (rpair ()) perspective)) in
+ map_node (fn (header, _, entries, result) => (header, (pred, perspective), entries, result))
+ end;
+
+fun map_entries f (Node {header, perspective, entries, result}) =
+ make_node (header, perspective, f entries, result);
fun fold_entries start f (Node {entries, ...}) = Entries.fold start f entries;
fun first_entry start P (Node {entries, ...}) = Entries.get_first start P entries;
-fun get_theory pos (Node {result, ...}) = Toplevel.end_theory pos (Lazy.get_finished result);
-fun set_result result = map_node (fn (header, entries, _) => (header, entries, result));
-
-val empty_exec = Lazy.value Toplevel.toplevel;
-val empty_node = make_node (Exn.Exn (ERROR "Bad theory header"), Entries.empty, empty_exec);
-val clear_node = map_node (fn (header, _, _) => (header, Entries.empty, empty_exec));
+fun get_theory pos (Node {result, ...}) = Toplevel.end_theory pos (Lazy.force result);
+fun set_result result =
+ map_node (fn (header, perspective, entries, _) => (header, perspective, entries, result));
fun get_node nodes name = Graph.get_node nodes name handle Graph.UNDEF _ => empty_node;
fun default_node name = Graph.default_node (name, empty_node);
@@ -95,7 +116,8 @@
datatype node_edit =
Clear |
Edits of (command_id option * command_id option) list |
- Header of node_header;
+ Header of node_header |
+ Perspective of command_id list;
type edit = string * node_edit;
@@ -150,7 +172,9 @@
val (header', nodes3) =
(header, Graph.add_deps_acyclic (name, parents) nodes2)
handle Graph.CYCLES cs => (Exn.Exn (ERROR (cat_lines (map cycle_msg cs))), nodes2);
- in Graph.map_node name (set_header header') nodes3 end));
+ in Graph.map_node name (set_header header') nodes3 end
+ | Perspective perspective =>
+ update_node name (set_perspective perspective) nodes));
fun put_node (name, node) (Version nodes) =
Version (update_node name (K node) nodes);
@@ -164,7 +188,8 @@
abstype state = State of
{versions: version Inttab.table, (*version_id -> document content*)
commands: Toplevel.transition future Inttab.table, (*command_id -> transition (future parsing)*)
- execs: Toplevel.state lazy Inttab.table, (*exec_id -> execution process*)
+ execs: (command_id * (Toplevel.state * unit lazy) lazy) Inttab.table,
+ (*exec_id -> command_id with eval/print process*)
execution: Future.group} (*global execution process*)
with
@@ -177,7 +202,7 @@
val init_state =
make_state (Inttab.make [(no_id, empty_version)],
Inttab.make [(no_id, Future.value Toplevel.empty)],
- Inttab.make [(no_id, empty_exec)],
+ Inttab.make [(no_id, (no_id, Lazy.value (Toplevel.toplevel, no_print)))],
Future.new_group NONE);
@@ -252,14 +277,9 @@
SOME prf => Toplevel.status tr (Proof.status_markup prf)
| NONE => ());
-fun async_state tr st =
- (singleton o Future.forks)
- {name = "Document.async_state", group = SOME (Future.new_group NONE),
- deps = [], pri = 0, interrupts = true}
- (fn () =>
- Toplevel.setmp_thread_position tr
- (fn () => Toplevel.print_state false st) ())
- |> ignore;
+fun print_state tr st =
+ (Lazy.lazy o Toplevel.setmp_thread_position tr)
+ (fn () => Toplevel.print_state false st);
fun run int tr st =
(case Toplevel.transition int tr st of
@@ -286,12 +306,11 @@
val _ = List.app (Toplevel.error_msg tr) errs;
in
(case result of
- NONE => (Toplevel.status tr Markup.failed; st)
+ NONE => (Toplevel.status tr Markup.failed; (st, no_print))
| SOME st' =>
(Toplevel.status tr Markup.finished;
proof_status tr st';
- if do_print then async_state tr st' else ();
- st'))
+ (st', if do_print then print_state tr st' else no_print)))
end;
end;
@@ -313,13 +332,10 @@
fun new_exec (command_id, command) (assigns, execs, exec) =
let
val exec_id' = new_id ();
- val exec' =
- Lazy.lazy (fn () =>
- let
- val tr = Toplevel.put_id (print_id exec_id') (Future.get_finished command);
- val st = Lazy.get_finished exec;
- in run_command tr st end);
- in ((command_id, exec_id') :: assigns, (exec_id', exec') :: execs, exec') end;
+ val exec' = exec |> Lazy.map (fn (st, _) =>
+ let val tr = Toplevel.put_id (print_id exec_id') (Future.join command)
+ in run_command tr st end);
+ in ((command_id, exec_id') :: assigns, (exec_id', (command_id, exec')) :: execs, exec') end;
in
@@ -351,7 +367,7 @@
| NONE =>
get_theory (Position.file_only import)
(#2 (Future.join (the (AList.lookup (op =) deps import))))));
- in Thy_Load.begin_theory dir thy_name imports files parents end
+ in Thy_Load.begin_theory dir thy_name imports files parents end;
fun get_command id =
(id, the_command state id |> Future.map (Toplevel.modify_init init));
in
@@ -364,12 +380,12 @@
(case prev of
NONE => no_id
| SOME prev_id => the_default no_id (the_entry node prev_id));
- val (assigns, execs, result) =
+ val (assigns, execs, last_exec) =
fold_entries (SOME id) (new_exec o get_command o #2 o #1)
- node ([], [], the_exec state prev_exec);
+ node ([], [], #2 (the_exec state prev_exec));
val node' = node
|> fold update_entry assigns
- |> set_result result;
+ |> set_result (Lazy.map #1 last_exec);
in ((assigns, execs, [(name, node')]), node') end)
end))
|> Future.joins |> map #1;
@@ -390,8 +406,17 @@
let
val version = the_version state version_id;
- fun force_exec NONE = ()
- | force_exec (SOME exec_id) = ignore (Lazy.force (the_exec state exec_id));
+ fun force_exec _ NONE = ()
+ | force_exec node (SOME exec_id) =
+ let
+ val (command_id, exec) = the_exec state exec_id;
+ val (_, print) = Lazy.force exec;
+ val perspective = get_perspective node;
+ val _ =
+ if #1 (get_perspective node) command_id orelse true (* FIXME *)
+ then ignore (Lazy.future Future.default_params print)
+ else ();
+ in () end;
val execution = Future.new_group NONE;
val _ =
@@ -400,7 +425,7 @@
(singleton o Future.forks)
{name = "theory:" ^ name, group = SOME (Future.new_group (SOME execution)),
deps = map (Future.task_of o #2) deps, pri = 1, interrupts = true}
- (fold_entries NONE (fn (_, exec) => fn () => force_exec exec) node));
+ (fold_entries NONE (fn (_, exec) => fn () => force_exec node exec) node));
in (versions, commands, execs, execution) end);
--- a/src/Pure/PIDE/document.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/PIDE/document.scala Tue Aug 23 17:12:54 2011 +0200
@@ -31,35 +31,37 @@
/* named nodes -- development graph */
- type Edit[A] = (String, Node.Edit[A])
- type Edit_Text = Edit[Text.Edit]
- type Edit_Command = Edit[(Option[Command], Option[Command])]
- type Edit_Command_ID = Edit[(Option[Command_ID], Option[Command_ID])]
+ type Edit[A, B] = (String, Node.Edit[A, B])
+ type Edit_Text = Edit[Text.Edit, Text.Perspective]
+ type Edit_Command = Edit[(Option[Command], Option[Command]), Command.Perspective]
type Node_Header = Exn.Result[Thy_Header]
object Node
{
- sealed abstract class Edit[A]
+ sealed abstract class Edit[A, B]
{
- def map[B](f: A => B): Edit[B] =
+ def foreach(f: A => Unit)
+ {
this match {
- case Clear() => Clear()
- case Edits(es) => Edits(es.map(f))
- case Header(header) => Header(header)
+ case Edits(es) => es.foreach(f)
+ case _ =>
}
+ }
}
- case class Clear[A]() extends Edit[A]
- case class Edits[A](edits: List[A]) extends Edit[A]
- case class Header[A](header: Node_Header) extends Edit[A]
+ case class Clear[A, B]() extends Edit[A, B]
+ case class Edits[A, B](edits: List[A]) extends Edit[A, B]
+ case class Header[A, B](header: Node_Header) extends Edit[A, B]
+ case class Perspective[A, B](perspective: B) extends Edit[A, B]
- def norm_header[A](f: String => String, g: String => String, header: Node_Header): Header[A] =
+ def norm_header[A, B](f: String => String, g: String => String, header: Node_Header)
+ : Header[A, B] =
header match {
- case Exn.Res(h) => Header[A](Exn.capture { h.norm_deps(f, g) })
- case exn => Header[A](exn)
+ case Exn.Res(h) => Header[A, B](Exn.capture { h.norm_deps(f, g) })
+ case exn => Header[A, B](exn)
}
- val empty: Node = Node(Exn.Exn(ERROR("Bad theory header")), Map(), Linear_Set())
+ val empty: Node = Node(Exn.Exn(ERROR("Bad theory header")), Nil, Map(), Linear_Set())
def command_starts(commands: Iterator[Command], offset: Text.Offset = 0)
: Iterator[(Command, Text.Offset)] =
@@ -77,6 +79,7 @@
sealed case class Node(
val header: Node_Header,
+ val perspective: Command.Perspective,
val blobs: Map[String, Blob],
val commands: Linear_Set[Command])
{
--- a/src/Pure/PIDE/isar_document.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/PIDE/isar_document.ML Tue Aug 23 17:12:54 2011 +0200
@@ -27,7 +27,8 @@
fn ([], a) =>
Document.Header
(Exn.Res (triple string (list string) (list (pair string bool)) a)),
- fn ([a], []) => Document.Header (Exn.Exn (ERROR a))]))
+ fn ([a], []) => Document.Header (Exn.Exn (ERROR a)),
+ fn (a, []) => Document.Perspective (map int_atom a)]))
end;
val running = Document.cancel_execution state;
--- a/src/Pure/PIDE/isar_document.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/PIDE/isar_document.scala Tue Aug 23 17:12:54 2011 +0200
@@ -140,18 +140,20 @@
/* document versions */
def edit_version(old_id: Document.Version_ID, new_id: Document.Version_ID,
- edits: List[Document.Edit_Command_ID])
+ edits: List[Document.Edit_Command])
{
val edits_yxml =
{ import XML.Encode._
- def encode: T[List[Document.Edit_Command_ID]] =
+ def id: T[Command] = (cmd => long(cmd.id))
+ def encode: T[List[Document.Edit_Command]] =
list(pair(string,
variant(List(
{ case Document.Node.Clear() => (Nil, Nil) },
- { case Document.Node.Edits(a) => (Nil, list(pair(option(long), option(long)))(a)) },
+ { case Document.Node.Edits(a) => (Nil, list(pair(option(id), option(id)))(a)) },
{ case Document.Node.Header(Exn.Res(Thy_Header(a, b, c))) =>
(Nil, triple(string, list(string), list(pair(string, bool)))(a, b, c)) },
- { case Document.Node.Header(Exn.Exn(e)) => (List(Exn.message(e)), Nil) }))))
+ { case Document.Node.Header(Exn.Exn(e)) => (List(Exn.message(e)), Nil) },
+ { case Document.Node.Perspective(cs) => (cs.map(c => long_atom(c.id)), Nil) }))))
YXML.string_of_body(encode(edits)) }
input("Isar_Document.edit_version", Document.ID(old_id), Document.ID(new_id), edits_yxml)
--- a/src/Pure/PIDE/markup_tree.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/PIDE/markup_tree.scala Tue Aug 23 17:12:54 2011 +0200
@@ -22,10 +22,7 @@
type Entry = (Text.Info[Any], Markup_Tree)
type T = SortedMap[Text.Range, Entry]
- val empty = SortedMap.empty[Text.Range, Entry](new scala.math.Ordering[Text.Range]
- {
- def compare(r1: Text.Range, r2: Text.Range): Int = r1 compare r2
- })
+ val empty = SortedMap.empty[Text.Range, Entry](Text.Range.Ordering)
def update(branches: T, entry: Entry): T = branches + (entry._1.range -> entry)
def single(entry: Entry): T = update(empty, entry)
--- a/src/Pure/PIDE/text.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/PIDE/text.scala Tue Aug 23 17:12:54 2011 +0200
@@ -8,6 +8,11 @@
package isabelle
+import scala.collection.mutable
+import scala.math.Ordering
+import scala.util.Sorting
+
+
object Text
{
/* offset */
@@ -20,6 +25,11 @@
object Range
{
def apply(start: Offset): Range = Range(start, start)
+
+ object Ordering extends scala.math.Ordering[Text.Range]
+ {
+ def compare(r1: Text.Range, r2: Text.Range): Int = r1 compare r2
+ }
}
sealed case class Range(val start: Offset, val stop: Offset)
@@ -50,6 +60,33 @@
}
+ /* perspective */
+
+ type Perspective = List[Range] // visible text partitioning in canonical order
+
+ def perspective(ranges: Seq[Range]): Perspective =
+ {
+ val sorted_ranges = ranges.toArray
+ Sorting.quickSort(sorted_ranges)(Range.Ordering)
+
+ val result = new mutable.ListBuffer[Text.Range]
+ var last: Option[Text.Range] = None
+ for (range <- sorted_ranges)
+ {
+ last match {
+ case Some(last_range)
+ if ((last_range overlaps range) || last_range.stop == range.start) =>
+ last = Some(Text.Range(last_range.start, range.stop))
+ case _ =>
+ result ++= last
+ last = Some(range)
+ }
+ }
+ result ++= last
+ result.toList
+ }
+
+
/* information associated with text range */
sealed case class Info[A](val range: Text.Range, val info: A)
--- a/src/Pure/ProofGeneral/proof_general_emacs.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/ProofGeneral/proof_general_emacs.ML Tue Aug 23 17:12:54 2011 +0200
@@ -75,7 +75,7 @@
fun message bg en prfx text =
(case render text of
"" => ()
- | s => Output.raw_writeln (enclose bg en (prefix_lines prfx s)));
+ | s => Output.physical_writeln (enclose bg en (prefix_lines prfx s)));
fun setup_messages () =
(Output.Private_Hooks.writeln_fn := message "" "" "";
@@ -85,7 +85,7 @@
Output.Private_Hooks.tracing_fn := message (special "I" ^ special "V") (special "J") "";
Output.Private_Hooks.warning_fn := message (special "K") (special "L") "### ";
Output.Private_Hooks.error_fn := (fn (_, s) => message (special "M") (special "N") "*** " s);
- Output.Private_Hooks.prompt_fn := (fn s => Output.raw_stdout (render s ^ special "S")));
+ Output.Private_Hooks.prompt_fn := (fn s => Output.physical_stdout (render s ^ special "S")));
fun panic s =
(message (special "M") (special "N") "!!! " ("## SYSTEM EXIT ##\n" ^ s); exit 1);
--- a/src/Pure/ProofGeneral/proof_general_pgip.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/ProofGeneral/proof_general_pgip.ML Tue Aug 23 17:12:54 2011 +0200
@@ -66,7 +66,7 @@
fun matching_pgip_id id = (id = ! pgip_id)
-val output_xml_fn = Unsynchronized.ref Output.raw_writeln
+val output_xml_fn = Unsynchronized.ref Output.physical_writeln
fun output_xml s = ! output_xml_fn (XML.string_of s);
val output_pgips = XML.string_of o PgipOutput.output o assemble_pgips o map PgipOutput.output;
@@ -1009,7 +1009,7 @@
(** Out-of-loop PGIP commands (for Emacs hybrid mode) **)
local
- val pgip_output_channel = Unsynchronized.ref Output.raw_writeln
+ val pgip_output_channel = Unsynchronized.ref Output.physical_writeln
in
(* Set recipient for PGIP results *)
--- a/src/Pure/Syntax/syntax_trans.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/Syntax/syntax_trans.ML Tue Aug 23 17:12:54 2011 +0200
@@ -255,8 +255,19 @@
fun struct_tr structs [Const ("_indexdefault", _)] =
Syntax.free (the_struct structs 1)
| struct_tr structs [t as (Const ("_indexnum", _) $ Const (s, _))] =
- Syntax.free (the_struct structs
- (case Lexicon.read_nat s of SOME n => n | NONE => raise TERM ("struct_tr", [t])))
+ (case Lexicon.read_nat s of
+ SOME n =>
+ let
+ val x = the_struct structs n;
+ val advice =
+ " -- use " ^ quote ("\\<^bsub>" ^ x ^ "\\<^esub>") ^ " instead" ^
+ (if n = 1 then " (may be omitted)" else "");
+ val _ =
+ legacy_feature
+ ("Old-style numbered structure index " ^ quote ("\\<^sub>" ^ s) ^
+ Position.str_of (Position.thread_data ()) ^ advice);
+ in Syntax.free x end
+ | NONE => raise TERM ("struct_tr", [t]))
| struct_tr _ ts = raise TERM ("struct_tr", ts);
--- a/src/Pure/System/isabelle_process.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/System/isabelle_process.ML Tue Aug 23 17:12:54 2011 +0200
@@ -171,7 +171,7 @@
fun init in_fifo out_fifo = ignore (Simple_Thread.fork false (fn () =>
let
val _ = OS.Process.sleep (seconds 0.5); (*yield to raw ML toplevel*)
- val _ = Output.raw_stdout Symbol.STX;
+ val _ = Output.physical_stdout Symbol.STX;
val _ = quick_and_dirty := true;
val _ = Goal.parallel_proofs := 0;
--- a/src/Pure/System/session.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/System/session.ML Tue Aug 23 17:12:54 2011 +0200
@@ -107,7 +107,7 @@
val factor = Time.toReal (#cpu timing) / Time.toReal (#elapsed timing)
|> Real.fmt (StringCvt.FIX (SOME 2));
val _ =
- Output.raw_stderr ("Timing " ^ item ^ " (" ^
+ Output.physical_stderr ("Timing " ^ item ^ " (" ^
string_of_int (Multithreading.max_threads_value ()) ^ " threads, " ^
Timing.message timing ^ ", factor " ^ factor ^ ")\n");
in () end
--- a/src/Pure/System/session.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/System/session.scala Tue Aug 23 17:12:54 2011 +0200
@@ -164,10 +164,10 @@
private case class Start(timeout: Time, args: List[String])
private case object Interrupt
- private case class Init_Node(
- name: String, master_dir: String, header: Document.Node_Header, text: String)
- private case class Edit_Node(
- name: String, master_dir: String, header: Document.Node_Header, edits: List[Text.Edit])
+ private case class Init_Node(name: String, master_dir: String,
+ header: Document.Node_Header, perspective: Text.Perspective, text: String)
+ private case class Edit_Node(name: String, master_dir: String,
+ header: Document.Node_Header, perspective: Text.Perspective, edits: List[Text.Edit])
private case class Change_Node(
name: String,
doc_edits: List[Document.Edit_Command],
@@ -183,7 +183,7 @@
/* incoming edits */
def handle_edits(name: String, master_dir: String,
- header: Document.Node_Header, edits: List[Document.Node.Edit[Text.Edit]])
+ header: Document.Node_Header, edits: List[Document.Node.Edit[Text.Edit, Text.Perspective]])
//{{{
{
val syntax = current_syntax()
@@ -196,7 +196,8 @@
else file_store.append(master_dir, Thy_Header.thy_path(Path.explode(s)))
}
def norm_use(s: String): String = file_store.append(master_dir, Path.explode(s))
- val norm_header = Document.Node.norm_header[Text.Edit](norm_import, norm_use, header)
+ val norm_header =
+ Document.Node.norm_header[Text.Edit, Text.Perspective](norm_import, norm_use, header)
val text_edits = (name, norm_header) :: edits.map(edit => (name, edit))
val result = Future.fork { Thy_Syntax.text_edits(syntax, previous.join, text_edits) }
@@ -229,22 +230,20 @@
removed <- previous.nodes(name).commands.get_after(prev)
} former_assignment -= removed
- def id_command(command: Command): Document.Command_ID =
+ def id_command(command: Command)
{
if (global_state().lookup_command(command.id).isEmpty) {
global_state.change(_.define_command(command))
prover.get.define_command(command.id, Symbol.encode(command.source))
}
- command.id
}
- val id_edits =
- doc_edits map {
- case (name, edit) =>
- (name, edit.map({ case (c1, c2) => (c1.map(id_command), c2.map(id_command)) }))
- }
+ doc_edits foreach {
+ case (_, edit) =>
+ edit foreach { case (c1, c2) => c1 foreach id_command; c2 foreach id_command }
+ }
global_state.change(_.define_version(version, former_assignment))
- prover.get.edit_version(previous.id, version.id, id_edits)
+ prover.get.edit_version(previous.id, version.id, doc_edits)
}
//}}}
@@ -337,14 +336,18 @@
case Interrupt if prover.isDefined =>
prover.get.interrupt
- case Init_Node(name, master_dir, header, text) if prover.isDefined =>
+ case Init_Node(name, master_dir, header, perspective, text) if prover.isDefined =>
// FIXME compare with existing node
handle_edits(name, master_dir, header,
- List(Document.Node.Clear(), Document.Node.Edits(List(Text.Edit.insert(0, text)))))
+ List(Document.Node.Clear(),
+ Document.Node.Edits(List(Text.Edit.insert(0, text))),
+ Document.Node.Perspective(perspective)))
reply(())
- case Edit_Node(name, master_dir, header, text_edits) if prover.isDefined =>
- handle_edits(name, master_dir, header, List(Document.Node.Edits(text_edits)))
+ case Edit_Node(name, master_dir, header, perspective, text_edits) if prover.isDefined =>
+ handle_edits(name, master_dir, header,
+ List(Document.Node.Edits(text_edits),
+ Document.Node.Perspective(perspective)))
reply(())
case change: Change_Node if prover.isDefined =>
@@ -372,9 +375,13 @@
def interrupt() { session_actor ! Interrupt }
- def init_node(name: String, master_dir: String, header: Document.Node_Header, text: String)
- { session_actor !? Init_Node(name, master_dir, header, text) }
+ // FIXME simplify signature
+ def init_node(name: String, master_dir: String,
+ header: Document.Node_Header, perspective: Text.Perspective, text: String)
+ { session_actor !? Init_Node(name, master_dir, header, perspective, text) }
- def edit_node(name: String, master_dir: String, header: Document.Node_Header, edits: List[Text.Edit])
- { session_actor !? Edit_Node(name, master_dir, header, edits) }
+ // FIXME simplify signature
+ def edit_node(name: String, master_dir: String, header: Document.Node_Header,
+ perspective: Text.Perspective, edits: List[Text.Edit])
+ { session_actor !? Edit_Node(name, master_dir, header, perspective, edits) }
}
--- a/src/Pure/Thy/present.ML Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/Thy/present.ML Tue Aug 23 17:12:54 2011 +0200
@@ -289,7 +289,8 @@
val documents =
if doc = "" then []
else if not (can File.check_dir document_path) then
- (if verbose then Output.raw_stderr "Warning: missing document directory\n" else (); [])
+ (if verbose then Output.physical_stderr "Warning: missing document directory\n"
+ else (); [])
else read_variants doc_variants;
val parent_index_path = Path.append Path.parent index_path;
@@ -403,14 +404,14 @@
File.copy (Path.explode "~~/etc/isabelle.css") html_prefix;
List.app finish_html thys;
List.app (uncurry File.write) files;
- if verbose then Output.raw_stderr ("Browser info at " ^ show_path html_prefix ^ "\n")
+ if verbose then Output.physical_stderr ("Browser info at " ^ show_path html_prefix ^ "\n")
else ())
else ();
val _ =
(case dump_prefix of NONE => () | SOME (cp, path) =>
(prepare_sources cp path;
- if verbose then Output.raw_stderr ("Document sources at " ^ show_path path ^ "\n")
+ if verbose then Output.physical_stderr ("Document sources at " ^ show_path path ^ "\n")
else ()));
val doc_paths =
@@ -421,7 +422,8 @@
in isabelle_document true doc_format name tags path html_prefix end);
val _ =
if verbose then
- doc_paths |> List.app (fn doc => Output.raw_stderr ("Document at " ^ show_path doc ^ "\n"))
+ doc_paths
+ |> List.app (fn doc => Output.physical_stderr ("Document at " ^ show_path doc ^ "\n"))
else ();
in
browser_info := empty_browser_info;
--- a/src/Pure/Thy/thy_syntax.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Pure/Thy/thy_syntax.scala Tue Aug 23 17:12:54 2011 +0200
@@ -97,6 +97,37 @@
+ /** command perspective **/
+
+ def command_perspective(node: Document.Node, perspective: Text.Perspective): Command.Perspective =
+ {
+ if (perspective.isEmpty) Nil
+ else {
+ val result = new mutable.ListBuffer[Command]
+ @tailrec
+ def check_ranges(ranges: List[Text.Range], commands: Stream[(Command, Text.Offset)])
+ {
+ (ranges, commands) match {
+ case (range :: more_ranges, (command, offset) #:: more_commands) =>
+ val command_range = command.range + offset
+ range compare command_range match {
+ case -1 => check_ranges(more_ranges, commands)
+ case 0 =>
+ result += command
+ check_ranges(ranges, more_commands)
+ case 1 => check_ranges(ranges, more_commands)
+ }
+ case _ =>
+ }
+ }
+ val perspective_range = Text.Range(perspective.head.start, perspective.last.stop)
+ check_ranges(perspective, node.command_range(perspective_range).toStream)
+ result.toList
+ }
+ }
+
+
+
/** text edits **/
def text_edits(
@@ -138,7 +169,7 @@
@tailrec def recover_spans(commands: Linear_Set[Command]): Linear_Set[Command] =
{
- commands.iterator.find(_.is_unparsed) match {
+ commands.iterator.find(cmd => !cmd.is_defined) match {
case Some(first_unparsed) =>
val first =
commands.reverse_iterator(first_unparsed).
@@ -210,6 +241,14 @@
doc_edits += (name -> Document.Node.Header(header))
nodes += (name -> node.copy(header = header))
}
+
+ case (name, Document.Node.Perspective(text_perspective)) =>
+ val node = nodes(name)
+ val perspective = command_perspective(node, text_perspective)
+ if (!Command.equal_perspective(node.perspective, perspective)) {
+ doc_edits += (name -> Document.Node.Perspective(perspective))
+ nodes += (name -> node.copy(perspective = perspective))
+ }
}
(doc_edits.toList, Document.Version(Document.new_id(), nodes))
}
--- a/src/Tools/jEdit/src/document_model.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Tools/jEdit/src/document_model.scala Tue Aug 23 17:12:54 2011 +0200
@@ -60,10 +60,29 @@
class Document_Model(val session: Session, val buffer: Buffer,
val master_dir: String, val node_name: String, val thy_name: String)
{
- /* pending text edits */
+ /* header */
def node_header(): Exn.Result[Thy_Header] =
+ {
+ Swing_Thread.require()
Exn.capture { Thy_Header.check(thy_name, buffer.getSegment(0, buffer.getLength)) }
+ }
+
+
+ /* perspective */
+
+ def perspective(): Text.Perspective =
+ {
+ Swing_Thread.require()
+ Text.perspective(
+ for {
+ doc_view <- Isabelle.document_views(buffer)
+ range <- doc_view.perspective()
+ } yield range)
+ }
+
+
+ /* pending text edits */
private object pending_edits // owned by Swing thread
{
@@ -77,14 +96,15 @@
case Nil =>
case edits =>
pending.clear
- session.edit_node(node_name, master_dir, node_header(), edits)
+ session.edit_node(node_name, master_dir, node_header(), perspective(), edits)
}
}
def init()
{
flush()
- session.init_node(node_name, master_dir, node_header(), Isabelle.buffer_text(buffer))
+ session.init_node(node_name, master_dir,
+ node_header(), perspective(), Isabelle.buffer_text(buffer))
}
private val delay_flush =
--- a/src/Tools/jEdit/src/document_view.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Tools/jEdit/src/document_view.scala Tue Aug 23 17:12:54 2011 +0200
@@ -10,6 +10,7 @@
import isabelle._
+import scala.collection.mutable
import scala.actors.Actor._
import java.lang.System
@@ -86,7 +87,7 @@
}
- /* visible line ranges */
+ /* visible text range */
// simplify slightly odd result of TextArea.getScreenLineEndOffset etc.
// NB: jEdit already normalizes \r\n and \r to \n
@@ -96,14 +97,14 @@
Text.Range(start, stop)
}
- def screen_lines_range(): Text.Range =
+ def visible_range(): Text.Range =
{
val start = text_area.getScreenLineStartOffset(0)
val raw_end = text_area.getScreenLineEndOffset(text_area.getVisibleLines - 1 max 0)
proper_line_range(start, if (raw_end >= 0) raw_end else model.buffer.getLength)
}
- def invalidate_line_range(range: Text.Range)
+ def invalidate_range(range: Text.Range)
{
text_area.invalidateLineRange(
model.buffer.getLineOfOffset(range.start),
@@ -111,6 +112,22 @@
}
+ /* perspective */
+
+ def perspective(): Text.Perspective =
+ {
+ Swing_Thread.require()
+ Text.perspective(
+ for {
+ i <- 0 until text_area.getVisibleLines
+ val start = text_area.getScreenLineStartOffset(i)
+ val stop = text_area.getScreenLineEndOffset(i)
+ if start >= 0 && stop >= 0
+ }
+ yield Text.Range(start, stop))
+ }
+
+
/* snapshot */
// owned by Swing thread
@@ -224,9 +241,9 @@
if (control) init_popup(snapshot, x, y)
- _highlight_range map { case (range, _) => invalidate_line_range(range) }
+ _highlight_range map { case (range, _) => invalidate_range(range) }
_highlight_range = if (control) subexp_range(snapshot, x, y) else None
- _highlight_range map { case (range, _) => invalidate_line_range(range) }
+ _highlight_range map { case (range, _) => invalidate_range(range) }
}
}
}
@@ -415,15 +432,15 @@
val buffer = model.buffer
Isabelle.swing_buffer_lock(buffer) {
val (updated, snapshot) = flush_snapshot()
- val visible_range = screen_lines_range()
+ val visible = visible_range()
if (updated || changed.exists(snapshot.node.commands.contains))
overview.repaint()
- if (updated) invalidate_line_range(visible_range)
+ if (updated) invalidate_range(visible)
else {
val visible_cmds =
- snapshot.node.command_range(snapshot.revert(visible_range)).map(_._1)
+ snapshot.node.command_range(snapshot.revert(visible)).map(_._1)
if (visible_cmds.exists(changed)) {
for {
line <- 0 until text_area.getVisibleLines
--- a/src/Tools/jEdit/src/plugin.scala Tue Aug 23 16:37:23 2011 +0200
+++ b/src/Tools/jEdit/src/plugin.scala Tue Aug 23 17:12:54 2011 +0200
@@ -199,6 +199,13 @@
def document_model(buffer: Buffer): Option[Document_Model] = Document_Model(buffer)
def document_view(text_area: JEditTextArea): Option[Document_View] = Document_View(text_area)
+ def document_views(buffer: Buffer): List[Document_View] =
+ for {
+ text_area <- jedit_text_areas(buffer).toList
+ val doc_view = document_view(text_area)
+ if doc_view.isDefined
+ } yield doc_view.get
+
def init_model(buffer: Buffer)
{
swing_buffer_lock(buffer) {