1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
(*
Isabelle configuration for Proof General.
Author: David Aspinall <da@dcs.ed.ac.uk>
Contact: Isabelle maintainer <isabelle@dcs.ed.ac.uk>
$Id$
*)
(*
use "/home/da/isa-patches/thy_read.ML";
open ThyRead;
*)
signature PROOFGENERAL =
sig
val kill_goal : unit -> unit
val help : unit -> unit
val show_context : unit -> unit
val retract_ML_file : string -> unit
val retract_thy_file : string -> unit
val repeat_undo : int -> unit
val clear_response_buffer : unit -> unit
val list_loaded_files : unit -> unit
val use_thy_and_update : string -> unit
val special_theories : string list ref
end;
structure ProofGeneral =
struct
(* Some top-level commands for Proof General.
These easily could be customized to do different things.
*)
fun kill_goal () = Goal "PROP no_goal_supplied";
fun help () = print version;
fun show_context () = the_context();
(* Function used internally by Proof General to track
dependencies between theory and ML files. *)
fun retract_file1 not_thy filename =
let val (path, tname) = split_filename filename
fun file_msg x = if (x <> "") then
writeln ("Proof General, you can unlock the file "
^ (quote x))
else ()
fun show_msgs thy =
let val (thy_file, ml_file) = get_thy_filenames (path_of thy) thy
in (if not_thy then ()
else file_msg thy_file;
file_msg ml_file) end
fun already_loaded thy =
let val t = get_thyinfo thy
in if is_none t then false
else let val {thy_time, ml_time, ...} = the t
in is_some thy_time andalso is_some ml_time end
end
fun children_loaded thy =
let val children = children_of thy
val present = filter (is_some o get_thyinfo) children;
in filter already_loaded present end
in
if already_loaded tname then
(show_msgs tname;
map (retract_file1 false) (children_loaded tname); ())
else ()
end;
(* retract a script file and all it's theory/script children,
but not it's parent theory. *)
val retract_ML_file = retract_file1 true;
(* retract a theory file and all it's theory/script children *)
val retract_thy_file = retract_file1 false;
fun repeat_undo 0 = ()
| repeat_undo n = (undo(); repeat_undo (n-1));
fun clear_response_buffer () =
writeln("Proof General, please clear the response buffer.");
val special_theories = ref ["ProtoPure", "Pure", "CPure"];
fun list_loaded_files () =
let
val thys_list = Symtab.dest (!loaded_thys)
fun loading_msg (tname,tinfo) =
if (tname mem (!special_theories)) then () else
let val path = path_of tname
val (thy_file,ml_file) = get_thy_filenames path tname
fun file_msg x = if (x <> "") then
(* Simulate output of theory loader *)
writeln ("Reading " ^ (quote x))
else ()
in
(file_msg thy_file; file_msg ml_file)
end
in
(writeln "Updating loaded files list...";
seq loading_msg thys_list;
writeln "Done.")
end;
(*
Possible alternative: parse "children are out of date"
message, and unlock those ones (plus descendants).
This seems feasible, but use_thy ought to do update
anyway, I think.
*)
fun use_thy_and_update thy =
(use_thy_no_topml thy;
update();
list_loaded_files();
clear_response_buffer());
end; (* struct ProofGeneral *)
fun remove_mlfile_fromdb thy =
let val tinfo = case Symtab.lookup (!loaded_thys, thy) of
Some ({path, children, parents = parents, thy_time, theory,...}) =>
{ path = path, children = children, parents = parents, theory=theory,
thy_time = thy_time, ml_time = None }
| None => error
("remove_mlfile_from_db: theory " ^ thy ^ " not found");
in loaded_thys := Symtab.update ((thy, tinfo), !loaded_thys) end;
(*
fun use_thy_and_update thy =
(use_thy_no_topml thy; (* don't read ML but will be in db [useful bug]*)
update () (* fixup dependencies left broken by use_thy
(question: can it re-read the top ML, though?? hope not) *)
handle exn =>
(remove_mlfile_fromdb thy handle _ => raise exn; raise exn);
remove_mlfile_fromdb thy);
*)
(* Temporary hack. *)
(*
NB: this has bad behaviour because update will force loading of
the theory file if used again later. Need a test case for
this, and to fix it.
*)
(* configure output channels to decorate output *)
local
fun quickout s = TextIO.output (TextIO.stdOut, s);
fun out s =
(TextIO.output (TextIO.stdOut, s); TextIO.flushOut TextIO.stdOut);
fun outnl s =
(TextIO.output (TextIO.stdOut, s^"\n"); TextIO.flushOut TextIO.stdOut);
fun prefix_lines_specials spec prfx txt sufx =
txt |> split_lines |> map (fn s => spec ^ prfx ^ s ^ sufx ^ "\n")
|> implode;
(* Problem with writeln: it's hardwired to do out (s^"\n") but
we really want annotations to appear before carriage returns.
This hack deals with the last CR in a string.
*)
fun out_with_hacked_last_cr startspec str endspec =
(quickout startspec;
case (rev (split_lines str)) of
[] => out endspec
| ""::rest => (seq outnl (rev rest);
out endspec)
| _ => (quickout str; out endspec))
in
(* \240 is octal 360, first special character used. *)
val _ =
(prs_fn :=
(fn s => out_with_hacked_last_cr "\240" s "\241");
warning_fn :=
(fn s => out (prefix_lines_specials "\242" "### " s "\243"));
error_fn :=
(fn s => out (prefix_lines_specials "\244" "*** " s "\245")))
end;
(* add markup to proof state output *)
val proof_state_special_prefix="\246"; (* ?\366 *)
val proof_state_special_suffix="\247"; (* ?\367 *)
val goal_start_special="\248"; (* ?\370 *)
current_goals_markers:=(proof_state_special_prefix,
proof_state_special_suffix,
goal_start_special);
local
fun out s =
(TextIO.output (TextIO.stdOut, s); TextIO.flushOut TextIO.stdOut);
in
fun print_current_goals_with_plain_output i j t =
Library.setmp prs_fn out (print_current_goals_default i j) t;
(* Annoyingly, Proof General waits for the first prompt before doing
anything. Hack sending a prompt to get things going *)
val _ = out "> \n";
end;
print_current_goals_fn := print_current_goals_with_plain_output;
(* add specials to ml prompts *)
(*
ml_prompts ">\250" "-\251"; (* ?\372, ?\373 *)
NB: Obscure bug with proof-shell-annotated-prompt-regexp set
properly to include annotations: PG doesn't recognize first proof
state output.
*)
(* Turn on verbose update output, Proof General likes to parse it.
update_verbose:=true;
Unfortunately broken. We use list_loaded_files instead. *)
(* Get Proof General to cache the loaded files. *)
ProofGeneral.list_loaded_files();
ProofGeneral.clear_response_buffer();
writeln "Isabelle Proof General: Isabelle process ready!";
|