5 Isabelle configuration for Proof General (see http://proofgeneral.inf.ed.ac.uk) |
5 Isabelle configuration for Proof General (see http://proofgeneral.inf.ed.ac.uk) |
6 Includes support for PGIP control language for Isabelle/Isar. |
6 Includes support for PGIP control language for Isabelle/Isar. |
7 |
7 |
8 =========================================================================== |
8 =========================================================================== |
9 NOTE: With this version you will lose support for the Isabelle |
9 NOTE: With this version you will lose support for the Isabelle |
10 preferences menu in the currently released version of Proof General (3.5). |
10 settings menu in the currently released version of Proof General (3.5). |
11 No other changes should be visible in the Emacs interface. |
11 No other changes should be visible in the Emacs interface. |
12 |
12 |
13 If the loss of preferences is a serious problem, please use a "sticky" |
13 The 3.6pre pre-release versions of Emacs Proof General now support the |
14 check-out of the previous version of this file, version 1.27. |
14 new PGIP format for preferences and restore the settings menu. |
15 |
15 Please visit http://proofgeneral.inf.ed.ac.uk/develdownload |
16 A version of Emacs Proof General which supports the new PGIP format for |
|
17 preferences will be available shortly. |
|
18 =========================================================================== |
16 =========================================================================== |
19 |
17 |
20 STATUS: this version is an experimental version that supports PGIP 2.X. |
18 STATUS: this version is an experimental version that supports PGIP 2.X. |
21 |
19 |
22 *) |
20 *) |
201 fun assemble_pgip resp attrs s = assemble_pgips [XML.element resp attrs [s]] |
199 fun assemble_pgip resp attrs s = assemble_pgips [XML.element resp attrs [s]] |
202 |
200 |
203 fun assemble_pgipe resp attrs = assemble_pgips [XML.element resp attrs []] |
201 fun assemble_pgipe resp attrs = assemble_pgips [XML.element resp attrs []] |
204 |
202 |
205 (* FIXME: need to add stuff to gather PGIPs here *) |
203 (* FIXME: need to add stuff to gather PGIPs here *) |
206 fun issue_pgip resp attrs = writeln_default o (assemble_pgip resp attrs) |
204 fun issue_pgip resp attrs txt = |
|
205 if pgip_emacs_compatibility() then |
|
206 decorated_output (* add urgent message annotation *) |
|
207 (oct_char "360") (oct_char "361") "" |
|
208 (assemble_pgip resp attrs txt) |
|
209 else |
|
210 writeln_default (assemble_pgip resp attrs txt) |
207 |
211 |
208 (* FIXME: temporarily to support PG 3.4. *) |
212 (* FIXME: temporarily to support PG 3.4. *) |
209 fun issue_pgip_maybe_decorated bg en resp attrs s = |
213 fun issue_pgip_maybe_decorated bg en resp attrs s = |
210 if pgip_emacs_compatibility() then |
214 if pgip_emacs_compatibility() then |
211 (* in PGIP mode, but using escape characters as well. *) |
215 (* in PGIP mode, but using escape characters as well. *) |
217 |
221 |
218 end |
222 end |
219 |
223 |
220 (* messages and notification *) |
224 (* messages and notification *) |
221 |
225 |
222 fun message resp attrs bg en prfx s = |
226 local |
223 if pgip() then |
227 val delay_msgs = ref false (* whether to accumulate messages *) |
224 issue_pgip_maybe_decorated bg en resp attrs (prefix_lines prfx s) |
228 val delayed_msgs = ref [] |
225 else |
229 in |
226 decorated_output bg en prfx s; |
230 |
227 |
231 fun message resp attrs bg en prfx s = |
|
232 if pgip() then |
|
233 (if (!delay_msgs) then |
|
234 delayed_msgs := (resp,attrs,prefix_lines prfx s)::(!delayed_msgs) (* nb: no decs *) |
|
235 else |
|
236 issue_pgip_maybe_decorated bg en resp attrs (prefix_lines prfx s)) |
|
237 else |
|
238 decorated_output bg en prfx s; |
|
239 |
|
240 fun start_delay_msgs () = (delay_msgs := true; |
|
241 delayed_msgs := []) |
|
242 |
|
243 fun end_delayed_msgs () = |
|
244 (delay_msgs := false; |
|
245 map (fn (resp,attrs,s) => XML.element resp attrs [s]) (!delayed_msgs)) |
|
246 end |
228 |
247 |
229 local |
248 local |
230 val display_area = ("area", "display") |
249 val display_area = ("area", "display") |
231 val message_area = ("area", "message") |
250 val message_area = ("area", "message") |
232 val tracing_category = ("category", "tracing") |
251 val tracing_category = ("category", "tracing") |
491 in |
508 in |
492 |
509 |
493 fun nat_option r = (pgipnat, |
510 fun nat_option r = (pgipnat, |
494 withdefault (fn () => string_of_int (!r)), |
511 withdefault (fn () => string_of_int (!r)), |
495 (fn s => (case Syntax.read_nat s of |
512 (fn s => (case Syntax.read_nat s of |
496 None => error "nat_option: illegal value" |
513 None => error ("nat_option: illegal value " ^ s) |
497 | Some i => r := i))); |
514 | Some i => r := i))); |
498 |
515 |
499 fun bool_option r = (pgipbool, |
516 fun bool_option r = (pgipbool, |
500 withdefault (fn () => Bool.toString (!r)), |
517 withdefault (fn () => Bool.toString (!r)), |
501 (fn "false" => r := false | "true" => r := true |
518 (fn "false" => r := false | "true" => r := true |
502 | _ => error "bool_option: illegal value")); |
519 | x => error ("bool_option: illegal value" ^ x))); |
503 |
520 |
504 val proof_option = (pgipbool, |
521 val proof_option = (pgipbool, |
505 withdefault (fn () => Bool.toString (!proofs >= 2)), |
522 withdefault (fn () => Bool.toString (!proofs >= 2)), |
506 (fn "false" => proofs := 1 | "true" => proofs := 2 |
523 (fn "false" => proofs := 1 | "true" => proofs := 2 |
507 | _ => error "proof_option: illegal value")); |
524 | x => error ("proof_option: illegal value" ^ x))); |
508 |
525 |
509 val thm_deps_option = (pgipbool, |
526 val thm_deps_option = (pgipbool, |
510 withdefault (fn () => Bool.toString (Output.has_mode "thm_deps")), |
527 withdefault (fn () => Bool.toString (Output.has_mode "thm_deps")), |
511 (fn "false" => print_mode := ((!print_mode) \ "thm_deps") |
528 (fn "false" => print_mode := ((!print_mode) \ "thm_deps") |
512 | "true" => print_mode := ("thm_deps" ins (!print_mode)) |
529 | "true" => print_mode := ("thm_deps" ins (!print_mode)) |
513 | _ => error "thm_deps_option: illegal value")); |
530 | x => error ("thm_deps_option: illegal value " ^ x))); |
514 |
531 |
515 local |
532 local |
516 val pg_print_depth_val = ref 10 |
533 val pg_print_depth_val = ref 10 |
517 fun pg_print_depth n = (print_depth n; pg_print_depth_val := n) |
534 fun pg_print_depth n = (print_depth n; pg_print_depth_val := n) |
518 in |
535 in |
519 val print_depth_option = (pgipnat, |
536 val print_depth_option = (pgipnat, |
520 withdefault (fn () => string_of_int (!pg_print_depth_val)), |
537 withdefault (fn () => string_of_int (!pg_print_depth_val)), |
521 (fn s => (case Syntax.read_nat s of |
538 (fn s => (case Syntax.read_nat s of |
522 None => error "print_depth_option: illegal value" |
539 None => error ("print_depth_option: illegal value" ^ s) |
523 | Some i => pg_print_depth i))) |
540 | Some i => pg_print_depth i))) |
524 end |
541 end |
525 |
542 |
526 val preferences = ref |
543 val preferences = ref |
527 [("Display", |
544 [("Display", |
749 |
766 |
750 fun xmls_of_thy_begin (name,toks,str) = (* see isar_syn.ML/theoryP *) |
767 fun xmls_of_thy_begin (name,toks,str) = (* see isar_syn.ML/theoryP *) |
751 let |
768 let |
752 val ((thyname,imports,files),_) = ThyHeader.args (toks@sync) |
769 val ((thyname,imports,files),_) = ThyHeader.args (toks@sync) |
753 in |
770 in |
754 markup_text_attrs str "opentheory" [("thyname",thyname)] |
771 markup_text_attrs str "opentheory" [("thyname",thyname), |
|
772 ("parentnames", space_implode ";" imports)] |
755 end |
773 end |
756 |
774 |
757 fun xmls_of_thy_decl (name,toks,str) = (* see isar_syn.ML/thy_decl cases *) |
775 fun xmls_of_thy_decl (name,toks,str) = (* see isar_syn.ML/thy_decl cases *) |
758 let |
776 let |
759 (* NB: PGIP only deals with single name bindings at the moment; |
777 (* NB: PGIP only deals with single name bindings at the moment; |
903 else match_tokens (t::ts,ws,w::vs) |
923 else match_tokens (t::ts,ws,w::vs) |
904 | match_tokens _ = error ("match_tokens: mismatched input parse") |
924 | match_tokens _ = error ("match_tokens: mismatched input parse") |
905 in |
925 in |
906 fun xmls_of_str str = |
926 fun xmls_of_str str = |
907 let |
927 let |
908 val toks = OuterSyntax.scan str |
|
909 |
|
910 (* parsing: See outer_syntax.ML/toplevel_source *) |
928 (* parsing: See outer_syntax.ML/toplevel_source *) |
911 |
|
912 fun parse_loop ([],[],xmls) = xmls |
929 fun parse_loop ([],[],xmls) = xmls |
913 | parse_loop ([],itoks,xmls) = xmls @ (xmls_of_impropers itoks) |
930 | parse_loop ([],itoks,xmls) = xmls @ (xmls_of_impropers itoks) |
914 | parse_loop ((nm,toks,_)::trs,itoks,xmls) = |
931 | parse_loop ((nm,toks,_)::trs,itoks,xmls) = |
915 let |
932 let |
916 (* first proper token is command, except FIXME for -- *) |
933 (* first proper token is command, except FIXME for -- *) |
926 val xmls_tr = xmls_of_transition (nm,str,toks) |
943 val xmls_tr = xmls_of_transition (nm,str,toks) |
927 in |
944 in |
928 parse_loop(trs,itoks'',xmls @ xmls_whs @ xmls_tr) |
945 parse_loop(trs,itoks'',xmls @ xmls_whs @ xmls_tr) |
929 end |
946 end |
930 in |
947 in |
931 (* FIXME: put errors/warnings inside the parse result *) |
948 (let val toks = OuterSyntax.scan str |
932 parse_loop (OuterSyntax.read toks, toks, []) |
949 in |
|
950 parse_loop (OuterSyntax.read toks, toks, []) |
|
951 end) |
|
952 handle _ => markup_unparseable str |
933 end |
953 end |
934 |
954 |
935 |
955 |
936 fun parsescript str = |
956 fun parsescript str attrs = |
937 issue_pgips [XML.element "parseresult" [] (xmls_of_str str)] |
957 let |
938 |
958 val _ = start_delay_msgs () (* accumulate error messages to put inside parseresult *) |
|
959 val xmls = xmls_of_str str |
|
960 val errs = end_delayed_msgs () |
|
961 in |
|
962 issue_pgips [XML.element "parseresult" attrs (errs@xmls)] |
|
963 end |
939 end |
964 end |
940 |
965 |
941 |
966 |
942 |
967 |
943 (**** PGIP: Isabelle -> Interface ****) |
968 (**** PGIP: Isabelle -> Interface ****) |
1008 (* instead of error we could guess theory? *) |
1033 (* instead of error we could guess theory? *) |
1009 | other => error ("Don't know how to read a file with extension " ^ other) |
1034 | other => error ("Don't know how to read a file with extension " ^ other) |
1010 end |
1035 end |
1011 |
1036 |
1012 |
1037 |
1013 local |
1038 (* Proof control commands *) |
1014 (* Proof control commands *) |
1039 |
1015 |
1040 local |
1016 fun xmlattro attrs attr = assoc(attrs,attr) |
1041 fun xmlattro attr attrs = assoc(attrs,attr) |
1017 |
1042 |
1018 fun xmlattr attrs attr = |
1043 fun xmlattr attr attrs = |
1019 (case xmlattro attrs attr of |
1044 (case xmlattro attr attrs of |
1020 Some value => value |
1045 Some value => value |
1021 | None => raise PGIP ("Missing attribute: " ^ attr)) |
1046 | None => raise PGIP ("Missing attribute: " ^ attr)) |
1022 |
1047 |
1023 val thyname_attr = "thyname" |
1048 val thyname_attro = xmlattro "thyname" |
1024 val objtype_attr = "objtype" |
1049 val thyname_attr = xmlattr "thyname" |
1025 val name_attr = "name" |
1050 val objtype_attro = xmlattro "objtype" |
1026 val dirname_attr = "dir" |
1051 val objtype_attr = xmlattr "objtype" |
|
1052 val name_attr = xmlattr "name" |
|
1053 val dirname_attr = xmlattr "dir" |
1027 fun comment x = "(* " ^ x ^ " *)" |
1054 fun comment x = "(* " ^ x ^ " *)" |
1028 |
1055 |
1029 (* parse URLs like "file://host/name.thy" *) |
1056 fun localfile_of_url url = (* only handle file:/// or file://localhost/ *) |
1030 (* FIXME: instead of this, extend code in General/url.ML & use that. *) |
1057 case Url.unpack url of |
1031 fun decode_url url = |
1058 (Url.File path) => File.sysify_path path |
1032 (let |
1059 | _ => error ("Cannot access non-local URL " ^ url) |
1033 val sep = find_index_eq ":" (explode url) |
1060 |
1034 val proto = String.substring(url,0,sep) |
1061 val fileurl_of = localfile_of_url o (xmlattr "url") |
1035 val hostsep = find_index_eq "/" (drop (sep+3,explode url)) |
|
1036 val host = String.substring(url,sep+3,hostsep-sep+4) |
|
1037 val doc = if (size url >= sep+hostsep+3) then |
|
1038 String.substring(url,sep+hostsep+4,size url-hostsep-sep-4) |
|
1039 else "" |
|
1040 in |
|
1041 (proto,host,doc) |
|
1042 end) handle Subscript => error ("Badly formed URL " ^ url) |
|
1043 |
|
1044 fun localfile_of_url url = |
|
1045 let |
|
1046 val (proto,host,name) = decode_url url |
|
1047 in |
|
1048 if (proto = "file" andalso |
|
1049 (host = "" orelse |
|
1050 host = "localhost" orelse |
|
1051 host = (getenv "HOSTNAME"))) |
|
1052 then name |
|
1053 else error ("Cannot access non-local URL " ^ url) |
|
1054 end |
|
1055 |
|
1056 fun fileurl_of attrs = localfile_of_url (xmlattr attrs "url") |
|
1057 |
1062 |
1058 val topthy = Toplevel.theory_of o Toplevel.get_state |
1063 val topthy = Toplevel.theory_of o Toplevel.get_state |
1059 val topthy_name = PureThy.get_name o topthy |
1064 val topthy_name = PureThy.get_name o topthy |
1060 |
1065 |
1061 val currently_open_file = ref (None : string option) |
1066 val currently_open_file = ref (None : string option) |
1062 |
|
1063 in |
1067 in |
1064 |
1068 |
1065 fun process_pgip_element pgipxml = (case pgipxml of |
1069 fun process_pgip_element pgipxml = (case pgipxml of |
1066 (XML.Text t) => warning ("Ignored text in PGIP packet: \n" ^ t) |
1070 (XML.Text t) => warning ("Ignored text in PGIP packet: \n" ^ t) |
1067 | (XML.Elem (xml as (elem, attrs, data))) => |
1071 | (xml as (XML.Elem (elem, attrs, data))) => |
1068 (case elem of |
1072 (case elem of |
1069 (* protocol config *) |
1073 (* protocol config *) |
1070 "askpgip" => (usespgip (); send_pgip_config ()) |
1074 "askpgip" => (usespgip (); send_pgip_config ()) |
1071 | "askpgml" => usespgml () |
1075 | "askpgml" => usespgml () |
1072 (* proverconfig *) |
1076 (* proverconfig *) |
1073 | "askprefs" => hasprefs () |
1077 | "askprefs" => hasprefs () |
1074 | "getpref" => getpref (xmlattr attrs name_attr) |
1078 | "getpref" => getpref (name_attr attrs) |
1075 | "setpref" => setpref (xmlattr attrs name_attr) (xmltext data) |
1079 | "setpref" => setpref (name_attr attrs) (xmltext data) |
1076 (* provercontrol *) |
1080 (* provercontrol *) |
1077 | "proverinit" => isar_restart () |
1081 | "proverinit" => isar_restart () |
1078 | "proverexit" => isarcmd "quit" |
1082 | "proverexit" => isarcmd "quit" |
1079 | "startquiet" => isarcmd "disable_pr" |
1083 | "startquiet" => isarcmd "disable_pr" |
1080 | "stopquiet" => isarcmd "enable_pr" |
1084 | "stopquiet" => isarcmd "enable_pr" |
1096 | "undostep" => isarcmd "ProofGeneral.undo" |
1100 | "undostep" => isarcmd "ProofGeneral.undo" |
1097 | "abortgoal" => isarcmd "ProofGeneral.kill_proof" |
1101 | "abortgoal" => isarcmd "ProofGeneral.kill_proof" |
1098 | "forget" => error "Not implemented" |
1102 | "forget" => error "Not implemented" |
1099 | "restoregoal" => error "Not implemented" (* could just treat as forget? *) |
1103 | "restoregoal" => error "Not implemented" (* could just treat as forget? *) |
1100 (* proofctxt: improper commands *) |
1104 (* proofctxt: improper commands *) |
1101 | "askids" => askids (xmlattro attrs thyname_attr, |
1105 | "askids" => askids (thyname_attro attrs, objtype_attro attrs) |
1102 xmlattro attrs objtype_attr) |
1106 | "showid" => showid (thyname_attro attrs, objtype_attr attrs, name_attr attrs) |
1103 | "showid" => showid (xmlattro attrs thyname_attr, |
1107 | "parsescript" => parsescript (xmltext data) attrs (* just pass back attrs unchanged *) |
1104 xmlattr attrs objtype_attr, |
|
1105 xmlattr attrs name_attr) |
|
1106 | "parsescript" => parsescript (xmltext data) |
|
1107 | "showproofstate" => isarcmd "pr" |
1108 | "showproofstate" => isarcmd "pr" |
1108 | "showctxt" => isarcmd "print_theory" (* more useful than print_context *) |
1109 | "showctxt" => isarcmd "print_theory" (* more useful than print_context *) |
1109 | "searchtheorems" => isarcmd ("thms_containing " ^ (xmltext data)) |
1110 | "searchtheorems" => isarcmd ("thms_containing " ^ (xmltext data)) |
1110 | "setlinewidth" => isarcmd ("pretty_setmargin " ^ (xmltext data)) |
1111 | "setlinewidth" => isarcmd ("pretty_setmargin " ^ (xmltext data)) |
1111 | "viewdoc" => isarcmd ("print_" ^ (xmltext data)) (* FIXME: isatool doc? *) |
1112 | "viewdoc" => isarcmd ("print_" ^ (xmltext data)) (* FIXME: isatool doc? *) |
1114 | "theoryitem" => isarscript data |
1115 | "theoryitem" => isarscript data |
1115 | "closetheory" => (isarscript data; |
1116 | "closetheory" => (isarscript data; |
1116 writeln ("Theory "^(topthy_name())^" completed.")) |
1117 writeln ("Theory "^(topthy_name())^" completed.")) |
1117 (* improperfilecmd: theory-level commands not in script *) |
1118 (* improperfilecmd: theory-level commands not in script *) |
1118 | "aborttheory" => isarcmd ("init_toplevel") |
1119 | "aborttheory" => isarcmd ("init_toplevel") |
1119 | "retracttheory" => isarcmd ("kill_thy " ^ |
1120 | "retracttheory" => isarcmd ("kill_thy " ^ (quote (thyname_attr attrs))) |
1120 (quote (xmlattr attrs thyname_attr))) |
1121 | "loadfile" => use_thy_or_ml_file (fileurl_of attrs) |
1121 | "loadfile" => use_thy_or_ml_file (fileurl_of attrs) |
|
1122 | "openfile" => (inform_file_retracted (fileurl_of attrs); |
1122 | "openfile" => (inform_file_retracted (fileurl_of attrs); |
1123 currently_open_file := Some (fileurl_of attrs)) |
1123 currently_open_file := Some (fileurl_of attrs)) |
1124 | "closefile" => (case !currently_open_file of |
1124 | "closefile" => (case !currently_open_file of |
1125 Some f => (inform_file_processed f; |
1125 Some f => (inform_file_processed f; |
1126 currently_open_file := None) |
1126 currently_open_file := None) |
1127 | None => raise PGIP ("closefile when no file is open!")) |
1127 | None => raise PGIP ("closefile when no file is open!")) |
1128 | "abortfile" => (currently_open_file := None) (* perhaps error for no file open *) |
1128 | "abortfile" => (currently_open_file := None) (* perhaps error for no file open *) |
1129 | "changecwd" => ThyLoad.add_path (xmlattr attrs dirname_attr) |
1129 | "changecwd" => ThyLoad.add_path (dirname_attr attrs) |
1130 | "systemcmd" => isarscript data |
1130 | "systemcmd" => isarscript data |
1131 (* unofficial command for debugging *) |
1131 (* unofficial command for debugging *) |
1132 | "quitpgip" => raise PGIP_QUIT |
1132 | "quitpgip" => raise PGIP_QUIT |
1133 | _ => raise PGIP ("Unrecognized PGIP element: " ^ elem))) |
1133 | _ => raise PGIP ("Unrecognized PGIP element: " ^ elem))) |
1134 |
1134 |
1135 fun process_pgip_tree s = |
1135 fun process_pgip_tree xml = |
1136 (pgip_refseq := None; |
1136 (pgip_refseq := None; |
1137 pgip_refid := None; |
1137 pgip_refid := None; |
1138 (case s of |
1138 (case xml of |
1139 XML.Elem ("pgip", attrs, pgips) => |
1139 XML.Elem ("pgip", attrs, pgips) => |
1140 (let |
1140 (let |
1141 val class = xmlattr attrs "class" |
1141 val class = xmlattr "class" attrs |
1142 val _ = (pgip_refseq := xmlattro attrs "seq"; |
1142 val _ = (pgip_refseq := xmlattro "seq" attrs; |
1143 pgip_refid := xmlattro attrs "id") |
1143 pgip_refid := xmlattro "id" attrs) |
1144 in |
1144 in |
1145 if (class = "pa") then |
1145 if (class = "pa") then |
1146 seq process_pgip_element pgips |
1146 seq process_pgip_element pgips |
1147 else |
1147 else |
1148 raise PGIP "PGIP packet for me should have class=\"pa\"" |
1148 raise PGIP "PGIP packet for me should have class=\"pa\"" |
1149 end) |
1149 end) |
1150 | _ => raise PGIP "Invalid PGIP packet received") |
1150 | _ => raise PGIP "Invalid PGIP packet received") |
1151 handle (PGIP msg) => |
1151 handle (PGIP msg) => |
1152 (error (msg ^ "\nPGIP error occured in XML text below:\n" ^ |
1152 (error (msg ^ "\nPGIP error occured in XML text below:\n" ^ |
1153 (XML.string_of_tree s)))) |
1153 (XML.string_of_tree xml)))) |
1154 |
1154 |
1155 (* for export to Emacs *) |
1155 (* for export to Emacs *) |
1156 (* val process_pgip = process_pgip_tree o XML.tree_of_string; *) |
1156 (* val process_pgip = process_pgip_tree o XML.tree_of_string; *) |
1157 (* FIXME: for temporary compatibility with PG 3.4, we engage special characters |
1157 (* FIXME: for temporary compatibility with PG 3.4, we engage special characters |
1158 during output *) |
1158 during output *) |