|
Packit |
bd2e5d |
(*************************************************************************)
|
|
Packit |
bd2e5d |
(* *)
|
|
Packit |
bd2e5d |
(* OCaml LablTk library *)
|
|
Packit |
bd2e5d |
(* *)
|
|
Packit |
bd2e5d |
(* Jacques Garrigue, Kyoto University RIMS *)
|
|
Packit |
bd2e5d |
(* *)
|
|
Packit |
bd2e5d |
(* Copyright 1999 Institut National de Recherche en Informatique et *)
|
|
Packit |
bd2e5d |
(* en Automatique and Kyoto University. All rights reserved. *)
|
|
Packit |
bd2e5d |
(* This file is distributed under the terms of the GNU Library *)
|
|
Packit |
bd2e5d |
(* General Public License, with the special exception on linking *)
|
|
Packit |
bd2e5d |
(* described in file ../../../LICENSE. *)
|
|
Packit |
bd2e5d |
(* *)
|
|
Packit |
bd2e5d |
(*************************************************************************)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* $Id$ *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
open StdLabels
|
|
Packit |
bd2e5d |
open Tk
|
|
Packit |
bd2e5d |
open Jg_tk
|
|
Packit |
bd2e5d |
open Mytypes
|
|
Packit |
bd2e5d |
open Longident
|
|
Packit |
bd2e5d |
open Types
|
|
Packit |
bd2e5d |
open Typedtree
|
|
Packit |
bd2e5d |
open Env
|
|
Packit |
bd2e5d |
open Searchpos
|
|
Packit |
bd2e5d |
open Searchid
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Managing the module list *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let list_modules ~path =
|
|
Packit |
bd2e5d |
List.fold_left path ~init:[] ~f:
|
|
Packit |
bd2e5d |
begin fun modules dir ->
|
|
Packit |
bd2e5d |
let l =
|
|
Packit |
bd2e5d |
List.filter (Useunix.get_files_in_directory dir)
|
|
Packit |
bd2e5d |
~f:(fun x -> Filename.check_suffix x ".cmi") in
|
|
Packit |
bd2e5d |
let l = List.map l ~f:
|
|
Packit |
bd2e5d |
begin fun x ->
|
|
Packit |
bd2e5d |
String.capitalize_ascii (Filename.chop_suffix x ".cmi")
|
|
Packit |
bd2e5d |
end in
|
|
Packit |
bd2e5d |
List.fold_left l ~init:modules
|
|
Packit |
bd2e5d |
~f:(fun modules item ->
|
|
Packit |
bd2e5d |
if List.mem item modules then modules else item :: modules)
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let reset_modules box =
|
|
Packit |
bd2e5d |
Listbox.delete box ~first:(`Num 0) ~last:`End;
|
|
Packit |
bd2e5d |
module_list := List.sort (Jg_completion.compare_string ~nocase:true)
|
|
Packit |
bd2e5d |
(list_modules ~path:!Config.load_path);
|
|
Packit |
bd2e5d |
Listbox.insert box ~index:`End ~texts:!module_list;
|
|
Packit |
bd2e5d |
Jg_box.recenter box ~index:(`Num 0)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* How to display a symbol *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let view_symbol ~kind ~env ?path id =
|
|
Packit |
bd2e5d |
let name = match id with
|
|
Packit |
bd2e5d |
Lident x -> x
|
|
Packit |
bd2e5d |
| Ldot (_, x) -> x
|
|
Packit |
bd2e5d |
| _ -> match kind with Pvalue | Ptype | Plabel -> "z" | _ -> "Z"
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
match kind with
|
|
Packit |
bd2e5d |
Pvalue ->
|
|
Packit |
bd2e5d |
let path, vd = lookup_value id env in
|
|
Packit |
bd2e5d |
view_signature_item ~path ~env [Sig_value (Ident.create name, vd)]
|
|
Packit |
bd2e5d |
| Ptype -> view_type_id id ~env
|
|
Packit |
bd2e5d |
| Plabel -> let ld = lookup_label id env in
|
|
Packit |
bd2e5d |
begin match ld.lbl_res.desc with
|
|
Packit |
bd2e5d |
Tconstr (path, _, _) -> view_type_decl path ~env
|
|
Packit |
bd2e5d |
| _ -> ()
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
| Pconstructor ->
|
|
Packit |
bd2e5d |
let cd = lookup_constructor id env in
|
|
Packit |
bd2e5d |
begin match cd.cstr_tag, cd.cstr_res.desc with
|
|
Packit |
bd2e5d |
Cstr_extension _, Tconstr (cpath, args, _) ->
|
|
Packit |
bd2e5d |
view_signature ~title:(string_of_longident id) ~env ?path
|
|
Packit |
bd2e5d |
[Sig_typext (Ident.create name,
|
|
Packit |
bd2e5d |
{Types.ext_type_path = cpath;
|
|
Packit |
bd2e5d |
ext_type_params = args;
|
|
Packit |
bd2e5d |
ext_args = Cstr_tuple cd.cstr_args;
|
|
Packit |
bd2e5d |
ext_ret_type = (if cd.cstr_generalized
|
|
Packit |
bd2e5d |
then Some cd.cstr_res else None);
|
|
Packit |
bd2e5d |
ext_private = cd.cstr_private;
|
|
Packit |
bd2e5d |
ext_loc = cd.cstr_loc;
|
|
Packit |
bd2e5d |
ext_attributes = cd.cstr_attributes},
|
|
Packit |
bd2e5d |
if Path.same cpath Predef.path_exn then Text_exception
|
|
Packit |
bd2e5d |
else Text_first)]
|
|
Packit |
bd2e5d |
| _, Tconstr (cpath, _, _) ->
|
|
Packit |
bd2e5d |
view_type_decl cpath ~env
|
|
Packit |
bd2e5d |
| _ -> ()
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
| Pmodule -> view_module_id id ~env
|
|
Packit |
bd2e5d |
| Pmodtype -> view_modtype_id id ~env
|
|
Packit |
bd2e5d |
| Pclass -> view_class_id id ~env
|
|
Packit |
bd2e5d |
| Pcltype -> view_cltype_id id ~env
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Create a list of symbols you can choose from *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let choose_symbol ~title ~env ?signature ?path l =
|
|
Packit |
bd2e5d |
if match path with
|
|
Packit |
bd2e5d |
None -> false
|
|
Packit |
bd2e5d |
| Some path -> is_shown_module path
|
|
Packit |
bd2e5d |
then () else
|
|
Packit |
bd2e5d |
let tl = Jg_toplevel.titled title in
|
|
Packit |
bd2e5d |
Jg_bind.escape_destroy tl;
|
|
Packit |
bd2e5d |
top_widgets := coe tl :: !top_widgets;
|
|
Packit |
bd2e5d |
let buttons = Frame.create tl in
|
|
Packit |
bd2e5d |
let all = Button.create buttons ~text:"Show all" ~padx:20
|
|
Packit |
bd2e5d |
and ok = Jg_button.create_destroyer tl ~parent:buttons
|
|
Packit |
bd2e5d |
and detach = Button.create buttons ~text:"Detach"
|
|
Packit |
bd2e5d |
and edit = Button.create buttons ~text:"Impl"
|
|
Packit |
bd2e5d |
and intf = Button.create buttons ~text:"Intf" in
|
|
Packit |
bd2e5d |
let l = List.sort l ~cmp:(fun (li1, _) (li2,_) -> compare li1 li2) in
|
|
Packit |
bd2e5d |
let nl = List.map l ~f:
|
|
Packit |
bd2e5d |
begin fun (li, k) ->
|
|
Packit |
bd2e5d |
string_of_longident li ^ " (" ^ string_of_kind k ^ ")"
|
|
Packit |
bd2e5d |
end in
|
|
Packit |
bd2e5d |
let fb = Frame.create tl in
|
|
Packit |
bd2e5d |
let box =
|
|
Packit |
bd2e5d |
new Jg_multibox.c fb ~cols:3 ~texts:nl ~maxheight:3 ~width:21 in
|
|
Packit |
bd2e5d |
box#init;
|
|
Packit |
bd2e5d |
box#bind_kbd ~events:[`KeyPressDetail"Escape"]
|
|
Packit |
bd2e5d |
~action:(fun _ ~index -> destroy tl; break ());
|
|
Packit |
bd2e5d |
if List.length nl > 9 then ignore (Jg_multibox.add_scrollbar box);
|
|
Packit |
bd2e5d |
Jg_multibox.add_completion box ~action:
|
|
Packit |
bd2e5d |
begin fun pos ->
|
|
Packit |
bd2e5d |
let li, k = List.nth l pos in
|
|
Packit |
bd2e5d |
let path =
|
|
Packit |
bd2e5d |
match path, li with
|
|
Packit |
bd2e5d |
None, Ldot (lip, _) ->
|
|
Packit |
bd2e5d |
begin try
|
|
Packit |
bd2e5d |
Some (lookup_module ~load:true lip env)
|
|
Packit |
bd2e5d |
with Not_found -> None
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
| _ -> path
|
|
Packit |
bd2e5d |
in view_symbol li ~kind:k ~env ?path
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
pack [buttons] ~side:`Bottom ~fill:`X;
|
|
Packit |
bd2e5d |
pack [fb] ~side:`Top ~fill:`Both ~expand:true;
|
|
Packit |
bd2e5d |
begin match signature with
|
|
Packit |
bd2e5d |
None -> pack [ok] ~fill:`X ~expand:true
|
|
Packit |
bd2e5d |
| Some signature ->
|
|
Packit |
bd2e5d |
Button.configure all ~command:
|
|
Packit |
bd2e5d |
begin fun () ->
|
|
Packit |
bd2e5d |
view_signature signature ~title ~env ?path
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
pack [ok; all] ~side:`Right ~fill:`X ~expand:true
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
begin match path with None -> ()
|
|
Packit |
bd2e5d |
| Some path ->
|
|
Packit |
bd2e5d |
let frame = Frame.create tl in
|
|
Packit |
bd2e5d |
pack [frame] ~side:`Bottom ~fill:`X;
|
|
Packit |
bd2e5d |
add_shown_module path
|
|
Packit |
bd2e5d |
~widgets:{ mw_frame = frame; mw_title = None; mw_detach = detach;
|
|
Packit |
bd2e5d |
mw_edit = edit; mw_intf = intf }
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let choose_symbol_ref = ref choose_symbol
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Search, both by type and name *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let guess_search_mode s : [`Type | `Long | `Pattern] =
|
|
Packit |
bd2e5d |
let is_type = ref false and is_long = ref false in
|
|
Packit |
bd2e5d |
for i = 0 to String.length s - 2 do
|
|
Packit |
bd2e5d |
if s.[i] = '-' && s.[i+1] = '>' then is_type := true;
|
|
Packit |
bd2e5d |
if s.[i] = '.' then is_long := true
|
|
Packit |
bd2e5d |
done;
|
|
Packit |
bd2e5d |
if !is_type then `Type else if !is_long then `Long else `Pattern
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let search_string ?(mode="symbol") ew =
|
|
Packit |
bd2e5d |
let text = Entry.get ew in
|
|
Packit |
bd2e5d |
try
|
|
Packit |
bd2e5d |
if text = "" then () else
|
|
Packit |
bd2e5d |
let l = match mode with
|
|
Packit |
bd2e5d |
"Name" ->
|
|
Packit |
bd2e5d |
begin match guess_search_mode text with
|
|
Packit |
bd2e5d |
`Long -> search_string_symbol text
|
|
Packit |
bd2e5d |
| `Pattern -> search_pattern_symbol text
|
|
Packit |
bd2e5d |
| `Type -> search_string_type text ~mode:`Included
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
| "Type" -> search_string_type text ~mode:`Included
|
|
Packit |
bd2e5d |
| "Exact" -> search_string_type text ~mode:`Exact
|
|
Packit |
bd2e5d |
| _ -> assert false
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
match l with [] -> ()
|
|
Packit |
bd2e5d |
| [lid,kind] -> view_symbol lid ~kind ~env:!start_env
|
|
Packit |
bd2e5d |
| l -> choose_symbol ~title:"Choose symbol" ~env:!start_env l
|
|
Packit |
bd2e5d |
with Searchid.Error (s,e) ->
|
|
Packit |
bd2e5d |
Entry.icursor ew ~index:(`Num s)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let search_which = ref "Name"
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let search_symbol () =
|
|
Packit |
bd2e5d |
if !module_list = [] then
|
|
Packit |
bd2e5d |
module_list := List.sort ~cmp:compare (list_modules ~path:!Config.load_path);
|
|
Packit |
bd2e5d |
let tl = Jg_toplevel.titled "Search symbol" in
|
|
Packit |
bd2e5d |
Jg_bind.escape_destroy tl;
|
|
Packit |
bd2e5d |
let ew = Entry.create tl ~width:30 in
|
|
Packit |
bd2e5d |
let choice = Frame.create tl
|
|
Packit |
bd2e5d |
and which = Textvariable.create ~on:tl () in
|
|
Packit |
bd2e5d |
let itself = Radiobutton.create choice ~text:"Itself"
|
|
Packit |
bd2e5d |
~variable:which ~value:"Name"
|
|
Packit |
bd2e5d |
and extype = Radiobutton.create choice ~text:"Exact type"
|
|
Packit |
bd2e5d |
~variable:which ~value:"Exact"
|
|
Packit |
bd2e5d |
and iotype = Radiobutton.create choice ~text:"Included type"
|
|
Packit |
bd2e5d |
~variable:which ~value:"Type"
|
|
Packit |
bd2e5d |
and buttons = Frame.create tl in
|
|
Packit |
bd2e5d |
let search = Button.create buttons ~text:"Search" ~command:
|
|
Packit |
bd2e5d |
begin fun () ->
|
|
Packit |
bd2e5d |
search_which := Textvariable.get which;
|
|
Packit |
bd2e5d |
search_string ew ~mode:!search_which
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
and ok = Jg_button.create_destroyer tl ~parent:buttons ~text:"Cancel" in
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
Focus.set ew;
|
|
Packit |
bd2e5d |
Jg_bind.return_invoke ew ~button:search;
|
|
Packit |
bd2e5d |
Textvariable.set which !search_which;
|
|
Packit |
bd2e5d |
pack [itself; extype; iotype] ~side:`Left ~anchor:`W;
|
|
Packit |
bd2e5d |
pack [search; ok] ~side:`Left ~fill:`X ~expand:true;
|
|
Packit |
bd2e5d |
pack [coe ew; coe choice; coe buttons]
|
|
Packit |
bd2e5d |
~side:`Top ~fill:`X ~expand:true
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Display the contents of a module *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let ident_of_decl ~modlid = function
|
|
Packit |
bd2e5d |
Sig_value (id, _) -> Lident (Ident.name id), Pvalue
|
|
Packit |
bd2e5d |
| Sig_type (id, _, _) -> Lident (Ident.name id), Ptype
|
|
Packit |
bd2e5d |
| Sig_typext (id, _, _) -> Ldot (modlid, Ident.name id), Pconstructor
|
|
Packit |
bd2e5d |
| Sig_module (id, _, _) -> Lident (Ident.name id), Pmodule
|
|
Packit |
bd2e5d |
| Sig_modtype (id, _) -> Lident (Ident.name id), Pmodtype
|
|
Packit |
bd2e5d |
| Sig_class (id, _, _) -> Lident (Ident.name id), Pclass
|
|
Packit |
bd2e5d |
| Sig_class_type (id, _, _) -> Lident (Ident.name id), Pcltype
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let view_defined ~env ?(show_all=false) modlid =
|
|
Packit |
bd2e5d |
try match Typetexp.find_module env Location.none modlid with
|
|
Packit |
bd2e5d |
path, {md_type=Mty_signature sign} ->
|
|
Packit |
bd2e5d |
let rec iter_sign sign idents =
|
|
Packit |
bd2e5d |
match sign with
|
|
Packit |
bd2e5d |
[] -> List.rev idents
|
|
Packit |
bd2e5d |
| decl :: rem ->
|
|
Packit |
bd2e5d |
let rem = match decl, rem with
|
|
Packit |
bd2e5d |
Sig_class _, cty :: ty1 :: ty2 :: rem -> rem
|
|
Packit |
bd2e5d |
| Sig_class_type _, ty1 :: ty2 :: rem -> rem
|
|
Packit |
bd2e5d |
| _, rem -> rem
|
|
Packit |
bd2e5d |
in iter_sign rem (ident_of_decl ~modlid decl :: idents)
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let l = iter_sign sign [] in
|
|
Packit |
bd2e5d |
let title = string_of_path path in
|
|
Packit |
bd2e5d |
let env =
|
|
Packit |
bd2e5d |
match open_signature Asttypes.Fresh path env with None -> env
|
|
Packit |
bd2e5d |
| Some env -> env
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
!choose_symbol_ref l ~title ~signature:sign ~env ~path;
|
|
Packit |
bd2e5d |
if show_all then view_signature sign ~title ~env ~path
|
|
Packit |
bd2e5d |
| _ -> ()
|
|
Packit |
bd2e5d |
with Not_found -> ()
|
|
Packit |
bd2e5d |
| Env.Error err ->
|
|
Packit |
bd2e5d |
let tl, tw, finish = Jg_message.formatted ~title:"Error!" () in
|
|
Packit |
bd2e5d |
Env.report_error Format.std_formatter err;
|
|
Packit |
bd2e5d |
finish ()
|
|
Packit |
bd2e5d |
| Cmi_format.Error err ->
|
|
Packit |
bd2e5d |
let tl, tw, finish = Jg_message.formatted ~title:"Error!" () in
|
|
Packit |
bd2e5d |
Cmi_format.report_error Format.std_formatter err;
|
|
Packit |
bd2e5d |
finish ()
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Manage toplevel windows *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let close_all_views () =
|
|
Packit |
bd2e5d |
List.iter !top_widgets
|
|
Packit |
bd2e5d |
~f:(fun tl -> try destroy tl with Protocol.TkError _ -> ());
|
|
Packit |
bd2e5d |
top_widgets := []
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Launch a shell *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let shell_counter = ref 1
|
|
Packit |
bd2e5d |
let default_shell = ref "ocaml"
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let start_shell master =
|
|
Packit |
bd2e5d |
let tl = Jg_toplevel.titled "Start New Shell" in
|
|
Packit |
bd2e5d |
Wm.transient_set tl ~master;
|
|
Packit |
bd2e5d |
let input = Frame.create tl
|
|
Packit |
bd2e5d |
and buttons = Frame.create tl in
|
|
Packit |
bd2e5d |
let ok = Button.create buttons ~text:"Ok"
|
|
Packit |
bd2e5d |
and cancel = Jg_button.create_destroyer tl ~parent:buttons ~text:"Cancel"
|
|
Packit |
bd2e5d |
and labels = Frame.create input
|
|
Packit |
bd2e5d |
and entries = Frame.create input in
|
|
Packit |
bd2e5d |
let l1 = Label.create labels ~text:"Command:"
|
|
Packit |
bd2e5d |
and l2 = Label.create labels ~text:"Title:"
|
|
Packit |
bd2e5d |
and e1 =
|
|
Packit |
bd2e5d |
Jg_entry.create entries ~command:(fun _ -> Button.invoke ok)
|
|
Packit |
bd2e5d |
and e2 =
|
|
Packit |
bd2e5d |
Jg_entry.create entries ~command:(fun _ -> Button.invoke ok)
|
|
Packit |
bd2e5d |
and names = List.map ~f:fst (Shell.get_all ()) in
|
|
Packit |
bd2e5d |
Entry.insert e1 ~index:`End ~text:!default_shell;
|
|
Packit |
bd2e5d |
let shell_name () = "Shell #" ^ string_of_int !shell_counter in
|
|
Packit |
bd2e5d |
while List.mem (shell_name ()) names do
|
|
Packit |
bd2e5d |
incr shell_counter
|
|
Packit |
bd2e5d |
done;
|
|
Packit |
bd2e5d |
Entry.insert e2 ~index:`End ~text:(shell_name ());
|
|
Packit |
bd2e5d |
Button.configure ok ~command:(fun () ->
|
|
Packit |
bd2e5d |
if not (List.mem (Entry.get e2) names) then begin
|
|
Packit |
bd2e5d |
default_shell := Entry.get e1;
|
|
Packit |
bd2e5d |
Shell.f ~prog:!default_shell ~title:(Entry.get e2);
|
|
Packit |
bd2e5d |
destroy tl
|
|
Packit |
bd2e5d |
end);
|
|
Packit |
bd2e5d |
pack [l1;l2] ~side:`Top ~anchor:`W;
|
|
Packit |
bd2e5d |
pack [e1;e2] ~side:`Top ~fill:`X ~expand:true;
|
|
Packit |
bd2e5d |
pack [labels;entries] ~side:`Left ~fill:`X ~expand:true;
|
|
Packit |
bd2e5d |
pack [ok;cancel] ~side:`Left ~fill:`X ~expand:true;
|
|
Packit |
bd2e5d |
pack [input;buttons] ~side:`Top ~fill:`X ~expand:true
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Help window *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let show_help () =
|
|
Packit |
bd2e5d |
let tl = Jg_toplevel.titled "OCamlBrowser Help" in
|
|
Packit |
bd2e5d |
Jg_bind.escape_destroy tl;
|
|
Packit |
bd2e5d |
let fw, tw, sb = Jg_text.create_with_scrollbar tl in
|
|
Packit |
bd2e5d |
let ok = Jg_button.create_destroyer ~parent:tl ~text:"Ok" tl in
|
|
Packit |
bd2e5d |
Text.insert tw ~index:tend ~text:Help.text;
|
|
Packit |
bd2e5d |
Text.configure tw ~state:`Disabled;
|
|
Packit |
bd2e5d |
Jg_bind.enter_focus tw;
|
|
Packit |
bd2e5d |
pack [tw] ~side:`Left ~fill:`Both ~expand:true;
|
|
Packit |
bd2e5d |
pack [sb] ~side:`Right ~fill:`Y;
|
|
Packit |
bd2e5d |
pack [fw] ~side:`Top ~expand:true ~fill:`Both;
|
|
Packit |
bd2e5d |
pack [ok] ~side:`Bottom ~fill:`X
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Launch the classical viewer *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let f ?(dir=Unix.getcwd()) ?on () =
|
|
Packit |
bd2e5d |
let (top, tl) = match on with
|
|
Packit |
bd2e5d |
None ->
|
|
Packit |
bd2e5d |
let tl = Jg_toplevel.titled "Module viewer" in
|
|
Packit |
bd2e5d |
ignore (Jg_bind.escape_destroy tl); (tl, coe tl)
|
|
Packit |
bd2e5d |
| Some top ->
|
|
Packit |
bd2e5d |
Wm.title_set top "OCamlBrowser";
|
|
Packit |
bd2e5d |
Wm.iconname_set top "OCamlBrowser";
|
|
Packit |
bd2e5d |
let tl = Frame.create top in
|
|
Packit |
bd2e5d |
bind tl ~events:[`Destroy] ~action:(fun _ -> exit 0);
|
|
Packit |
bd2e5d |
pack [tl] ~expand:true ~fill:`Both;
|
|
Packit |
bd2e5d |
(top, coe tl)
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let menus = Jg_menu.menubar top in
|
|
Packit |
bd2e5d |
let filemenu = new Jg_menu.c "File" ~parent:menus
|
|
Packit |
bd2e5d |
and modmenu = new Jg_menu.c "Modules" ~parent:menus in
|
|
Packit |
bd2e5d |
let fmbox, mbox, msb = Jg_box.create_with_scrollbar tl in
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
Jg_box.add_completion mbox ~nocase:true ~action:
|
|
Packit |
bd2e5d |
begin fun index ->
|
|
Packit |
bd2e5d |
view_defined (Lident (Listbox.get mbox ~index)) ~env:!start_env
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
Setpath.add_update_hook (fun () -> reset_modules mbox);
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let ew = Entry.create tl in
|
|
Packit |
bd2e5d |
let buttons = Frame.create tl in
|
|
Packit |
bd2e5d |
let search = Button.create buttons ~text:"Search" ~pady:1
|
|
Packit |
bd2e5d |
~command:(fun () -> search_string ew)
|
|
Packit |
bd2e5d |
and close =
|
|
Packit |
bd2e5d |
Button.create buttons ~text:"Close all" ~pady:1 ~command:close_all_views
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
(* bindings *)
|
|
Packit |
bd2e5d |
Jg_bind.enter_focus ew;
|
|
Packit |
bd2e5d |
Jg_bind.return_invoke ew ~button:search;
|
|
Packit |
bd2e5d |
bind close ~events:[`Modified([`Double], `ButtonPressDetail 1)]
|
|
Packit |
bd2e5d |
~action:(fun _ -> destroy tl);
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* File menu *)
|
|
Packit |
bd2e5d |
filemenu#add_command "Open..."
|
|
Packit |
bd2e5d |
~command:(fun () -> !editor_ref ~opendialog:true ());
|
|
Packit |
bd2e5d |
filemenu#add_command "Editor..." ~command:(fun () -> !editor_ref ());
|
|
Packit |
bd2e5d |
filemenu#add_command "Shell..." ~command:(fun () -> start_shell tl);
|
|
Packit |
bd2e5d |
filemenu#add_command "Quit" ~command:(fun () -> destroy tl);
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* modules menu *)
|
|
Packit |
bd2e5d |
modmenu#add_command "Path editor..."
|
|
Packit |
bd2e5d |
~command:(fun () -> Setpath.set ~dir);
|
|
Packit |
bd2e5d |
modmenu#add_command "Reset cache"
|
|
Packit |
bd2e5d |
~command:(fun () -> reset_modules mbox; Env.reset_cache ());
|
|
Packit |
bd2e5d |
modmenu#add_command "Search symbol..." ~command:search_symbol;
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
pack [close; search] ~fill:`X ~side:`Right ~expand:true;
|
|
Packit |
bd2e5d |
pack [coe buttons; coe ew] ~fill:`X ~side:`Bottom;
|
|
Packit |
bd2e5d |
pack [msb] ~side:`Right ~fill:`Y;
|
|
Packit |
bd2e5d |
pack [mbox] ~side:`Left ~fill:`Both ~expand:true;
|
|
Packit |
bd2e5d |
pack [fmbox] ~fill:`Both ~expand:true ~side:`Top;
|
|
Packit |
bd2e5d |
reset_modules mbox
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Smalltalk-like version *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
class st_viewer ?(dir=Unix.getcwd()) ?on () =
|
|
Packit |
bd2e5d |
let (top, tl) = match on with
|
|
Packit |
bd2e5d |
None ->
|
|
Packit |
bd2e5d |
let tl = Jg_toplevel.titled "Module viewer" in
|
|
Packit |
bd2e5d |
ignore (Jg_bind.escape_destroy tl); (tl, coe tl)
|
|
Packit |
bd2e5d |
| Some top ->
|
|
Packit |
bd2e5d |
Wm.title_set top "OCamlBrowser";
|
|
Packit |
bd2e5d |
Wm.iconname_set top "OCamlBrowser";
|
|
Packit |
bd2e5d |
let tl = Frame.create top in
|
|
Packit |
bd2e5d |
bind tl ~events:[`Destroy] ~action:(fun _ -> exit 0);
|
|
Packit |
bd2e5d |
pack [tl] ~side:`Bottom ~expand:true ~fill:`Both;
|
|
Packit |
bd2e5d |
(top, coe tl)
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let menus = Menu.create top ~name:"menubar" ~typ:`Menubar in
|
|
Packit |
bd2e5d |
let () = Toplevel.configure top ~menu:menus in
|
|
Packit |
bd2e5d |
let filemenu = new Jg_menu.c "File" ~parent:menus
|
|
Packit |
bd2e5d |
and modmenu = new Jg_menu.c "Modules" ~parent:menus
|
|
Packit |
bd2e5d |
and viewmenu = new Jg_menu.c "View" ~parent:menus
|
|
Packit |
bd2e5d |
and helpmenu = new Jg_menu.c "Help" ~parent:menus in
|
|
Packit |
bd2e5d |
let search_frame = Frame.create tl in
|
|
Packit |
bd2e5d |
let boxes_frame = Frame.create tl ~name:"boxes" in
|
|
Packit |
bd2e5d |
let label = Label.create tl ~anchor:`W ~padx:5 in
|
|
Packit |
bd2e5d |
let view = Frame.create tl in
|
|
Packit |
bd2e5d |
let buttons = Frame.create tl in
|
|
Packit |
bd2e5d |
let _all = Button.create buttons ~text:"Show all" ~padx:20
|
|
Packit |
bd2e5d |
and close = Button.create buttons ~text:"Close all" ~command:close_all_views
|
|
Packit |
bd2e5d |
and detach = Button.create buttons ~text:"Detach"
|
|
Packit |
bd2e5d |
and edit = Button.create buttons ~text:"Impl"
|
|
Packit |
bd2e5d |
and intf = Button.create buttons ~text:"Intf" in
|
|
Packit |
bd2e5d |
object (self)
|
|
Packit |
bd2e5d |
val mutable boxes = []
|
|
Packit |
bd2e5d |
val mutable show_all = fun () -> ()
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
method create_box =
|
|
Packit |
bd2e5d |
let fmbox, mbox, sb = Jg_box.create_with_scrollbar boxes_frame in
|
|
Packit |
bd2e5d |
bind mbox ~events:[`Modified([`Double], `ButtonPressDetail 1)]
|
|
Packit |
bd2e5d |
~action:(fun _ -> show_all ());
|
|
Packit |
bd2e5d |
bind mbox ~events:[`Modified([`Double], `KeyPressDetail "Return")]
|
|
Packit |
bd2e5d |
~action:(fun _ -> show_all ());
|
|
Packit |
bd2e5d |
boxes <- boxes @ [fmbox, mbox];
|
|
Packit |
bd2e5d |
pack [sb] ~side:`Right ~fill:`Y;
|
|
Packit |
bd2e5d |
pack [mbox] ~side:`Left ~fill:`Both ~expand:true;
|
|
Packit |
bd2e5d |
pack [fmbox] ~side:`Left ~fill:`Both ~expand:true;
|
|
Packit |
bd2e5d |
fmbox, mbox
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
initializer
|
|
Packit |
bd2e5d |
(* Search *)
|
|
Packit |
bd2e5d |
let ew = Entry.create search_frame
|
|
Packit |
bd2e5d |
and searchtype = Textvariable.create ~on:tl () in
|
|
Packit |
bd2e5d |
bind ew ~events:[`KeyPressDetail "Return"] ~action:
|
|
Packit |
bd2e5d |
(fun _ -> search_string ew ~mode:(Textvariable.get searchtype));
|
|
Packit |
bd2e5d |
Jg_bind.enter_focus ew;
|
|
Packit |
bd2e5d |
let search_button ?value text =
|
|
Packit |
bd2e5d |
Radiobutton.create search_frame
|
|
Packit |
bd2e5d |
~text ~variable:searchtype ~value:text in
|
|
Packit |
bd2e5d |
let symbol = search_button "Name"
|
|
Packit |
bd2e5d |
and atype = search_button "Type" in
|
|
Packit |
bd2e5d |
Radiobutton.select symbol;
|
|
Packit |
bd2e5d |
pack [Label.create search_frame ~text:"Search"] ~side:`Left ~ipadx:5;
|
|
Packit |
bd2e5d |
pack [ew] ~fill:`X ~expand:true ~side:`Left;
|
|
Packit |
bd2e5d |
pack [Label.create search_frame ~text:"by"] ~side:`Left ~ipadx:5;
|
|
Packit |
bd2e5d |
pack [symbol; atype] ~side:`Left;
|
|
Packit |
bd2e5d |
pack [Label.create search_frame] ~side:`Right
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
initializer
|
|
Packit |
bd2e5d |
(* Boxes *)
|
|
Packit |
bd2e5d |
let fmbox, mbox = self#create_box in
|
|
Packit |
bd2e5d |
Jg_box.add_completion mbox ~nocase:true ~double:false ~action:
|
|
Packit |
bd2e5d |
begin fun index ->
|
|
Packit |
bd2e5d |
view_defined (Lident (Listbox.get mbox ~index)) ~env:!start_env
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
Setpath.add_update_hook (fun () -> reset_modules mbox; self#hide_after 1);
|
|
Packit |
bd2e5d |
List.iter [1;2] ~f:(fun _ -> ignore self#create_box);
|
|
Packit |
bd2e5d |
Searchpos.default_frame := Some
|
|
Packit |
bd2e5d |
{ mw_frame = view; mw_title = Some label;
|
|
Packit |
bd2e5d |
mw_detach = detach; mw_edit = edit; mw_intf = intf };
|
|
Packit |
bd2e5d |
Searchpos.set_path := self#set_path;
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Buttons *)
|
|
Packit |
bd2e5d |
pack [close] ~side:`Right ~fill:`X ~expand:true;
|
|
Packit |
bd2e5d |
bind close ~events:[`Modified([`Double], `ButtonPressDetail 1)]
|
|
Packit |
bd2e5d |
~action:(fun _ -> destroy tl);
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* File menu *)
|
|
Packit |
bd2e5d |
filemenu#add_command "Open..."
|
|
Packit |
bd2e5d |
~command:(fun () -> !editor_ref ~opendialog:true ());
|
|
Packit |
bd2e5d |
filemenu#add_command "Editor..." ~command:(fun () -> !editor_ref ());
|
|
Packit |
bd2e5d |
filemenu#add_command "Shell..." ~command:(fun () -> start_shell tl);
|
|
Packit |
bd2e5d |
filemenu#add_command "Quit" ~command:(fun () -> destroy tl);
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* View menu *)
|
|
Packit |
bd2e5d |
viewmenu#add_command "Show all defs" ~command:(fun () -> show_all ());
|
|
Packit |
bd2e5d |
let show_search = Textvariable.create ~on:tl () in
|
|
Packit |
bd2e5d |
Textvariable.set show_search "1";
|
|
Packit |
bd2e5d |
Menu.add_checkbutton viewmenu#menu ~label:"Search Entry"
|
|
Packit |
bd2e5d |
~variable:show_search ~indicatoron:true ~state:`Active
|
|
Packit |
bd2e5d |
~command:
|
|
Packit |
bd2e5d |
begin fun () ->
|
|
Packit |
bd2e5d |
let v = Textvariable.get show_search in
|
|
Packit |
bd2e5d |
if v = "1" then begin
|
|
Packit |
bd2e5d |
pack [search_frame] ~after:menus ~fill:`X
|
|
Packit |
bd2e5d |
end else Pack.forget [search_frame]
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* modules menu *)
|
|
Packit |
bd2e5d |
modmenu#add_command "Path editor..."
|
|
Packit |
bd2e5d |
~command:(fun () -> Setpath.set ~dir);
|
|
Packit |
bd2e5d |
modmenu#add_command "Reset cache"
|
|
Packit |
bd2e5d |
~command:(fun () -> reset_modules mbox; Env.reset_cache ());
|
|
Packit |
bd2e5d |
modmenu#add_command "Search symbol..." ~command:search_symbol;
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Help menu *)
|
|
Packit |
bd2e5d |
helpmenu#add_command "Manual..." ~command:show_help;
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
pack [search_frame] ~fill:`X;
|
|
Packit |
bd2e5d |
pack [boxes_frame] ~fill:`Both ~expand:true;
|
|
Packit |
bd2e5d |
pack [buttons] ~fill:`X ~side:`Bottom;
|
|
Packit |
bd2e5d |
pack [view] ~fill:`Both ~side:`Bottom ~expand:true;
|
|
Packit |
bd2e5d |
reset_modules mbox
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
val mutable shown_paths = []
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
method hide_after n =
|
|
Packit |
bd2e5d |
for i = n to List.length boxes - 1 do
|
|
Packit |
bd2e5d |
let fm, box = List.nth boxes i in
|
|
Packit |
bd2e5d |
if i < 3 then Listbox.delete box ~first:(`Num 0) ~last:`End
|
|
Packit |
bd2e5d |
else destroy fm
|
|
Packit |
bd2e5d |
done;
|
|
Packit |
bd2e5d |
let rec firsts n = function [] -> []
|
|
Packit |
bd2e5d |
| a :: l -> if n > 0 then a :: firsts (pred n) l else [] in
|
|
Packit |
bd2e5d |
shown_paths <- firsts (n-1) shown_paths;
|
|
Packit |
bd2e5d |
boxes <- firsts (max 3 n) boxes
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
method get_box ~path =
|
|
Packit |
bd2e5d |
let rec path_index p = function
|
|
Packit |
bd2e5d |
[] -> raise Not_found
|
|
Packit |
bd2e5d |
| a :: l -> if Path.same p a then 1 else path_index p l + 1 in
|
|
Packit |
bd2e5d |
try
|
|
Packit |
bd2e5d |
let n = path_index path shown_paths in
|
|
Packit |
bd2e5d |
self#hide_after (n+1);
|
|
Packit |
bd2e5d |
n
|
|
Packit |
bd2e5d |
with Not_found ->
|
|
Packit |
bd2e5d |
match path with
|
|
Packit |
bd2e5d |
Path.Pdot (path', _, _) ->
|
|
Packit |
bd2e5d |
let n = self#get_box ~path:path' in
|
|
Packit |
bd2e5d |
shown_paths <- shown_paths @ [path];
|
|
Packit |
bd2e5d |
if n + 1 >= List.length boxes then ignore self#create_box;
|
|
Packit |
bd2e5d |
n+1
|
|
Packit |
bd2e5d |
| _ ->
|
|
Packit |
bd2e5d |
self#hide_after 2;
|
|
Packit |
bd2e5d |
shown_paths <- [path];
|
|
Packit |
bd2e5d |
1
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
method set_path path ~sign =
|
|
Packit |
bd2e5d |
let rec path_elems l path =
|
|
Packit |
bd2e5d |
match path with
|
|
Packit |
bd2e5d |
Path.Pdot (path, _, _) -> path_elems (path::l) path
|
|
Packit |
bd2e5d |
| _ -> []
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let path_elems path =
|
|
Packit |
bd2e5d |
match path with
|
|
Packit |
bd2e5d |
| Path.Pident _ -> [path]
|
|
Packit |
bd2e5d |
| _ -> path_elems [] path
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let see_path ~box:n ?(sign=[]) path =
|
|
Packit |
bd2e5d |
let (_, box) = List.nth boxes n in
|
|
Packit |
bd2e5d |
let texts = Listbox.get_range box ~first:(`Num 0) ~last:`End in
|
|
Packit |
bd2e5d |
let rec index s = function
|
|
Packit |
bd2e5d |
[] -> raise Not_found
|
|
Packit |
bd2e5d |
| a :: l -> if a = s then 0 else 1 + index s l
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
try
|
|
Packit |
bd2e5d |
let modlid, s =
|
|
Packit |
bd2e5d |
match path with
|
|
Packit |
bd2e5d |
Path.Pdot (p, s, _) -> longident_of_path p, s
|
|
Packit |
bd2e5d |
| Path.Pident i -> Longident.Lident "M", Ident.name i
|
|
Packit |
bd2e5d |
| _ -> assert false
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let li, k =
|
|
Packit |
bd2e5d |
if sign = [] then Longident.Lident s, Pmodule else
|
|
Packit |
bd2e5d |
ident_of_decl ~modlid (List.hd sign) in
|
|
Packit |
bd2e5d |
let s =
|
|
Packit |
bd2e5d |
if n = 0 then string_of_longident li else
|
|
Packit |
bd2e5d |
string_of_longident li ^ " (" ^ string_of_kind k ^ ")" in
|
|
Packit |
bd2e5d |
let n = index s texts in
|
|
Packit |
bd2e5d |
Listbox.see box (`Num n);
|
|
Packit |
bd2e5d |
Listbox.activate box (`Num n)
|
|
Packit |
bd2e5d |
with Not_found -> ()
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let l = path_elems path in
|
|
Packit |
bd2e5d |
if l <> [] then begin
|
|
Packit |
bd2e5d |
List.iter l ~f:
|
|
Packit |
bd2e5d |
begin fun path ->
|
|
Packit |
bd2e5d |
if not (List.mem path shown_paths) then
|
|
Packit |
bd2e5d |
view_symbol (longident_of_path path) ~kind:Pmodule
|
|
Packit |
bd2e5d |
~env:!start_env ~path;
|
|
Packit |
bd2e5d |
let n = self#get_box path - 1 in
|
|
Packit |
bd2e5d |
see_path path ~box:n
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
see_path path ~box:(self#get_box path) ~sign
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
method choose_symbol ~title ~env ?signature ?path l =
|
|
Packit |
bd2e5d |
let n =
|
|
Packit |
bd2e5d |
match path with None -> 1
|
|
Packit |
bd2e5d |
| Some path -> self#get_box ~path
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
let l = List.sort l ~cmp:(fun (li1, _) (li2,_) -> compare li1 li2) in
|
|
Packit |
bd2e5d |
let nl = List.map l ~f:
|
|
Packit |
bd2e5d |
begin fun (li, k) ->
|
|
Packit |
bd2e5d |
string_of_longident li ^ " (" ^ string_of_kind k ^ ")"
|
|
Packit |
bd2e5d |
end in
|
|
Packit |
bd2e5d |
let _, box = List.nth boxes n in
|
|
Packit |
bd2e5d |
Listbox.delete box ~first:(`Num 0) ~last:`End;
|
|
Packit |
bd2e5d |
Listbox.insert box ~index:`End ~texts:nl;
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let current = ref None in
|
|
Packit |
bd2e5d |
let display index =
|
|
Packit |
bd2e5d |
let `Num pos = Listbox.index box ~index in
|
|
Packit |
bd2e5d |
try
|
|
Packit |
bd2e5d |
let li, k = try List.nth l pos with Failure _ -> raise Exit in
|
|
Packit |
bd2e5d |
self#hide_after (n+1);
|
|
Packit |
bd2e5d |
if !current = Some (li,k) then () else
|
|
Packit |
bd2e5d |
let path =
|
|
Packit |
bd2e5d |
match path, li with
|
|
Packit |
bd2e5d |
None, Ldot (lip, _) ->
|
|
Packit |
bd2e5d |
begin try
|
|
Packit |
bd2e5d |
Some (lookup_module ~load:true lip env)
|
|
Packit |
bd2e5d |
with Not_found -> None
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
| _ -> path
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
current := Some (li,k);
|
|
Packit |
bd2e5d |
view_symbol li ~kind:k ~env ?path
|
|
Packit |
bd2e5d |
with Exit -> ()
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
Jg_box.add_completion box ~double:false ~action:display;
|
|
Packit |
bd2e5d |
bind box ~events:[`KeyRelease] ~fields:[`Char]
|
|
Packit |
bd2e5d |
~action:(fun ev -> display `Active);
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
begin match signature with
|
|
Packit |
bd2e5d |
None -> ()
|
|
Packit |
bd2e5d |
| Some signature ->
|
|
Packit |
bd2e5d |
show_all <-
|
|
Packit |
bd2e5d |
begin fun () ->
|
|
Packit |
bd2e5d |
current := None;
|
|
Packit |
bd2e5d |
view_signature signature ~title ~env ?path
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let st_viewer ?dir ?on () =
|
|
Packit |
bd2e5d |
let viewer = new st_viewer ?dir ?on () in
|
|
Packit |
bd2e5d |
choose_symbol_ref := viewer#choose_symbol
|