diff --git a/src/indexMain.ml b/src/indexMain.ml index f15cd8e..cb30546 100644 --- a/src/indexMain.ml +++ b/src/indexMain.ml @@ -19,6 +19,18 @@ open Cmdliner let common_opts = IndexOptions.common_opts () +let man = [ + `S "COPYRIGHT"; + `P "Ocp-index is written by Louis Gesbert <louis.gesbert@ocamlpro.com>, \ + copyright OCamlPro 2013-2014, \ + distributed under the terms of the LGPL v3 with linking exception. \ + Full source available at $(i,https://github.com/OCamlPro/ocp-index)"; + `S "BUGS"; + `P "Bugs are tracked at $(i,https://github.com/OCamlPro/ocp-index/issues)."; + `S "SEE ALSO"; + `P "ocp-grep, ocp-browser"; +] + let default_cmd = let man = [ `S "DESCRIPTION"; @@ -26,8 +38,21 @@ let default_cmd = OCaml, for command-line or integrated use (e.g. for completion). \ It gathers information from .cmi (like ocamlbrowser) and \ .cmt/cmti files, including structure, location, type, and ocamldoc \ - comments when available." - ] + comments when available."; + `S "USING AN .ocp-index FILE"; + `P "It is possible to specify some of the options for ocp-index in a file \ + called $(b, .ocp-index) placed at the root of the project directory. \ + Currently only the list of include directories can be specified in this way. \ + Each line of the .ocp-index file should be of the form"; + `P "I \"<dir>\""; + `P "where \"<dir>\" is the name of a directory (between double quotes) \ + where ocp-index should look for .cmt[i] files. Typically this way \ + of specifying include directories would \ + be used in conjunction with the $(b,--no-recursive) options in order to \ + speed up directory scanning in those environments where the default \ + method is not fast enough (e.g. Cygwin). One can generate such a file by running"; + `P "find . -name '*.cmt*' -exec dirname {} \\\\; | sort | uniq | sed 's/.*/I \"&\"/g' > .ocp-index" + ] @ man in let doc = "Explore the interfaces of installed OCaml libraries." in Term.(ret (pure (fun _ -> `Help (`Pager, None)) $ common_opts)), @@ -59,18 +84,6 @@ let format_man = interpreted:" ] @ List.map (fun (k, s) -> `I (Printf.sprintf "$(b,%s)" k, s)) formats -let man = [ - `S "COPYRIGHT"; - `P "Ocp-index is written by Louis Gesbert <louis.gesbert@ocamlpro.com>, \ - copyright OCamlPro 2013-2014, \ - distributed under the terms of the LGPL v3 with linking exception. \ - Full source available at $(i,https://github.com/OCamlPro/ocp-index)"; - `S "BUGS"; - `P "Bugs are tracked at $(i,https://github.com/OCamlPro/ocp-index/issues)."; - `S "SEE ALSO"; - `P "ocp-grep, ocp-browser"; -] - let complete_cmd = let man = [ `S "DESCRIPTION"; diff --git a/src/indexMisc.ml b/src/indexMisc.ml index eee8666..3f19ec3 100644 --- a/src/indexMisc.ml +++ b/src/indexMisc.ml @@ -110,12 +110,21 @@ let unique_subdirs ?(skip = fun _ -> false) dir_list = in remove_dups (List.fold_left subdirs [] dir_list) +let read_all_lines path = + let ic = open_in path in + let acc = ref [] in + try + while true do + acc := input_line ic :: !acc + done; + assert false + with End_of_file -> !acc (* - Project root finding - *) let build_roots = (* by increasing order of priority *) [ "_darcs"; ".hg"; ".git"; - "jengaroot.ml"; "omakeroot"; "_build"; "_obuild" ] + "jengaroot.ml"; "omakeroot"; "_build"; "_obuild"; ".ocp-index" ] let find_build_dir path = let ( / ) = Filename.concat in diff --git a/src/indexMisc.mli b/src/indexMisc.mli index df74234..fe777d1 100644 --- a/src/indexMisc.mli +++ b/src/indexMisc.mli @@ -43,6 +43,8 @@ val parent_type: IndexTypes.info -> IndexTypes.info option If directory basename verifies [skip], it is not descended nor returned. *) val unique_subdirs: ?skip:(string -> bool) -> string list -> string list +val read_all_lines: string -> string list + (** An heuristic to guess where the root directory of the current project. Returns (project_root, build_dir) *) val project_root: ?path:string -> unit -> string option * string option diff --git a/src/indexOptions.ml b/src/indexOptions.ml index d5b5d18..3237dad 100644 --- a/src/indexOptions.ml +++ b/src/indexOptions.ml @@ -65,7 +65,7 @@ let default_filter = [ `V ; `E ; `C ; `M ; `K ] let filter_to_string l = let pp = function - | `V -> "v" | `E -> "b" | `C -> "c" + | `V -> "v" | `E -> "e" | `C -> "c" | `M -> "m" | `K -> "k" | `S -> "s" | `T -> "t" in @@ -84,7 +84,9 @@ let common_opts ?(default_filter = default_filter) () : t Term.t = Arg.(value & flag & info ["no-opamlib"] ~doc); in let arg = - let doc = "OCaml directories to (recursively) load the libraries from." in + let doc = "OCaml directories to load the libraries from. \ + By default, the directories are traversed recursively. \ + This can be changed by passing the $(b,--no-recursive) option." in Arg.(value & opt_all (list string) [] & info ["I"] ~docv:"DIRS" ~doc) in let set_default no_stdlib no_opamlib includes = @@ -99,6 +101,10 @@ let common_opts ?(default_filter = default_filter) () : t Term.t = in Term.(pure set_default $ no_stdlib $ no_opamlib $ arg) in + let no_recursive : bool Term.t = + let doc = "Do not traverse include directories recursively." in + Arg.(value & flag & info ["no-recursive"] ~doc) + in let color : bool Term.t = let arg = let choices = Arg.enum [ "always", `Always; @@ -245,14 +251,32 @@ let common_opts ?(default_filter = default_filter) () : t Term.t = Arg.(value & opt (some filepos_converter) None & info ["context"] ~docv:"FILEPOS" ~doc) in - let lib_info ocamllib (_root,build) (opens,full_opens) context = + let lib_info ocamllib no_recursive (root,build) (opens,full_opens) context = let dirs = match build with | None -> ocamllib | Some d -> d :: ocamllib in + let dirs = + let extra_dirs = match root with + | Some root -> + let make_absolute path = if Filename.is_relative path then Filename.concat root path else path in + let dot_ocp_index = Filename.concat root ".ocp-index" in + if Sys.file_exists dot_ocp_index then begin + let l = IndexMisc.read_all_lines dot_ocp_index in + List.map (fun s -> Scanf.sscanf s "I %S" make_absolute) l + end + else + [] + | None -> [] + in + dirs @ extra_dirs + in if dirs = [] then failwith "Failed to guess OCaml / opam lib dirs. Please use `-I'"; - let dirs = LibIndex.Misc.unique_subdirs dirs in + IndexMisc.debug "Scanning directories... "; + let chrono = IndexMisc.timer () in + let dirs = if no_recursive then dirs else LibIndex.Misc.unique_subdirs dirs in + IndexMisc.debug "%.3fs\n%!" (chrono ()); let info = LibIndex.load dirs in let info = List.fold_left (LibIndex.open_module ~cleanup_path:true) info opens @@ -281,8 +305,8 @@ let common_opts ?(default_filter = default_filter) () : t Term.t = in Term.( pure - (fun ocamllib project_dirs opens color filter context -> - { lib_info = lib_info ocamllib project_dirs opens context; + (fun ocamllib no_recursive project_dirs opens color filter context -> + { lib_info = lib_info ocamllib no_recursive project_dirs opens context; color; filter; project_root = fst project_dirs }) - $ ocamllib $ project_dirs $ open_modules $ color $ filter $ context + $ ocamllib $ no_recursive $ project_dirs $ open_modules $ color $ filter $ context )