| author | wenzelm |
| Sat, 30 Dec 2006 16:08:10 +0100 | |
| changeset 21969 | a8bf1106cb7c |
| parent 21959 | b50182aff75f |
| child 21970 | 1845e43aee93 |
| permissions | -rw-r--r-- |
| 21637 | 1 |
(* Title: Pure/ProofGeneral/proof_general_pgip.ML |
2 |
ID: $Id$ |
|
3 |
Author: David Aspinall and Markus Wenzel |
|
4 |
||
5 |
Isabelle configuration for Proof General using PGIP protocol. |
|
| 21940 | 6 |
See http://proofgeneral.inf.ed.ac.uk/kit |
| 21637 | 7 |
*) |
8 |
||
9 |
signature PROOF_GENERAL_PGIP = |
|
10 |
sig |
|
| 21940 | 11 |
val init_pgip: bool -> unit (* main PGIP loop with true; fail with false *) |
| 21642 | 12 |
|
|
21649
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
13 |
(* These two are just to support the semi-PGIP Emacs mode *) |
| 21940 | 14 |
val init_pgip_channel: (string -> unit) -> unit |
15 |
val process_pgip: string -> unit |
|
| 21637 | 16 |
end |
17 |
||
18 |
structure ProofGeneralPgip : PROOF_GENERAL_PGIP = |
|
19 |
struct |
|
20 |
||
21 |
structure P = OuterParse; |
|
22 |
||
23 |
open Pgip; |
|
24 |
||
| 21949 | 25 |
|
| 21637 | 26 |
(* print modes *) |
27 |
||
28 |
val proof_generalN = "ProofGeneral"; (*token markup (colouring vars, etc.)*) |
|
29 |
val pgmlN = "PGML"; (*XML escapes and PGML symbol elements*) |
|
30 |
val pgmlatomsN = "PGMLatoms"; (*variable kind decorations*) |
|
31 |
val thm_depsN = "thm_deps"; (*meta-information about theorem deps*) |
|
32 |
||
33 |
||
34 |
(* text output: print modes for xsymbol and PGML *) |
|
35 |
||
36 |
local |
|
37 |
||
38 |
fun xsym_output "\\" = "\\\\" |
|
39 |
| xsym_output s = if Symbol.is_raw s then Symbol.decode_raw s else s; |
|
40 |
||
41 |
fun xsymbols_output s = |
|
| 21940 | 42 |
if Output.has_mode Symbol.xsymbolsN andalso exists_string (equal "\\") s then |
| 21637 | 43 |
let val syms = Symbol.explode s |
44 |
in (implode (map xsym_output syms), real (Symbol.length syms)) end |
|
45 |
else Symbol.default_output s; |
|
46 |
||
47 |
(* XML immediately rendered pretty printer. Take care not to double escape *) |
|
48 |
fun pgml_sym s = |
|
49 |
(case Symbol.decode s of |
|
50 |
Symbol.Char s => XML.text s |
|
| 21940 | 51 |
| Symbol.Sym sn => XML.element "sym" [("name", sn)] [XML.text s]
|
| 21637 | 52 |
| Symbol.Ctrl sn => XML.element "ctrl" [("name", sn)] [XML.text s] (* FIXME: no such PGML! *)
|
53 |
| Symbol.Raw s => s); |
|
54 |
||
55 |
fun pgml_output str = |
|
56 |
let val syms = Symbol.explode str |
|
57 |
in (implode (map pgml_sym syms), real (Symbol.length syms)) end; |
|
58 |
||
59 |
in |
|
60 |
||
61 |
fun setup_xsymbols_output () = |
|
| 21940 | 62 |
Output.add_mode Symbol.xsymbolsN |
| 21637 | 63 |
(xsymbols_output, K xsymbols_output, Symbol.default_indent, Symbol.encode_raw); |
64 |
||
65 |
fun setup_pgml_output () = |
|
66 |
Output.add_mode pgmlN |
|
67 |
(pgml_output, K pgml_output, Symbol.default_indent, Symbol.encode_raw); |
|
68 |
||
69 |
end; |
|
70 |
||
71 |
||
72 |
(* token translations *) |
|
73 |
||
74 |
local |
|
75 |
||
76 |
val class_tag = "class" |
|
77 |
val tfree_tag = "tfree" |
|
78 |
val tvar_tag = "tvar" |
|
79 |
val free_tag = "free" |
|
80 |
val bound_tag = "bound" |
|
81 |
val var_tag = "var" |
|
82 |
val skolem_tag = "skolem" |
|
83 |
||
84 |
fun xml_atom kind x = XML.element "atom" [("kind", kind)] [XML.text x];
|
|
85 |
||
| 21940 | 86 |
fun tagit kind x = |
| 21949 | 87 |
(xml_atom kind x, real (Symbol.length (Symbol.explode x))); |
| 21637 | 88 |
|
89 |
fun free_or_skolem x = |
|
90 |
(case try Name.dest_skolem x of |
|
91 |
NONE => tagit free_tag x |
|
92 |
| SOME x' => tagit skolem_tag x'); |
|
93 |
||
94 |
fun var_or_skolem s = |
|
95 |
(case Syntax.read_variable s of |
|
96 |
SOME (x, i) => |
|
97 |
(case try Name.dest_skolem x of |
|
98 |
NONE => tagit var_tag s |
|
99 |
| SOME x' => tagit skolem_tag |
|
100 |
(setmp show_question_marks true Syntax.string_of_vname (x', i))) |
|
101 |
| NONE => tagit var_tag s); |
|
102 |
||
103 |
val proof_general_trans = |
|
104 |
Syntax.tokentrans_mode proof_generalN |
|
105 |
[("class", tagit class_tag),
|
|
106 |
("tfree", tagit tfree_tag),
|
|
107 |
("tvar", tagit tvar_tag),
|
|
108 |
("free", free_or_skolem),
|
|
109 |
("bound", tagit bound_tag),
|
|
110 |
("var", var_or_skolem)];
|
|
111 |
||
112 |
in |
|
113 |
||
114 |
val _ = Context.add_setup (Theory.add_tokentrfuns proof_general_trans); |
|
115 |
||
116 |
end; |
|
117 |
||
118 |
||
119 |
(** assembling and issuing PGIP packets **) |
|
120 |
||
121 |
val pgip_refid = ref NONE: string option ref; |
|
122 |
val pgip_refseq = ref NONE: int option ref; |
|
123 |
||
124 |
local |
|
125 |
val pgip_class = "pg" |
|
126 |
val pgip_tag = "Isabelle/Isar" |
|
127 |
val pgip_id = ref "" |
|
128 |
val pgip_seq = ref 0 |
|
129 |
fun pgip_serial () = inc pgip_seq |
|
130 |
||
131 |
fun assemble_pgips pgips = |
|
| 21940 | 132 |
Pgip { tag = SOME pgip_tag,
|
133 |
class = pgip_class, |
|
134 |
seq = pgip_serial(), |
|
135 |
id = !pgip_id, |
|
136 |
destid = !pgip_refid, |
|
137 |
(* destid=refid since Isabelle only communicates back to sender *) |
|
138 |
refid = !pgip_refid, |
|
139 |
refseq = !pgip_refseq, |
|
140 |
content = pgips } |
|
| 21637 | 141 |
in |
142 |
||
143 |
fun init_pgip_session_id () = |
|
144 |
pgip_id := getenv "HOSTNAME" ^ "/" ^ getenv "USER" ^ "/" ^ |
|
145 |
getenv "ISABELLE_PID" ^ "/" ^ Time.toString (Time.now ()) |
|
146 |
||
147 |
fun matching_pgip_id id = (id = !pgip_id) |
|
148 |
||
| 21940 | 149 |
val output_xml_fn = ref writeln_default |
|
21649
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
150 |
fun output_xml s = (!output_xml_fn) (XML.string_of_tree s); (* TODO: string buffer *) |
| 21637 | 151 |
|
| 21940 | 152 |
fun issue_pgip_rawtext str = |
|
21649
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
153 |
output_xml (PgipOutput.output (assemble_pgips [XML.Rawtext str])) |
| 21637 | 154 |
|
155 |
fun issue_pgips pgipops = |
|
156 |
output_xml (PgipOutput.output (assemble_pgips (map PgipOutput.output pgipops))); |
|
157 |
||
158 |
fun issue_pgip pgipop = |
|
159 |
output_xml (PgipOutput.output (assemble_pgips [PgipOutput.output pgipop])); |
|
160 |
||
161 |
end; |
|
162 |
||
163 |
||
164 |
(** messages and notification **) |
|
165 |
||
166 |
local |
|
167 |
val delay_msgs = ref false (*true: accumulate messages*) |
|
168 |
val delayed_msgs = ref [] |
|
169 |
||
170 |
fun queue_or_issue pgip = |
|
| 21940 | 171 |
if ! delay_msgs then |
172 |
delayed_msgs := pgip :: ! delayed_msgs |
|
173 |
else issue_pgip pgip |
|
| 21637 | 174 |
in |
| 21940 | 175 |
fun normalmsg area cat urgent s = |
176 |
let |
|
177 |
val content = XML.Elem("pgmltext",[],[XML.Rawtext s])
|
|
178 |
val pgip = Normalresponse {area=area,messagecategory=cat,
|
|
179 |
urgent=urgent,content=[content] } |
|
180 |
in |
|
181 |
queue_or_issue pgip |
|
182 |
end |
|
| 21637 | 183 |
|
|
21885
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
184 |
fun errormsg fatality s = |
| 21940 | 185 |
let |
|
21885
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
186 |
val content = XML.Elem("pgmltext",[],[XML.Rawtext s])
|
| 21940 | 187 |
val pgip = Errorresponse {area=NONE,fatality=fatality,
|
188 |
content=[content], |
|
189 |
(* FIXME: pass in locations *) |
|
190 |
location=NONE} |
|
191 |
in |
|
192 |
queue_or_issue pgip |
|
193 |
end |
|
| 21637 | 194 |
|
195 |
fun start_delay_msgs () = (set delay_msgs; delayed_msgs := []) |
|
196 |
fun end_delayed_msgs () = (reset delay_msgs; ! delayed_msgs) |
|
197 |
end; |
|
198 |
||
199 |
(* NB: all of the standard error/message functions now expect already-escaped text. |
|
200 |
FIXME: this may cause us problems now we're generating trees; on the other |
|
| 21940 | 201 |
hand the output functions were tuned some time ago, so it ought to be |
| 21637 | 202 |
enough to use Rawtext always above. *) |
203 |
||
204 |
fun setup_messages () = |
|
|
21885
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
205 |
(writeln_fn := (fn s => normalmsg Message Normal false s); |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
206 |
priority_fn := (fn s => normalmsg Message Normal true s); |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
207 |
tracing_fn := (fn s => normalmsg Message Tracing false s); |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
208 |
info_fn := (fn s => normalmsg Message Information false s); |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
209 |
debug_fn := (fn s => normalmsg Message Internal false s); |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
210 |
warning_fn := (fn s => errormsg Nonfatal s); |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
211 |
error_fn := (fn s => errormsg Fatal s); |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
212 |
panic_fn := (fn s => errormsg Panic s)) |
| 21637 | 213 |
|
214 |
(* immediate messages *) |
|
215 |
||
216 |
fun tell_clear_goals () = issue_pgip (Cleardisplay {area=Display})
|
|
217 |
fun tell_clear_response () = issue_pgip (Cleardisplay {area=Message})
|
|
218 |
fun tell_file_loaded path = issue_pgip (Informfileloaded {url=PgipTypes.pgipurl_of_path path})
|
|
219 |
fun tell_file_retracted path = issue_pgip (Informfileretracted {url=PgipTypes.pgipurl_of_path path})
|
|
220 |
||
221 |
||
222 |
||
223 |
(** theory / proof state output **) |
|
224 |
||
225 |
local |
|
226 |
||
227 |
fun statedisplay prts = |
|
228 |
let |
|
| 21940 | 229 |
val display = Pretty.output (Pretty.chunks prts) |
230 |
val statedisplay = XML.Elem("statedisplay",[], [XML.Rawtext display])
|
|
| 21637 | 231 |
in |
| 21940 | 232 |
issue_pgip (Proofstate {pgml=[XML.Elem("pgml",[],[statedisplay])]})
|
| 21637 | 233 |
end |
234 |
||
235 |
fun print_current_goals n m st = |
|
236 |
statedisplay (Display.pretty_current_goals n m st) |
|
237 |
||
238 |
fun print_state b st = |
|
239 |
statedisplay (Toplevel.pretty_state b st) |
|
240 |
||
241 |
in |
|
242 |
||
243 |
fun setup_state () = |
|
244 |
(Display.print_current_goals_fn := print_current_goals; |
|
245 |
Toplevel.print_state_fn := print_state); |
|
246 |
(* Toplevel.prompt_state_fn := (fn s => suffix (special "372") |
|
| 21940 | 247 |
(Toplevel.prompt_state_default s))); *) |
| 21637 | 248 |
|
249 |
end; |
|
250 |
||
251 |
||
252 |
(* theory loader actions *) |
|
253 |
||
254 |
local |
|
255 |
||
256 |
fun trace_action action name = |
|
257 |
if action = ThyInfo.Update then |
|
258 |
List.app tell_file_loaded (ThyInfo.loaded_files name) |
|
259 |
else if action = ThyInfo.Outdate orelse action = ThyInfo.Remove then |
|
260 |
List.app tell_file_retracted (ThyInfo.loaded_files name) |
|
261 |
else (); |
|
262 |
||
263 |
in |
|
264 |
fun setup_thy_loader () = ThyInfo.add_hook trace_action; |
|
265 |
fun sync_thy_loader () = List.app (trace_action ThyInfo.Update) (ThyInfo.names ()); |
|
266 |
end; |
|
267 |
||
268 |
||
| 21949 | 269 |
(* get informed about files *) |
| 21637 | 270 |
|
|
21858
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
wenzelm
parents:
21655
diff
changeset
|
271 |
val thy_name = Path.implode o #1 o Path.split_ext o Path.base o Path.explode; |
| 21637 | 272 |
|
273 |
val inform_file_retracted = ThyInfo.if_known_thy ThyInfo.remove_thy o thy_name; |
|
274 |
val inform_file_processed = ThyInfo.if_known_thy ThyInfo.touch_child_thys o thy_name; |
|
275 |
||
276 |
fun proper_inform_file_processed file state = |
|
277 |
let val name = thy_name file in |
|
278 |
if Toplevel.is_toplevel state andalso ThyInfo.known_thy name then |
|
279 |
(ThyInfo.touch_child_thys name; |
|
280 |
ThyInfo.pretend_use_thy_only name handle ERROR msg => |
|
281 |
(warning msg; warning ("Failed to register theory: " ^ quote name);
|
|
|
21858
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
wenzelm
parents:
21655
diff
changeset
|
282 |
tell_file_retracted (Path.base (Path.explode file)))) |
| 21637 | 283 |
else raise Toplevel.UNDEF |
284 |
end; |
|
285 |
||
286 |
fun vacuous_inform_file_processed file state = |
|
287 |
(warning ("No theory " ^ quote (thy_name file));
|
|
|
21858
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
wenzelm
parents:
21655
diff
changeset
|
288 |
tell_file_retracted (Path.base (Path.explode file))); |
| 21637 | 289 |
|
290 |
||
291 |
(* restart top-level loop (keeps most state information) *) |
|
292 |
||
293 |
val welcome = priority o Session.welcome; |
|
294 |
||
295 |
fun restart () = |
|
296 |
(sync_thy_loader (); |
|
297 |
tell_clear_goals (); |
|
298 |
tell_clear_response (); |
|
299 |
welcome (); |
|
|
21655
01b2d13153c8
Document structure in pgip_markup.ML. Minor fixes.
aspinall
parents:
21649
diff
changeset
|
300 |
priority "Running new version of PGIP code. In testing."; |
| 21637 | 301 |
raise Toplevel.RESTART) |
302 |
||
303 |
||
304 |
(* theorem dependency output *) |
|
305 |
local |
|
306 |
||
307 |
val spaces_quote = space_implode " " o map quote; |
|
308 |
||
309 |
fun thm_deps_message (thms, deps) = |
|
| 21940 | 310 |
let |
311 |
val valuethms = XML.Elem("value",[("name", "thms")],[XML.Text thms])
|
|
312 |
val valuedeps = XML.Elem("value",[("name", "deps")],[XML.Text deps])
|
|
| 21637 | 313 |
in |
| 21940 | 314 |
issue_pgip (Metainforesponse {attrs=[("infotype", "isabelle_theorem_dependencies")],
|
315 |
content=[valuethms,valuedeps]}) |
|
| 21637 | 316 |
end |
317 |
||
318 |
(* FIXME: check this uses non-transitive closure function here *) |
|
| 21969 | 319 |
fun tell_thm_deps ths = |
320 |
if Output.has_mode thm_depsN then |
|
321 |
let |
|
322 |
val names = filter_out (equal "") (map PureThy.get_name_hint ths); |
|
323 |
val deps = filter_out (equal "") |
|
324 |
(Symtab.keys (fold Proofterm.thms_of_proof |
|
325 |
(map Thm.proof_of ths) Symtab.empty)); |
|
326 |
in |
|
327 |
if null names orelse null deps then () |
|
328 |
else thm_deps_message (spaces_quote names, spaces_quote deps) |
|
329 |
end |
|
330 |
else (); |
|
| 21637 | 331 |
|
332 |
in |
|
333 |
||
334 |
fun setup_present_hook () = |
|
335 |
Present.add_hook (fn _ => fn res => tell_thm_deps (maps #2 res)); |
|
336 |
||
337 |
end; |
|
338 |
||
339 |
(** lexicalstructure element with keywords (PGIP version of elisp keywords file) **) |
|
340 |
||
| 21940 | 341 |
fun lexicalstructure_keywords () = |
| 21637 | 342 |
let val commands = OuterSyntax.dest_keywords () |
| 21940 | 343 |
fun category_of k = if k mem commands then "major" else "minor" |
| 21637 | 344 |
(* NB: we might filter to only include words like elisp case (OuterSyntax.is_keyword). *) |
| 21940 | 345 |
fun keyword_elt (keyword,help,kind,_) = |
346 |
XML.Elem("keyword", [("word", keyword), ("category", category_of kind)],
|
|
347 |
[XML.Elem("shorthelp", [], [XML.Text help])])
|
|
348 |
in |
|
| 21637 | 349 |
(* Also, note we don't call init_outer_syntax here to add interface commands, |
350 |
but they should never appear in scripts anyway so it shouldn't matter *) |
|
351 |
Lexicalstructure {content = map keyword_elt (OuterSyntax.dest_parsers()) }
|
|
352 |
end |
|
353 |
||
354 |
(* TODO: we can issue a lexicalstructure/keyword when the syntax gets extended dynamically; |
|
355 |
hooks needed in outer_syntax.ML to do that. *) |
|
356 |
||
357 |
||
358 |
(* Configuration: GUI config, proverinfo messages *) |
|
359 |
||
360 |
local |
|
361 |
val isabellewww = "http://isabelle.in.tum.de/" |
|
362 |
val staticconfig = "~~/lib/ProofGeneral/pgip_isar.xml" |
|
| 21940 | 363 |
fun orenv v d = case getenv v of "" => d | s => s |
| 21637 | 364 |
fun config_file() = orenv "ISABELLE_PGIPCONFIG" staticconfig |
365 |
fun isabelle_www() = orenv "ISABELLE_HOMEPAGE" isabellewww |
|
366 |
in |
|
367 |
fun send_pgip_config () = |
|
368 |
let |
|
|
21858
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
wenzelm
parents:
21655
diff
changeset
|
369 |
val path = Path.explode (config_file()) |
| 21940 | 370 |
val ex = File.exists path |
| 21637 | 371 |
|
| 21940 | 372 |
val wwwpage = |
373 |
(Url.explode (isabelle_www())) |
|
| 21969 | 374 |
handle ERROR _ => |
| 21940 | 375 |
(Output.panic |
376 |
("Error in URL in environment variable ISABELLE_HOMEPAGE.");
|
|
377 |
Url.explode isabellewww) |
|
378 |
||
379 |
val proverinfo = |
|
| 21637 | 380 |
Proverinfo { name = "Isabelle",
|
| 21940 | 381 |
version = version, |
382 |
instance = Session.name(), |
|
383 |
descr = "The Isabelle/Isar theorem prover", |
|
384 |
url = wwwpage, |
|
385 |
filenameextns = ".thy;" } |
|
| 21637 | 386 |
in |
| 21940 | 387 |
if ex then |
388 |
(issue_pgip proverinfo; |
|
389 |
issue_pgip_rawtext (File.read path); |
|
390 |
issue_pgip (lexicalstructure_keywords())) |
|
| 21637 | 391 |
else Output.panic ("PGIP configuration file \"" ^ config_file() ^ "\" not found")
|
392 |
end; |
|
393 |
end |
|
394 |
||
395 |
||
396 |
||
397 |
||
398 |
(* Sending commands to Isar *) |
|
399 |
||
400 |
fun isarcmd s = |
|
401 |
s |> OuterSyntax.scan |> OuterSyntax.read |
|
|
21885
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
402 |
(*|> map (Toplevel.position (Position.name "PGIP message") o #3)*) |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
403 |
|> map #3 |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
404 |
|> Toplevel.>>>; |
| 21637 | 405 |
|
| 21940 | 406 |
(* TODO: |
|
21885
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
407 |
- apply a command given a transition function, e.g. IsarCmd.undo. |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
408 |
- fix position from path of currently open file [line numbers risk garbling though]. |
|
5a11263bd8cf
Remove obsolete prefixes from error and warning messages.
aspinall
parents:
21867
diff
changeset
|
409 |
*) |
| 21637 | 410 |
|
411 |
(* load an arbitrary file (must be .thy or .ML) *) |
|
412 |
||
413 |
fun use_thy_or_ml_file file = |
|
414 |
let |
|
|
21858
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
wenzelm
parents:
21655
diff
changeset
|
415 |
val (path,extn) = Path.split_ext (Path.explode file) |
| 21637 | 416 |
in |
417 |
case extn of |
|
| 21940 | 418 |
"" => isarcmd ("use_thy " ^ quote (Path.implode path))
|
419 |
| "thy" => isarcmd ("use_thy " ^ quote (Path.implode path))
|
|
| 21637 | 420 |
| "ML" => isarcmd ("use " ^ quote file)
|
421 |
| other => error ("Don't know how to read a file with extension " ^ other)
|
|
422 |
end |
|
423 |
||
424 |
||
| 21867 | 425 |
(******* PGIP actions *******) |
| 21637 | 426 |
|
427 |
||
| 21940 | 428 |
(* Responses to each of the PGIP input commands. |
| 21637 | 429 |
These are programmed uniformly for extensibility. *) |
430 |
||
| 21940 | 431 |
fun askpgip (Askpgip vs) = |
| 21637 | 432 |
issue_pgip |
433 |
(Usespgip { version = PgipIsabelle.isabelle_pgip_version_supported,
|
|
| 21940 | 434 |
pgipelems = PgipIsabelle.accepted_inputs }) |
| 21637 | 435 |
|
| 21940 | 436 |
fun askpgml (Askpgml vs) = |
| 21637 | 437 |
issue_pgip |
| 21940 | 438 |
(Usespgml { version = PgipIsabelle.isabelle_pgml_version_supported })
|
| 21637 | 439 |
|
| 21902 | 440 |
fun askprefs (Askprefs vs) = |
| 21940 | 441 |
let |
442 |
fun preference_of {name, descr, default, pgiptype, get, set } =
|
|
443 |
{ name = name, descr = SOME descr, default = SOME default,
|
|
444 |
pgiptype = pgiptype } |
|
| 21637 | 445 |
in |
| 21940 | 446 |
List.app (fn (prefcat, prefs) => |
447 |
issue_pgip (Hasprefs {prefcategory=SOME prefcat,
|
|
448 |
prefs=map preference_of prefs})) |
|
| 21637 | 449 |
Preferences.preferences |
| 21940 | 450 |
end |
| 21637 | 451 |
|
| 21902 | 452 |
fun askconfig (Askconfig vs) = () (* TODO: add config response *) |
| 21637 | 453 |
|
454 |
local |
|
| 21940 | 455 |
fun lookuppref pref = |
456 |
case AList.lookup (op =) |
|
457 |
(map (fn p => (#name p,p)) |
|
458 |
(maps snd Preferences.preferences)) pref of |
|
459 |
NONE => error ("Unknown prover preference: " ^ quote pref)
|
|
460 |
| SOME p => p |
|
| 21637 | 461 |
in |
| 21940 | 462 |
fun setpref (Setpref vs) = |
463 |
let |
|
464 |
val name = #name vs |
|
465 |
val value = #value vs |
|
466 |
val set = #set (lookuppref name) |
|
| 21637 | 467 |
in |
| 21940 | 468 |
set value |
| 21637 | 469 |
end |
470 |
||
| 21902 | 471 |
fun getpref (Getpref vs) = |
| 21940 | 472 |
let |
473 |
val name = #name vs |
|
474 |
val get = #get (lookuppref name) |
|
475 |
in |
|
| 21637 | 476 |
issue_pgip (Prefval {name=name, value=get ()})
|
477 |
end |
|
478 |
end |
|
479 |
||
480 |
fun proverinit vs = restart () |
|
481 |
||
482 |
fun proverexit vs = isarcmd "quit" |
|
483 |
||
484 |
fun startquiet vs = isarcmd "disable_pr" |
|
485 |
||
486 |
fun stopquiet vs = isarcmd "enable_pr" |
|
487 |
||
| 21940 | 488 |
fun pgmlsymbolson vs = |
| 21637 | 489 |
change print_mode (fn mode => |
| 21940 | 490 |
remove (op =) Symbol.xsymbolsN mode @ [Symbol.xsymbolsN]) |
| 21637 | 491 |
|
492 |
fun pgmlsymbolsoff vs = |
|
493 |
change print_mode (remove (op =) Symbol.xsymbolsN) |
|
494 |
||
| 21940 | 495 |
fun dostep (Dostep vs) = |
496 |
let |
|
497 |
val text = #text vs |
|
498 |
in |
|
499 |
isarcmd text |
|
| 21637 | 500 |
end |
501 |
||
| 21902 | 502 |
fun undostep (Undostep vs) = |
| 21940 | 503 |
let |
504 |
val times = #times vs |
|
505 |
in |
|
506 |
isarcmd ("undos_proof " ^ Int.toString times)
|
|
| 21637 | 507 |
end |
508 |
||
509 |
fun redostep vs = isarcmd "redo" |
|
| 21940 | 510 |
|
511 |
fun abortgoal vs = isarcmd "ProofGeneral.kill_proof" |
|
| 21637 | 512 |
|
513 |
||
| 21867 | 514 |
(*** PGIP identifier tables ***) |
515 |
||
516 |
fun setids t = issue_pgip (Setids {idtables = [t]})
|
|
517 |
fun addids t = issue_pgip (Addids {idtables = [t]})
|
|
518 |
fun delids t = issue_pgip (Delids {idtables = [t]})
|
|
519 |
||
520 |
(* |
|
| 21940 | 521 |
fun delallids ty = |
522 |
issue_pgip (Setids {idtables =
|
|
523 |
[{context=NONE,objtype=ty,ids=[]}]}) *)
|
|
| 21867 | 524 |
|
| 21940 | 525 |
fun askids (Askids vs) = |
| 21637 | 526 |
let |
| 21940 | 527 |
val url = #url vs (* ask for identifiers within a file *) |
528 |
val thyname = #thyname vs (* ask for identifiers within a theory *) |
|
529 |
val objtype = #objtype vs (* ask for identifiers of a particular type *) |
|
| 21867 | 530 |
|
| 21940 | 531 |
fun idtable ty ctx ids = {objtype=ty,context=ctx,ids=ids}
|
| 21867 | 532 |
|
| 21940 | 533 |
val thms_of_thy = map fst o PureThy.thms_of o ThyInfo.get_theory |
534 |
in |
|
535 |
(* case (url_attr,thyname,objtype) of |
|
536 |
(NONE,NONE,NONE) => |
|
537 |
*) (* top-level: return *) |
|
| 21867 | 538 |
|
| 21940 | 539 |
(* TODO: add askids for "file" here, which returns single theory with same name *) |
| 21867 | 540 |
(* FIXME: objtypes on both sides *) |
| 21940 | 541 |
case (thyname,objtype) of |
| 21867 | 542 |
(* only files known in top context *) |
| 21940 | 543 |
(NONE, NONE) => setids (idtable ObjFile NONE (ThyInfo.names())) (*FIXME: uris?*) |
544 |
| (NONE, SOME ObjFile) => setids (idtable ObjFile NONE (ThyInfo.names())) (* ditto *) |
|
545 |
| (SOME fi, SOME ObjFile) => setids (idtable ObjTheory (SOME fi) [fi]) (* FIXME: lookup file *) |
|
546 |
| (NONE, SOME ObjTheory) => setids (idtable ObjTheory NONE (ThyInfo.names())) |
|
547 |
| (SOME thy, SOME ObjTheory) => setids (idtable ObjTheory (SOME thy) (ThyInfo.get_preds thy)) |
|
548 |
| (SOME thy, SOME ObjTheorem) => setids (idtable ObjTheorem (SOME thy) (thms_of_thy thy)) |
|
549 |
(* next case is both of above. FIXME: cleanup this *) |
|
550 |
| (SOME thy, NONE) => (setids (idtable ObjTheory (SOME thy) (ThyInfo.get_preds thy)); |
|
551 |
setids (idtable ObjTheorem (SOME thy) (thms_of_thy thy))) |
|
552 |
| (_, SOME ot) => error ("No objects of type "^(PgipTypes.name_of_objtype ot)^" are available here.")
|
|
| 21637 | 553 |
end |
554 |
||
555 |
local |
|
556 |
(* accumulate printed output in a single PGIP response (inside <pgmltext>) *) |
|
557 |
fun with_displaywrap pgipfn dispfn = |
|
558 |
let |
|
| 21940 | 559 |
val lines = ref ([]: string list); |
560 |
fun wlgrablines s = lines := s :: ! lines; |
|
| 21637 | 561 |
in |
| 21940 | 562 |
setmp writeln_fn wlgrablines dispfn (); |
563 |
issue_pgip (pgipfn (!lines)) |
|
| 21637 | 564 |
end; |
565 |
in |
|
| 21940 | 566 |
fun showid (Showid vs) = |
| 21637 | 567 |
let |
| 21940 | 568 |
val thyname = #thyname vs |
569 |
val objtype = #objtype vs |
|
570 |
val name = #name vs |
|
571 |
val topthy = Toplevel.theory_of o Toplevel.get_state |
|
| 21637 | 572 |
|
| 21940 | 573 |
fun idvalue objtype name strings = |
574 |
Idvalue { name=name, objtype=objtype,
|
|
575 |
text=[XML.Elem("pgmltext",[],map XML.Text strings)] }
|
|
| 21637 | 576 |
|
| 21940 | 577 |
fun pthm thy name = print_thm (get_thm thy (Name name)) |
578 |
in |
|
579 |
case (thyname, objtype) of |
|
580 |
(_,ObjTheory) => |
|
581 |
with_displaywrap (idvalue ObjTheory name) |
|
582 |
(fn ()=>(print_theory (ThyInfo.get_theory name))) |
|
583 |
| (SOME thy, ObjTheorem) => |
|
584 |
with_displaywrap (idvalue ObjTheorem name) |
|
585 |
(fn ()=>(pthm (ThyInfo.get_theory thy) name)) |
|
586 |
| (NONE, ObjTheorem) => |
|
587 |
with_displaywrap (idvalue ObjTheorem name) |
|
588 |
(fn ()=>pthm (topthy()) name) |
|
589 |
| (_, ot) => error ("Cannot show objects of type "^(PgipTypes.name_of_objtype ot))
|
|
| 21637 | 590 |
end |
591 |
||
| 21867 | 592 |
(*** Inspecting state ***) |
593 |
||
| 21940 | 594 |
(* The file which is currently being processed interactively. |
| 21637 | 595 |
In the pre-PGIP code, this was informed to Isabelle and the theory loader |
596 |
on completion, but that allows for circularity in case we read |
|
597 |
ourselves. So PGIP opens the filename at the start of a script. |
|
598 |
We ought to prevent problems by modifying the theory loader to know |
|
| 21940 | 599 |
about this special status, but for now we just keep a local reference. |
600 |
*) |
|
| 21637 | 601 |
|
602 |
val currently_open_file = ref (NONE : pgipurl option) |
|
603 |
||
| 21940 | 604 |
fun askguise vs = |
| 21637 | 605 |
(* The "guise" is the PGIP abstraction of the prover's state. |
606 |
The <informguise> message is merely used for consistency checking. *) |
|
| 21940 | 607 |
let |
608 |
val openfile = !currently_open_file |
|
| 21637 | 609 |
|
| 21940 | 610 |
val topthy = Toplevel.theory_of o Toplevel.get_state |
611 |
val topthy_name = Context.theory_name o topthy |
|
| 21637 | 612 |
|
| 21940 | 613 |
val opentheory = SOME (topthy_name()) handle Toplevel.UNDEF => NONE |
| 21637 | 614 |
|
| 21940 | 615 |
fun topproofpos () = try Toplevel.proof_position_of (Isar.state ()); |
616 |
val openproofpos = topproofpos() |
|
| 21637 | 617 |
in |
618 |
issue_pgip (Informguise { file = openfile,
|
|
| 21940 | 619 |
theory = opentheory, |
620 |
(* would be nice to get thm name... *) |
|
621 |
theorem = NONE, |
|
622 |
proofpos = openproofpos }) |
|
| 21637 | 623 |
end |
624 |
||
| 21902 | 625 |
fun parsescript (Parsescript vs) = |
| 21637 | 626 |
let |
| 21940 | 627 |
val text = #text vs |
628 |
val systemdata = #systemdata vs |
|
629 |
val location = #location vs (* TODO: extract position *) |
|
| 21637 | 630 |
|
| 21867 | 631 |
val _ = start_delay_msgs () (* gather parsing errs/warns *) |
632 |
val doc = PgipParser.pgip_parser text |
|
| 21637 | 633 |
val errs = end_delayed_msgs () |
634 |
||
| 21940 | 635 |
val sysattrs = PgipTypes.opt_attr "systemdata" systemdata |
636 |
val locattrs = PgipTypes.attrs_of_location location |
|
| 21637 | 637 |
in |
638 |
issue_pgip (Parseresult { attrs= sysattrs@locattrs,
|
|
| 21940 | 639 |
doc = doc, |
640 |
errs = map PgipOutput.output errs }) |
|
| 21637 | 641 |
end |
642 |
||
643 |
fun showproofstate vs = isarcmd "pr" |
|
644 |
||
| 21969 | 645 |
fun showctxt vs = isarcmd "print_context" |
| 21637 | 646 |
|
| 21902 | 647 |
fun searchtheorems (Searchtheorems vs) = |
| 21940 | 648 |
let |
649 |
val arg = #arg vs |
|
| 21637 | 650 |
in |
| 21969 | 651 |
isarcmd ("find_theorems " ^ arg)
|
| 21637 | 652 |
end |
653 |
||
| 21940 | 654 |
fun setlinewidth (Setlinewidth vs) = |
655 |
let |
|
656 |
val width = #width vs |
|
| 21637 | 657 |
in |
| 21940 | 658 |
isarcmd ("pretty_setmargin " ^ Int.toString width) (* FIXME: conversion back/forth! *)
|
| 21637 | 659 |
end |
660 |
||
| 21902 | 661 |
fun viewdoc (Viewdoc vs) = |
| 21940 | 662 |
let |
663 |
val arg = #arg vs |
|
664 |
in |
|
665 |
isarcmd ("print_" ^ arg) (* FIXME: isatool doc?. Return URLs, maybe? *)
|
|
| 21637 | 666 |
end |
667 |
||
| 21867 | 668 |
(*** Theory ***) |
669 |
||
| 21902 | 670 |
fun doitem (Doitem vs) = |
| 21637 | 671 |
let |
| 21940 | 672 |
val text = #text vs |
| 21637 | 673 |
in |
| 21940 | 674 |
isarcmd text |
| 21637 | 675 |
end |
676 |
||
677 |
fun undoitem vs = |
|
678 |
isarcmd "ProofGeneral.undo" |
|
679 |
||
680 |
fun redoitem vs = |
|
681 |
isarcmd "ProofGeneral.redo" |
|
682 |
||
| 21940 | 683 |
fun aborttheory vs = |
| 21637 | 684 |
isarcmd "init_toplevel" |
685 |
||
| 21902 | 686 |
fun retracttheory (Retracttheory vs) = |
| 21940 | 687 |
let |
688 |
val thyname = #thyname vs |
|
| 21637 | 689 |
in |
| 21940 | 690 |
isarcmd ("kill_thy " ^ quote thyname)
|
| 21637 | 691 |
end |
692 |
||
| 21867 | 693 |
|
694 |
(*** Files ***) |
|
695 |
||
696 |
(* Path management: we allow theory files to have dependencies in |
|
697 |
their own directory, but when we change directory for a new file we |
|
698 |
remove the path. Leaving it there can cause confusion with |
|
699 |
difference in batch mode. |
|
| 21940 | 700 |
NB: PGIP does not assume that the prover has a load path. |
| 21867 | 701 |
*) |
702 |
||
703 |
local |
|
704 |
val current_working_dir = ref (NONE : string option) |
|
705 |
in |
|
| 21940 | 706 |
fun changecwd_dir newdirpath = |
707 |
let |
|
| 21867 | 708 |
val newdir = File.platform_path newdirpath |
| 21940 | 709 |
in |
| 21867 | 710 |
(case (!current_working_dir) of |
711 |
NONE => () |
|
712 |
| SOME dir => ThyLoad.del_path dir; |
|
713 |
ThyLoad.add_path newdir; |
|
714 |
current_working_dir := SOME newdir) |
|
715 |
end |
|
716 |
end |
|
717 |
||
| 21940 | 718 |
fun changecwd (Changecwd vs) = |
719 |
let |
|
720 |
val url = #url vs |
|
721 |
val newdir = PgipTypes.path_of_pgipurl url |
|
| 21867 | 722 |
in |
| 21940 | 723 |
changecwd_dir url |
| 21867 | 724 |
end |
725 |
||
| 21902 | 726 |
fun openfile (Openfile vs) = |
| 21940 | 727 |
let |
| 21867 | 728 |
val url = #url vs |
729 |
val filepath = PgipTypes.path_of_pgipurl url |
|
730 |
val filedir = Path.dir filepath |
|
731 |
val thy_name = Path.implode o #1 o Path.split_ext o Path.base |
|
732 |
val openfile_retract = Output.no_warnings (ThyInfo.if_known_thy ThyInfo.remove_thy) o thy_name; |
|
733 |
in |
|
734 |
case !currently_open_file of |
|
735 |
SOME f => raise PGIP ("<openfile> when a file is already open! ")
|
|
736 |
| NONE => (openfile_retract filepath; |
|
| 21940 | 737 |
changecwd_dir filedir; |
738 |
currently_open_file := SOME url) |
|
| 21867 | 739 |
end |
740 |
||
741 |
fun closefile vs = |
|
742 |
case !currently_open_file of |
|
| 21940 | 743 |
SOME f => (proper_inform_file_processed (File.platform_path f) |
744 |
(Isar.state()); |
|
| 21867 | 745 |
currently_open_file := NONE) |
746 |
| NONE => raise PGIP ("<closefile> when no file is open!")
|
|
747 |
||
| 21940 | 748 |
fun loadfile (Loadfile vs) = |
749 |
let |
|
750 |
val url = #url vs |
|
751 |
in |
|
752 |
case !currently_open_file of |
|
| 21637 | 753 |
SOME f => raise PGIP ("<loadfile> when a file is open!")
|
754 |
| NONE => use_thy_or_ml_file (File.platform_path url) |
|
755 |
end |
|
756 |
||
757 |
fun abortfile vs = |
|
758 |
case !currently_open_file of |
|
759 |
SOME f => (isarcmd "init_toplevel"; |
|
| 21940 | 760 |
currently_open_file := NONE) |
| 21637 | 761 |
| NONE => raise PGIP ("<abortfile> when no file is open!")
|
762 |
||
| 21940 | 763 |
fun retractfile (Retractfile vs) = |
764 |
let |
|
765 |
val url = #url vs |
|
| 21637 | 766 |
in |
| 21940 | 767 |
case !currently_open_file of |
| 21637 | 768 |
SOME f => raise PGIP ("<retractfile> when a file is open!")
|
769 |
| NONE => inform_file_retracted (File.platform_path url) |
|
770 |
end |
|
771 |
||
772 |
||
| 21867 | 773 |
(*** System ***) |
| 21637 | 774 |
|
| 21902 | 775 |
fun systemcmd (Systemcmd vs) = |
| 21940 | 776 |
let |
| 21637 | 777 |
val arg = #arg vs |
778 |
in |
|
779 |
isarcmd arg |
|
780 |
end |
|
781 |
||
782 |
exception PGIP_QUIT; |
|
783 |
fun quitpgip vs = raise PGIP_QUIT |
|
784 |
||
| 21902 | 785 |
fun process_input inp = case inp |
786 |
of Pgip.Askpgip _ => askpgip inp |
|
787 |
| Pgip.Askpgml _ => askpgml inp |
|
| 21940 | 788 |
| Pgip.Askprefs _ => askprefs inp |
| 21902 | 789 |
| Pgip.Askconfig _ => askconfig inp |
790 |
| Pgip.Getpref _ => getpref inp |
|
791 |
| Pgip.Setpref _ => setpref inp |
|
792 |
| Pgip.Proverinit _ => proverinit inp |
|
793 |
| Pgip.Proverexit _ => proverexit inp |
|
794 |
| Pgip.Startquiet _ => startquiet inp |
|
795 |
| Pgip.Stopquiet _ => stopquiet inp |
|
796 |
| Pgip.Pgmlsymbolson _ => pgmlsymbolson inp |
|
797 |
| Pgip.Pgmlsymbolsoff _ => pgmlsymbolsoff inp |
|
798 |
| Pgip.Dostep _ => dostep inp |
|
799 |
| Pgip.Undostep _ => undostep inp |
|
800 |
| Pgip.Redostep _ => redostep inp |
|
801 |
| Pgip.Forget _ => error "<forget> not implemented" |
|
802 |
| Pgip.Restoregoal _ => error "<restoregoal> not implemented" |
|
803 |
| Pgip.Abortgoal _ => abortgoal inp |
|
804 |
| Pgip.Askids _ => askids inp |
|
805 |
| Pgip.Showid _ => showid inp |
|
806 |
| Pgip.Askguise _ => askguise inp |
|
807 |
| Pgip.Parsescript _ => parsescript inp |
|
808 |
| Pgip.Showproofstate _ => showproofstate inp |
|
809 |
| Pgip.Showctxt _ => showctxt inp |
|
810 |
| Pgip.Searchtheorems _ => searchtheorems inp |
|
811 |
| Pgip.Setlinewidth _ => setlinewidth inp |
|
812 |
| Pgip.Viewdoc _ => viewdoc inp |
|
813 |
| Pgip.Doitem _ => doitem inp |
|
814 |
| Pgip.Undoitem _ => undoitem inp |
|
815 |
| Pgip.Redoitem _ => redoitem inp |
|
816 |
| Pgip.Aborttheory _ => aborttheory inp |
|
817 |
| Pgip.Retracttheory _ => retracttheory inp |
|
818 |
| Pgip.Loadfile _ => loadfile inp |
|
819 |
| Pgip.Openfile _ => openfile inp |
|
820 |
| Pgip.Closefile _ => closefile inp |
|
821 |
| Pgip.Abortfile _ => abortfile inp |
|
822 |
| Pgip.Retractfile _ => retractfile inp |
|
823 |
| Pgip.Changecwd _ => changecwd inp |
|
824 |
| Pgip.Systemcmd _ => systemcmd inp |
|
825 |
| Pgip.Quitpgip _ => quitpgip inp |
|
| 21637 | 826 |
|
827 |
||
| 21940 | 828 |
fun process_pgip_element pgipxml = |
| 21637 | 829 |
case pgipxml of |
| 21969 | 830 |
xml as (XML.Elem elem) => |
| 21940 | 831 |
(case Pgip.input elem of |
832 |
NONE => warning ("Unrecognized PGIP command, ignored: \n" ^
|
|
833 |
(XML.string_of_tree xml)) |
|
834 |
| SOME inp => (process_input inp)) (* errors later; packet discarded *) |
|
| 21969 | 835 |
| XML.Text t => ignored_text_warning t |
836 |
| XML.Rawtext t => ignored_text_warning t |
|
| 21637 | 837 |
and ignored_text_warning t = |
| 21940 | 838 |
if size (Symbol.strip_blanks t) > 0 then |
839 |
warning ("Ignored text in PGIP packet: \n" ^ t)
|
|
| 21637 | 840 |
else () |
841 |
||
842 |
fun process_pgip_tree xml = |
|
843 |
(pgip_refid := NONE; |
|
844 |
pgip_refseq := NONE; |
|
845 |
(case xml of |
|
846 |
XML.Elem ("pgip", attrs, pgips) =>
|
|
847 |
(let |
|
848 |
val class = PgipTypes.get_attr "class" attrs |
|
849 |
val dest = PgipTypes.get_attr_opt "destid" attrs |
|
| 21940 | 850 |
val seq = PgipTypes.read_pgipnat (PgipTypes.get_attr "seq" attrs) |
| 21637 | 851 |
(* Respond to prover broadcasts, or messages for us. Ignore rest *) |
| 21940 | 852 |
val processit = |
853 |
case dest of |
|
| 21637 | 854 |
NONE => class = "pa" |
| 21940 | 855 |
| SOME id => matching_pgip_id id |
856 |
in if processit then |
|
857 |
(pgip_refid := PgipTypes.get_attr_opt "id" attrs; |
|
858 |
pgip_refseq := SOME seq; |
|
859 |
List.app process_pgip_element pgips; |
|
860 |
(* return true to indicate <ready/> *) |
|
861 |
true) |
|
862 |
else |
|
863 |
(* no response to ignored messages. *) |
|
864 |
false |
|
| 21637 | 865 |
end) |
866 |
| _ => raise PGIP "Invalid PGIP packet received") |
|
867 |
handle PGIP msg => |
|
868 |
(Output.error_msg ((msg ^ "\nPGIP error occured in XML text below:\n") ^ |
|
| 21940 | 869 |
(XML.string_of_tree xml)); |
870 |
true)) |
|
| 21637 | 871 |
|
|
21649
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
872 |
(* External input *) |
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
873 |
|
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
874 |
val process_pgip_plain = K () o process_pgip_tree o XML.tree_of_string |
| 21637 | 875 |
|
876 |
end |
|
877 |
||
878 |
||
879 |
(* PGIP loop: process PGIP input only *) |
|
880 |
||
881 |
local |
|
882 |
||
883 |
exception XML_PARSE |
|
884 |
||
885 |
fun loop ready src = |
|
886 |
let |
|
887 |
val _ = if ready then issue_pgip (Ready ()) else () |
|
| 21969 | 888 |
val pgipo = |
889 |
(case try Source.get_single src of |
|
890 |
SOME pgipo => pgipo |
|
891 |
| NONE => raise XML_PARSE) |
|
| 21637 | 892 |
in |
893 |
case pgipo of |
|
894 |
NONE => () |
|
895 |
| SOME (pgip,src') => |
|
896 |
let |
|
| 21940 | 897 |
val ready' = (process_pgip_tree pgip) |
898 |
handle e => (handler (e,SOME src'); true) |
|
| 21637 | 899 |
in |
900 |
loop ready' src' |
|
901 |
end |
|
902 |
end handle e => handler (e,SOME src) (* error in XML parse or Ready issue *) |
|
903 |
||
904 |
and handler (e,srco) = |
|
905 |
case (e,srco) of |
|
906 |
(XML_PARSE,SOME src) => |
|
907 |
Output.panic "Invalid XML input, aborting" |
|
908 |
| (PGIP_QUIT,_) => () |
|
| 21940 | 909 |
| (Interrupt,SOME src) => |
910 |
(Output.error_msg "Interrupt during PGIP processing"; loop true src) |
|
911 |
| (Toplevel.UNDEF,SOME src) => |
|
912 |
(Output.error_msg "No working context defined"; loop true src) |
|
913 |
| (e,SOME src) => |
|
914 |
(Output.error_msg (Toplevel.exn_message e); loop true src) |
|
| 21637 | 915 |
| (_,NONE) => () |
916 |
in |
|
917 |
(* TODO: add socket interface *) |
|
918 |
||
919 |
val xmlP = XML.scan_comment_whspc |-- XML.parse_elem >> single |
|
920 |
||
921 |
val tty_src = Source.set_prompt "" (Source.source Symbol.stopper xmlP NONE Source.tty) |
|
922 |
||
923 |
fun pgip_toplevel x = loop true x |
|
924 |
end |
|
925 |
||
926 |
||
| 21940 | 927 |
(* additional outer syntax for Isar *) |
| 21637 | 928 |
(* da: TODO: perhaps we can drop this superfluous syntax now?? |
929 |
Seems cleaner to support the operations directly above in the PGIP actions. |
|
930 |
*) |
|
931 |
||
932 |
local structure P = OuterParse and K = OuterKeyword in |
|
933 |
||
934 |
val undoP = (*undo without output*) |
|
935 |
OuterSyntax.improper_command "ProofGeneral.undo" "(internal)" K.control |
|
936 |
(Scan.succeed (Toplevel.no_timing o IsarCmd.undo)); |
|
937 |
||
938 |
val redoP = (*redo without output*) |
|
939 |
OuterSyntax.improper_command "ProofGeneral.redo" "(internal)" K.control |
|
940 |
(Scan.succeed (Toplevel.no_timing o IsarCmd.redo)); |
|
941 |
||
942 |
(* ProofGeneral.kill_proof still used above *) |
|
943 |
val kill_proofP = |
|
944 |
OuterSyntax.improper_command "ProofGeneral.kill_proof" "(internal)" K.control |
|
945 |
(Scan.succeed (Toplevel.no_timing o IsarCmd.kill_proof_notify tell_clear_goals)); |
|
946 |
||
947 |
(* FIXME: Not quite same as commands used above *) |
|
948 |
val inform_file_processedP = |
|
949 |
OuterSyntax.improper_command "ProofGeneral.inform_file_processed" "(internal)" K.control |
|
950 |
(P.name >> (fn file => Toplevel.no_timing o |
|
| 21959 | 951 |
Toplevel.init_empty (vacuous_inform_file_processed file) o |
| 21637 | 952 |
Toplevel.kill o |
| 21959 | 953 |
Toplevel.init_empty (proper_inform_file_processed file))); |
| 21637 | 954 |
|
955 |
val inform_file_retractedP = |
|
956 |
OuterSyntax.improper_command "ProofGeneral.inform_file_retracted" "(internal)" K.control |
|
957 |
(P.name >> (Toplevel.no_timing oo |
|
958 |
(fn file => Toplevel.imperative (fn () => inform_file_retracted file)))); |
|
959 |
||
960 |
(* This one can actually be used for Daniel's interface scripting idea: generically!! *) |
|
961 |
val process_pgipP = |
|
962 |
OuterSyntax.improper_command "ProofGeneral.process_pgip" "(internal)" K.control |
|
963 |
(P.text >> (Toplevel.no_timing oo |
|
|
21649
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
964 |
(fn txt => Toplevel.imperative (fn () => process_pgip_plain txt)))); |
| 21637 | 965 |
|
966 |
fun init_outer_syntax () = OuterSyntax.add_parsers |
|
| 21949 | 967 |
[undoP, redoP, kill_proofP, inform_file_processedP, inform_file_retractedP, process_pgipP]; |
| 21637 | 968 |
|
969 |
end; |
|
970 |
||
971 |
||
972 |
(* init *) |
|
973 |
||
974 |
val initialized = ref false; |
|
975 |
||
| 21969 | 976 |
fun init_pgip false = |
977 |
Output.panic "No Proof General interface support for Isabelle/classic mode." |
|
978 |
| init_pgip true = |
|
979 |
(! initialized orelse |
|
980 |
(setmp warning_fn (K ()) init_outer_syntax (); |
|
981 |
setup_xsymbols_output (); |
|
982 |
setup_pgml_output (); |
|
983 |
setup_messages (); |
|
984 |
setup_state (); |
|
985 |
setup_thy_loader (); |
|
986 |
setup_present_hook (); |
|
987 |
init_pgip_session_id (); |
|
988 |
welcome (); |
|
989 |
set initialized); |
|
990 |
sync_thy_loader (); |
|
991 |
change print_mode (cons proof_generalN o remove (op =) proof_generalN); |
|
992 |
change print_mode (append [pgmlN, pgmlatomsN] o subtract (op =) [pgmlN, pgmlatomsN]); |
|
993 |
pgip_toplevel tty_src); |
|
| 21637 | 994 |
|
|
21649
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
995 |
|
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
996 |
|
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
997 |
(** Out-of-loop PGIP commands (for Emacs hybrid mode) **) |
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
998 |
|
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
999 |
local |
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1000 |
val pgip_output_channel = ref writeln_default |
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1001 |
in |
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1002 |
|
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1003 |
(* Set recipient for PGIP results *) |
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1004 |
fun init_pgip_channel writefn = |
| 21940 | 1005 |
(init_pgip_session_id(); |
1006 |
pgip_output_channel := writefn) |
|
|
21649
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1007 |
|
| 21940 | 1008 |
(* Process a PGIP command. |
1009 |
This works for preferences but not generally guaranteed |
|
|
21649
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1010 |
because we haven't done full setup here (e.g., no pgml mode) *) |
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1011 |
fun process_pgip str = |
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1012 |
setmp output_xml_fn (!pgip_output_channel) process_pgip_plain str |
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1013 |
|
|
40e6fdd26f82
Support PGIP communication for preferences in Emacs mode.
aspinall
parents:
21646
diff
changeset
|
1014 |
end |
| 21637 | 1015 |
|
1016 |
end; |
|
1017 |