diff options
| -rw-r--r-- | ide/command_windows.ml | 7 | ||||
| -rw-r--r-- | ide/command_windows.mli | 2 | ||||
| -rw-r--r-- | ide/coq.ml | 53 | ||||
| -rw-r--r-- | ide/coq.mli | 10 | ||||
| -rw-r--r-- | ide/coqide.ml | 96 | ||||
| -rw-r--r-- | ide/typed_notebook.ml | 4 | ||||
| -rw-r--r-- | lib/lib.mllib | 1 | ||||
| -rw-r--r-- | lib/safe_marshal.ml | 11 | ||||
| -rw-r--r-- | toplevel/coqtop.ml | 16 | ||||
| -rw-r--r-- | toplevel/ide_blob.ml | 25 | ||||
| -rw-r--r-- | toplevel/ide_blob.mli | 3 |
11 files changed, 158 insertions, 70 deletions
diff --git a/ide/command_windows.ml b/ide/command_windows.ml index beb8ebb526..1b768de9a2 100644 --- a/ide/command_windows.ml +++ b/ide/command_windows.ml @@ -6,6 +6,8 @@ (* * GNU Lesser General Public License Version 2.1 *) (************************************************************************) +let get_current_toplevel = ref (fun () -> Coq.dummy_coqtop) + class command_window () = (* let window = GWindow.window ~allow_grow:true ~allow_shrink:true @@ -104,9 +106,10 @@ object(self) then com ^ " " else com ^ " " ^ entry#text ^" . " in try - Coq.raw_interp Coq.dummy_coqtop phrase; + let curtop = !get_current_toplevel () in + Coq.raw_interp curtop phrase; result#buffer#set_text - ("Result for command " ^ phrase ^ ":\n" ^ (Coq.read_stdout Coq.dummy_coqtop)) + ("Result for command " ^ phrase ^ ":\n" ^ (Coq.read_stdout curtop)) with e -> let (s,loc) = Coq.process_exn e in assert (Glib.Utf8.validate s); diff --git a/ide/command_windows.mli b/ide/command_windows.mli index b211afabdc..24e79cb933 100644 --- a/ide/command_windows.mli +++ b/ide/command_windows.mli @@ -17,4 +17,4 @@ class command_window : val command_window : unit -> command_window - +val get_current_toplevel : (unit -> Coq.coqtop) ref diff --git a/ide/coq.ml b/ide/coq.ml index f385ae0489..fecd3f2922 100644 --- a/ide/coq.ml +++ b/ide/coq.ml @@ -47,9 +47,8 @@ let msg m = let msgnl m = (msg m)^"\n" -let init () = - Coqtop.init_ide (List.tl (Array.to_list Sys.argv)) - +let init () = List.tl (Array.to_list Sys.argv) +(* Coqtop.init_ide (List.tl (Array.to_list Sys.argv))*) let i = ref 0 @@ -83,22 +82,40 @@ let version () = (if Mltop.is_native then "native" else "bytecode") (if Coq_config.best="opt" then "native" else "bytecode") -let eval_call c = - match Ide_blob.eval_call c with +exception Coq_failure of (Util.loc * Pp.std_ppcmds) + +let eval_call coqtop (c:'a Ide_blob.call) = + Safe_marshal.send coqtop.cin c; + let res = (Safe_marshal.receive: in_channel -> 'a Ide_blob.value) coqtop.cout in + match res with | Ide_blob.Good v -> v - | Ide_blob.Fail e -> raise e + | Ide_blob.Fail (l,pp) -> prerr_endline (msg pp); raise (Coq_failure (l,pp)) -let is_in_loadpath coqtop s = eval_call (Ide_blob.is_in_loadpath s) +let is_in_loadpath coqtop s = eval_call coqtop (Ide_blob.is_in_loadpath s) let reset_initial = Ide_blob.reinit -let raw_interp coqtop s = eval_call (Ide_blob.raw_interp s) +let raw_interp coqtop s = eval_call coqtop (Ide_blob.raw_interp s) -let interp coqtop b s = eval_call (Ide_blob.interp b s) +let interp coqtop b s = eval_call coqtop (Ide_blob.interp b s) -let rewind coqtop i = eval_call (Ide_blob.rewind i) +let rewind coqtop i = eval_call coqtop (Ide_blob.rewind i) -let read_stdout coqtop = eval_call Ide_blob.read_stdout +let read_stdout coqtop = eval_call coqtop Ide_blob.read_stdout + +let spawn_coqtop () = + let prog = Sys.argv.(0) in + let dir = Filename.dirname prog in + let oc,ic = Unix.open_process (dir^"/coqtop.opt -ideslave") in + { cin = ic; cout = oc } + +let kill_coqtop coqtop = raw_interp coqtop "Quit." + +let reset_coqtop coqtop = + kill_coqtop coqtop; + let ni = spawn_coqtop () in + coqtop.cin <- ni.cin; + coqtop.cout <- ni.cout module PrintOpt = struct @@ -120,10 +137,10 @@ struct List.iter (fun cmd -> let str = (if value then "Set" else "Unset") ^ " Printing " ^ cmd ^ "." in - raw_interp dummy_coqtop str) + raw_interp coqtop str) opt - let enforce_hack () = Hashtbl.iter (set ()) state_hack + let enforce_hack coqtop = Hashtbl.iter (set coqtop) state_hack end let rec is_pervasive_exn = function @@ -158,15 +175,15 @@ let print_toplevel_error exc = let process_exn e = let s,loc= print_toplevel_error e in (msgnl s,loc) -type tried_tactic = +type tried_tactic = | Interrupted | Success of int (* nb of goals after *) | Failed let goals coqtop = - PrintOpt.enforce_hack (); - eval_call Ide_blob.current_goals + PrintOpt.enforce_hack coqtop; + eval_call coqtop Ide_blob.current_goals -let make_cases coqtop s = eval_call (Ide_blob.make_cases s) +let make_cases coqtop s = eval_call coqtop (Ide_blob.make_cases s) -let current_status coqtop = eval_call Ide_blob.current_status +let current_status coqtop = eval_call coqtop Ide_blob.current_status diff --git a/ide/coq.mli b/ide/coq.mli index d50aab2802..914eb708a5 100644 --- a/ide/coq.mli +++ b/ide/coq.mli @@ -19,6 +19,14 @@ type coqtop val dummy_coqtop : coqtop +val spawn_coqtop : unit -> coqtop + +val kill_coqtop : coqtop -> unit + +val reset_coqtop : coqtop -> unit + +exception Coq_failure of (Util.loc * Pp.std_ppcmds) + module PrintOpt : sig type t @@ -61,3 +69,5 @@ type tried_tactic = val current_status : coqtop -> string val goals : coqtop -> goals + +val msgnl : Pp.std_ppcmds -> string diff --git a/ide/coqide.ml b/ide/coqide.ml index e8e4252780..e8198ec6fe 100644 --- a/ide/coqide.ml +++ b/ide/coqide.ml @@ -101,6 +101,7 @@ type viewable_script = proof_view : GText.view; message_view : GText.view; analyzed_view : analyzed_views; + toplvl : Coq.coqtop; } @@ -181,7 +182,7 @@ let set_active_view i = prerr_endline "entering set_active_view"; (try on_active_view (fun {tab_label=lbl} -> lbl#set_text lbl#text) with _ -> ()); session_notebook#goto_page i; - let s = session_notebook#current_term in + let s = session_notebook#get_nth_term i in s.tab_label#set_use_markup true; s.tab_label#set_label ("<span background=\"light green\">"^s.tab_label#text^"</span>"); active_view := i; @@ -279,6 +280,7 @@ let kill_input_view i = v.tab_label#destroy (); v.proof_view#destroy (); v.message_view#destroy (); + Coq.kill_coqtop v.toplvl; session_notebook#remove_page i (* (* XXX - beaucoups d'appels, a garder *) @@ -289,6 +291,19 @@ let remove_current_view_page () = let c = session_notebook#current_page in kill_input_view c +let print_items = [ + ([implicit],"Display _implicit arguments",GdkKeysyms._i,false); + ([coercions],"Display _coercions",GdkKeysyms._c,false); + ([raw_matching],"Display raw _matching expressions",GdkKeysyms._m,true); + ([notations],"Display _notations",GdkKeysyms._n,true); + ([all_basic],"Display _all basic low-level contents",GdkKeysyms._a,false); + ([existential],"Display _existential variable instances",GdkKeysyms._e,false); + ([universes],"Display _universe levels",GdkKeysyms._u,false); + ([all_basic;existential;universes],"Display all _low-level contents",GdkKeysyms._l,false) +] + +let setopts ct opts v = + List.iter (fun o -> set ct o v) opts (* Reset this to None on page change ! *) let (last_completion:(string*int*int*bool) option ref) = ref None @@ -375,9 +390,9 @@ exception Stop of int (* XXX *) let activate_input i = prerr_endline "entering activate_input"; - (try on_active_view (fun {analyzed_view=a_v} -> a_v#reset_initial; a_v#deactivate ()) +(* (try on_active_view (fun {analyzed_view=a_v} -> a_v#reset_initial; a_v#deactivate ()) with _ -> ()); - (session_notebook#get_nth_term i).analyzed_view#activate (); + (session_notebook#get_nth_term i).analyzed_view#activate (); *) set_active_view i; prerr_endline "exiting activate_input" @@ -514,7 +529,7 @@ let toggle_proof_visibility (buffer:GText.buffer) (cursor:GText.iter) = buffer#apply_tag ~start:decl_start ~stop:decl_end Tags.Script.folded; buffer#apply_tag ~start:decl_end ~stop:prf_end Tags.Script.hidden) -class analyzed_view (_script:Undo.undoable_view) (_pv:GText.view) (_mv:GText.view) _cs = +class analyzed_view (_script:Undo.undoable_view) (_pv:GText.view) (_mv:GText.view) _cs _ct = object(self) val input_view = _script val input_buffer = _script#buffer @@ -523,6 +538,7 @@ object(self) val message_view = _mv val message_buffer = _mv#buffer val cmd_stack = _cs + val mycoqtop = _ct val mutable is_active = false val mutable read_only = false val mutable filename = None @@ -742,8 +758,9 @@ object(self) try Ideproof.display (Ideproof.mode_tactic menu_callback) - proof_view (Coq.goals Coq.dummy_coqtop) - with e -> prerr_endline (Printexc.to_string e) + proof_view (Coq.goals mycoqtop) + with + | e -> prerr_endline (Printexc.to_string e) end method show_goals = self#show_goals_full @@ -776,12 +793,14 @@ object(self) try full_goal_done <- false; prerr_endline "Send_to_coq starting now"; - let r = Coq.interp Coq.dummy_coqtop verbosely phrase in + let r = Coq.interp mycoqtop verbosely phrase in let is_complete = true in - let msg = Coq.read_stdout Coq.dummy_coqtop in + let msg = Coq.read_stdout mycoqtop in sync display_output msg; Some (is_complete,r) - with e -> + with + | Coq_failure (l,pp) -> Pervasives.prerr_endline (Coq.msgnl pp); None + | e -> if show_error then sync display_error e; None @@ -974,7 +993,7 @@ object(self) cmd_stack; Stack.clear cmd_stack; self#clear_message)(); - Coq.reset_initial () + Coq.reset_coqtop mycoqtop (* backtrack Coq to the phrase preceding iterator [i] *) method backtrack_to_no_lock i = @@ -990,7 +1009,7 @@ object(self) in begin try - prerr_endline (string_of_int (rewind Coq.dummy_coqtop (n_step 0))); + prerr_endline (string_of_int (Coq.rewind mycoqtop (n_step 0))); prerr_endline (string_of_int (Stack.length cmd_stack)); sync (fun _ -> let start = @@ -1053,7 +1072,7 @@ object(self) self#show_goals; self#clear_message in - ignore ((rewind Coq.dummy_coqtop 1)); + ignore ((Coq.rewind mycoqtop 1)); sync update_input () with | Stack.Empty -> (* flash_info "Nothing to Undo"*)() @@ -1117,7 +1136,7 @@ object(self) val mutable deact_id = None val mutable act_id = None - method deactivate () = + method deactivate () = () (* is_active <- false; (match act_id with None -> () | Some id -> @@ -1125,14 +1144,14 @@ object(self) input_view#misc#disconnect id; prerr_endline "DISCONNECTED old active : "; print_id id; - )(*; + ); deact_id <- Some (input_view#event#connect#key_press self#disconnected_keypress_handler); prerr_endline "CONNECTED inactive : "; print_id (Option.get deact_id)*) (* XXX *) - method activate () = + method activate () = if not is_active then begin is_active <- true;(* (match deact_id with None -> () | Some id -> input_view#misc#disconnect id; @@ -1148,11 +1167,12 @@ object(self) with | None -> () | Some f -> let dir = Filename.dirname f in - if not (is_in_loadpath Coq.dummy_coqtop dir) then + if not (is_in_loadpath mycoqtop dir) then begin - ignore (Coq.interp Coq.dummy_coqtop false + ignore (Coq.interp mycoqtop false (Printf.sprintf "Add LoadPath \"%s\". " dir)) end + end method electric_handler = input_buffer#connect#insert_text ~callback: @@ -1340,8 +1360,10 @@ let create_session () = GMisc.label ~text:"*scratch*" () in let stack = Stack.create () in + let ct = + spawn_coqtop () in let legacy_av = - new analyzed_view script proof message stack in + new analyzed_view script proof message stack ct in let _ = script#buffer#create_mark ~name:"start_of_input" script#buffer#start_iter in let _ = @@ -1349,6 +1371,9 @@ let create_session () = let _ = GtkBase.Widget.add_events proof#as_widget [`ENTER_NOTIFY;`POINTER_MOTION] in let _ = + List.map (fun (opts,_,_,dflt) -> setopts ct opts dflt) print_items in + let _ = legacy_av#activate () in + let _ = proof#event#connect#motion_notify ~callback: (fun e -> let win = match proof#get_window `WIDGET with @@ -1376,7 +1401,8 @@ let create_session () = proof_view=proof; message_view=message; analyzed_view=legacy_av; - encoding="" + encoding=""; + toplvl=ct } (* XXX - to be used later @@ -2193,17 +2219,17 @@ let main files = in let _do_or_activate f () = let current = session_notebook#current_term in - let analyzed_view = current.analyzed_view in + let analyzed_view = current.analyzed_view in (* if analyzed_view#is_active then begin - prerr_endline ("view "^current.tab_label#text^"already active"); - ignore (f analyzed_view) + prerr_endline ("view "^current.tab_label#text^"already active"); *) + ignore (f analyzed_view) (* end else begin flash_info "New proof started"; prerr_endline ("activating view "^current.tab_label#text); activate_input session_notebook#current_page; ignore (f analyzed_view) - end + end *) in let do_or_activate f = @@ -2211,7 +2237,8 @@ let main files = (_do_or_activate (fun av -> f av; pop_info (); - push_info (Coq.current_status Coq.dummy_coqtop) + let cur_ct = session_notebook#current_term.toplvl in + push_info (Coq.current_status cur_ct) ) ) in @@ -2440,8 +2467,9 @@ with _ := Induction for _ Sort _.\n",61,10, Some GdkKeysyms._S); (* Template for match *) let callback () = let w = get_current_word () in +let cur_ct = session_notebook#current_term.toplvl in try - let cases = Coq.make_cases Coq.dummy_coqtop w + let cases = Coq.make_cases cur_ct w in let print c = function | [x] -> Format.fprintf c " | %s => _@\n" x @@ -2590,25 +2618,12 @@ with _ := Induction for _ Sort _.\n",61,10, Some GdkKeysyms._S); ~accel_group ~accel_modi:!current.modifier_for_display in - - let print_items = [ - ([implicit],"Display _implicit arguments",GdkKeysyms._i,false); - ([coercions],"Display _coercions",GdkKeysyms._c,false); - ([raw_matching],"Display raw _matching expressions",GdkKeysyms._m,true); - ([notations],"Display _notations",GdkKeysyms._n,true); - ([all_basic],"Display _all basic low-level contents",GdkKeysyms._a,false); - ([existential],"Display _existential variable instances",GdkKeysyms._e,false); - ([universes],"Display _universe levels",GdkKeysyms._u,false); - ([all_basic;existential;universes],"Display all _low-level contents",GdkKeysyms._l,false) - ] in - let setopts opts v = List.iter (fun o -> set Coq.dummy_coqtop o v) opts in let _ = List.map (fun (opts,text,key,dflt) -> - setopts opts dflt; view_factory#add_check_item ~key ~active:dflt text ~callback:(fun v -> do_or_activate (fun a -> - setopts opts v; + setopts session_notebook#current_term.toplvl opts v; a#show_goals) ())) print_items in @@ -3068,7 +3083,7 @@ with _ := Induction for _ Sort _.\n",61,10, Some GdkKeysyms._S); let f = if Filename.check_suffix f ".v" then f else f^".v" in load_file (fun s -> print_endline s; exit 1) f) files; - activate_input 0 + activate_input 0 end else begin @@ -3078,6 +3093,7 @@ with _ := Induction for _ Sort _.\n",61,10, Some GdkKeysyms._S); end; initial_about session_notebook#current_term.proof_view#buffer; !show_toolbar !current.show_toolbar; + Command_windows.get_current_toplevel := (fun () -> session_notebook#current_term.toplvl); session_notebook#current_term.script#misc#grab_focus () ;; diff --git a/ide/typed_notebook.ml b/ide/typed_notebook.ml index bd26bab273..ad122ee2bd 100644 --- a/ide/typed_notebook.ml +++ b/ide/typed_notebook.ml @@ -54,7 +54,9 @@ object(self) method pages = term_list - method current_term = List.nth term_list super#current_page + method current_term = + List.nth term_list super#current_page + end let create build = diff --git a/lib/lib.mllib b/lib/lib.mllib index 86d29c4be6..b5db04d213 100644 --- a/lib/lib.mllib +++ b/lib/lib.mllib @@ -25,3 +25,4 @@ Heap Option Dnet Store +Safe_marshal diff --git a/lib/safe_marshal.ml b/lib/safe_marshal.ml index e9ba81b499..0ae5245d7f 100644 --- a/lib/safe_marshal.ml +++ b/lib/safe_marshal.ml @@ -5,6 +5,15 @@ (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (************************************************************************) +(* +let uuencode s = + let norm_s = s ^ (String.make (String.length s mod 3) '\000') in + let rec y f x = f (y f) x in + let chop rem = function + | "" -> [] + | s -> String.sub s 0 3 :: (rem (String.sub s 3 (String.length (s - 3)))) in + let chunks = y chop norm_s in + *) let hobcnv = Array.init 256 (fun i -> Printf.sprintf "%.2x" i) let bohcnv = Array.init 256 (fun i -> i - @@ -13,7 +22,7 @@ let bohcnv = Array.init 256 (fun i -> i - (if 0x61 <= i then 0x20 else 0)) let hex_of_bin ch = hobcnv.(int_of_char ch) -let bin_of_hex s = bohcnv.(char_of_int s[0]) * 16 + bohcnv.(char_of_int s[1]) +let bin_of_hex s = char_of_int (bohcnv.(int_of_char s.[0]) * 16 + bohcnv.(int_of_char s.[1])) let send cout expr = let mshl_expr = Marshal.to_string expr [] in diff --git a/toplevel/coqtop.ml b/toplevel/coqtop.ml index 74c4ff3db8..440d362807 100644 --- a/toplevel/coqtop.ml +++ b/toplevel/coqtop.ml @@ -150,6 +150,7 @@ let usage () = let warning s = msg_warning (str s) +let ide_slave = ref false let ide_args = ref [] let parse_args arglist = @@ -287,6 +288,8 @@ let parse_args arglist = | "-no-hash-consing" :: rem -> Flags.hash_cons_proofs := false; parse rem + | "-ideslave" :: rem -> ide_slave := true; parse rem + | s :: rem -> ide_args := s :: !ide_args; parse rem @@ -308,6 +311,12 @@ let init arglist = begin try parse_args arglist; + if !ide_args <> [] then usage (); + if !ide_slave then begin + Flags.make_silent true; + Pfedit.set_undo (Some 5000); + Ide_blob.init_stdout () + end; if_verbose print_header (); init_load_path (); inputstate (); @@ -342,13 +351,14 @@ let init_ide arglist = Flags.make_silent true; Pfedit.set_undo (Some 5000); Ide_blob.init_stdout (); - init arglist; List.rev !ide_args let start () = init_toplevel (List.tl (Array.to_list Sys.argv)); - if !ide_args <> [] then usage (); - Toplevel.loop(); + if !ide_slave then + Ide_blob.loop () + else + Toplevel.loop(); (* Initialise and launch the Ocaml toplevel *) Coqinit.init_ocaml_path(); Mltop.ocaml_toploop(); diff --git a/toplevel/ide_blob.ml b/toplevel/ide_blob.ml index a312b0037b..899cee1e46 100644 --- a/toplevel/ide_blob.ml +++ b/toplevel/ide_blob.ml @@ -403,7 +403,9 @@ let concl_next_tac sigma concl = ]) let current_goals () = - let pfts = Pfedit.get_pftreestate () in + let pfts = + Proof_global.give_me_the_proof () + in let { Evd.it=all_goals ; sigma=sigma } = Proof.V82.subgoals pfts in if all_goals = [] then begin @@ -524,12 +526,14 @@ type 'a call = type 'a value = | Good of 'a - | Fail of exn + | Fail of (Util.loc * Pp.std_ppcmds) let eval_call c = + let null_formatter = Format.make_formatter (fun _ _ _ -> ()) (fun _ -> ()) in let filter_compat_exn = function | Vernac.DuringCommandInterp (loc,inner) | Vernacexpr.DuringSyntaxChecking (loc,inner) -> inner + | Vernacexpr.Quit -> raise Vernacexpr.Quit | e -> e in try Good (match c with @@ -541,7 +545,11 @@ let eval_call c = | Cur_goals -> Obj.magic (current_goals ()) | Cur_status -> Obj.magic (current_status ()) | Cases s -> Obj.magic (make_cases s)) - with e -> Fail (filter_compat_exn e) + with e -> + let (l,pp) = explain_exn (filter_compat_exn e) in + (* force evaluation of format stream *) + Pp.msg_with null_formatter pp; + Fail (l,pp) let is_in_loadpath s : bool call = In_loadpath s @@ -568,3 +576,14 @@ let make_cases s : string list list call = Cases s (* End of wrappers *) + +let loop () = + try + while true do + let q = (Safe_marshal.receive: in_channel -> 'a call) stdin in + let r = eval_call q in + Safe_marshal.send stdout r + done + with + | Vernacexpr.Quit -> exit 0 + | _ -> exit 1 diff --git a/toplevel/ide_blob.mli b/toplevel/ide_blob.mli index c74d67f2ce..561821b563 100644 --- a/toplevel/ide_blob.mli +++ b/toplevel/ide_blob.mli @@ -23,7 +23,7 @@ type 'a call type 'a value = | Good of 'a - | Fail of exn + | Fail of (Util.loc * Pp.std_ppcmds) val eval_call : 'a call -> 'a value @@ -43,3 +43,4 @@ val current_goals : goals call val read_stdout : string call +val loop : unit -> unit |
