diff --git a/src/driver/bin/odoc_driver.ml b/src/driver/bin/odoc_driver.ml index fb01d653d2..7e43cf8f0f 100644 --- a/src/driver/bin/odoc_driver.ml +++ b/src/driver/bin/odoc_driver.ml @@ -7,7 +7,7 @@ let with_dir dir pat f = | Some dir -> f dir () let run_inner ~odoc_dir ~odocl_dir ~index_dir ~mld_dir ~compile_grep ~link_grep - ~generate_grep ~index_grep ~remap packages + ~generate_grep ~index_grep ~remap ~index_mld packages { Common_args.verbose; html_dir; @@ -27,6 +27,16 @@ let run_inner ~odoc_dir ~odocl_dir ~index_dir ~mld_dir ~compile_grep ~link_grep Logs.set_reporter (Logs_fmt.reporter ()); Stats.init_nprocs nb_workers; + let index_mld_content = + Option.bind index_mld (fun fpath -> + match Bos.OS.File.read fpath with + | Ok content -> Some content + | Error (`Msg msg) -> + Logs.err (fun m -> + m "Failed to read index_mld file '%a': %s" Fpath.pp fpath msg); + exit 1) + in + Eio_main.run @@ fun env -> Eio.Switch.run @@ fun sw -> let () = Worker_pool.start_workers env sw nb_workers in @@ -45,7 +55,9 @@ let run_inner ~odoc_dir ~odocl_dir ~index_dir ~mld_dir ~compile_grep ~link_grep (fun () -> let units = let dirs = { Odoc_unit.odoc_dir; odocl_dir; index_dir; mld_dir } in - Odoc_units_of.packages ~dirs ~indices_style:Odoc_units_of.Normal + Odoc_units_of.packages ~dirs + ~indices_style: + (Odoc_units_of.Normal { toplevel_content = index_mld_content }) ~extra_paths ~remap all in Compile.init_stats units; @@ -124,14 +136,14 @@ let run_inner ~odoc_dir ~odocl_dir ~index_dir ~mld_dir ~compile_grep ~link_grep if stats then Stats.bench_results html_dir let run odoc_dir odocl_dir index_dir mld_dir compile_grep link_grep - generate_grep index_grep remap packages common () = + generate_grep index_grep remap packages index_mld common () = with_dir odoc_dir "odoc-%s" @@ fun odoc_dir () -> with_dir odocl_dir "odocl-%s" @@ fun odocl_dir () -> with_dir index_dir "index-%s" @@ fun index_dir () -> with_dir mld_dir "mld-%s" @@ fun mld_dir () -> let () = run_inner ~odoc_dir ~odocl_dir ~index_dir ~mld_dir ~compile_grep ~link_grep - ~generate_grep ~index_grep ~remap packages common + ~generate_grep ~index_grep ~remap ~index_mld packages common in () @@ -189,10 +201,20 @@ let remap = let packages = Arg.(value & pos_all string [] & info [] ~docv:"PACKAGES") +let index_mld = + let doc = + "Provide an index.mld file to serve as the top-level index of the \ + documentation" + in + Arg.( + value + & opt (some Common_args.fpath_arg) None + & info [ "index-mld" ] ~docv:"INDEX" ~doc) + let cmd_term = Term.( const run $ odoc_dir $ odocl_dir $ index_dir $ mld_dir $ compile_grep - $ link_grep $ generate_grep $ index_grep $ remap $ packages + $ link_grep $ generate_grep $ index_grep $ remap $ packages $ index_mld $ Common_args.term $ const ()) let cmd = diff --git a/src/driver/compile.ml b/src/driver/compile.ml index b2b90a4224..4405a71427 100644 --- a/src/driver/compile.ml +++ b/src/driver/compile.ml @@ -2,13 +2,13 @@ open Bos -type compiled = Odoc_unit.t +type compiled = Odoc_unit.any let odoc_partial_filename = "__odoc_partial.m" -let mk_byhash (pkgs : Odoc_unit.t list) = +let mk_byhash (pkgs : Odoc_unit.any list) = List.fold_left - (fun acc (u : Odoc_unit.t) -> + (fun acc (u : Odoc_unit.any) -> match u.Odoc_unit.kind with | `Intf { hash; _ } as kind -> let elt = { u with kind } in @@ -18,11 +18,11 @@ let mk_byhash (pkgs : Odoc_unit.t list) = | _ -> acc) Util.StringMap.empty pkgs -let init_stats (units : Odoc_unit.t list) = +let init_stats (units : Odoc_unit.any list) = let total, total_impl, non_hidden, mlds, assets, indexes = List.fold_left (fun (total, total_impl, non_hidden, mlds, assets, indexes) - (unit : Odoc_unit.t) -> + (unit : Odoc_unit.any) -> let total = match unit.kind with `Intf _ -> total + 1 | _ -> total in let total_impl = match unit.kind with `Impl _ -> total_impl + 1 | _ -> total_impl @@ -56,8 +56,8 @@ let init_stats (units : Odoc_unit.t list) = open Eio.Std type partial = - ((string * string) * Odoc_unit.intf Odoc_unit.unit list) list - * Odoc_unit.intf Odoc_unit.unit list Util.StringMap.t + ((string * string) * Odoc_unit.intf Odoc_unit.t list) list + * Odoc_unit.intf Odoc_unit.t list Util.StringMap.t let unmarshal filename : partial = let ic = open_in_bin (Fpath.to_string filename) in @@ -73,7 +73,7 @@ let marshal (v : partial) filename = (fun () -> Marshal.to_channel oc v []) let find_partials odoc_dir : - Odoc_unit.intf Odoc_unit.unit list Util.StringMap.t * _ = + Odoc_unit.intf Odoc_unit.t list Util.StringMap.t * _ = let tbl = Hashtbl.create 1000 in let hashes_result = OS.Dir.fold_contents ~dotfiles:false ~elements:`Dirs @@ -94,7 +94,7 @@ let find_partials odoc_dir : | Ok h -> (h, tbl) | Error _ -> (* odoc_dir doesn't exist...? *) (Util.StringMap.empty, tbl) -let compile ?partial ~partial_dir (all : Odoc_unit.t list) = +let compile ?partial ~partial_dir (all : Odoc_unit.any list) = let hashes = mk_byhash all in let compile_mod = (* Modules have a more complicated compilation because: @@ -119,7 +119,7 @@ let compile ?partial ~partial_dir (all : Odoc_unit.t list) = | Some units -> Ok (List.map - (fun (unit : Odoc_unit.intf Odoc_unit.unit) -> + (fun (unit : Odoc_unit.intf Odoc_unit.t) -> let deps = match unit.kind with `Intf { deps; _ } -> deps in let _fibers = Fiber.List.map @@ -152,7 +152,7 @@ let compile ?partial ~partial_dir (all : Odoc_unit.t list) = units) in let rec compile_mod : - string -> (Odoc_unit.intf Odoc_unit.unit list, exn) Result.t = + string -> (Odoc_unit.intf Odoc_unit.t list, exn) Result.t = fun hash -> let units = try Util.StringMap.find hash hashes with _ -> [] in let r = @@ -185,9 +185,9 @@ let compile ?partial ~partial_dir (all : Odoc_unit.t list) = compile_mod in - let compile (unit : Odoc_unit.t) = + let compile (unit : Odoc_unit.any) = match unit.kind with - | `Intf intf -> (compile_mod intf.hash :> (Odoc_unit.t list, _) Result.t) + | `Intf intf -> (compile_mod intf.hash :> (Odoc_unit.any list, _) Result.t) | `Impl src -> let includes = List.fold_left @@ -242,7 +242,7 @@ let compile ?partial ~partial_dir (all : Odoc_unit.t list) = | None -> ()); all -type linked = Odoc_unit.t +type linked = Odoc_unit.any let link : custom_layout:bool -> compiled list -> _ = fun ~custom_layout compiled -> diff --git a/src/driver/compile.mli b/src/driver/compile.mli index 5626b202ef..5d68fe0ca0 100644 --- a/src/driver/compile.mli +++ b/src/driver/compile.mli @@ -1,9 +1,9 @@ -type compiled = Odoc_unit.t +type compiled = Odoc_unit.any -val init_stats : Odoc_unit.t list -> unit +val init_stats : Odoc_unit.any list -> unit val compile : - ?partial:Fpath.t -> partial_dir:Fpath.t -> Odoc_unit.t list -> compiled list + ?partial:Fpath.t -> partial_dir:Fpath.t -> Odoc_unit.any list -> compiled list (** Use [partial] to reuse the output of a previous call to [compile]. Useful in the voodoo context. diff --git a/src/driver/landing_pages.ml b/src/driver/landing_pages.ml index f84ffecdd4..f58a5a3fc1 100644 --- a/src/driver/landing_pages.ml +++ b/src/driver/landing_pages.ml @@ -3,7 +3,8 @@ open Packages let fpf = Format.fprintf -let make_index ~dirs ~rel_dir ?(libs = []) ?(pkgs = []) ?index ~content () = +let make_index ~dirs ~rel_dir ~libs ~pkgs ~index ~enable_warnings ~content : + Odoc_unit.mld Odoc_unit.t = let { odoc_dir; odocl_dir; mld_dir; _ } = dirs in let input_file = Fpath.(mld_dir // rel_dir / "index.mld") in let odoc_file = Fpath.(odoc_dir // rel_dir / "page-index.odoc") in @@ -29,7 +30,7 @@ let make_index ~dirs ~rel_dir ?(libs = []) ?(pkgs = []) ?index ~content () = input_file; odoc_file; odocl_file; - enable_warnings = false; + enable_warnings; to_output = true; kind = `Mld; index; @@ -56,7 +57,8 @@ let library ~dirs ~pkg ~index lib = in let rel_dir = lib_dir pkg lib in let libs = [ (pkg, lib) ] in - make_index ~dirs ~rel_dir ~libs ~index ~content () + make_index ~dirs ~rel_dir ~libs ~pkgs:[] ~index:(Some index) ~content + ~enable_warnings:false let package ~dirs ~pkg ~index = let library_list ppf pkg = @@ -83,7 +85,8 @@ let package ~dirs ~pkg ~index = let content = content pkg in let rel_dir = doc_dir pkg in let libs = List.map (fun lib -> (pkg, lib)) pkg.libraries in - make_index ~dirs ~rel_dir ~index ~content ~pkgs:[ pkg ] ~libs () + make_index ~dirs ~rel_dir ~index:(Some index) ~content ~pkgs:[ pkg ] ~libs + ~enable_warnings:false let src ~dirs ~pkg ~index = let content ppf = @@ -95,7 +98,8 @@ let src ~dirs ~pkg ~index = pkg.name in let rel_dir = src_dir pkg in - make_index ~dirs ~rel_dir ~index ~content () + make_index ~dirs ~pkgs:[] ~libs:[] ~rel_dir ~index:(Some index) ~content + ~enable_warnings:true let package_list ~dirs ~remap all = let content all ppf = @@ -111,7 +115,8 @@ let package_list ~dirs ~remap all = in let content = content all in let rel_dir = Fpath.v "./" in - make_index ~dirs ~rel_dir ~pkgs:all ~content () + make_index ~dirs ~rel_dir ~pkgs:all ~libs:[] ~index:None ~content + ~enable_warnings:true let content dir _pkg libs _src subdirs all_libs pfp = let is_root = Fpath.to_string dir = "./" in @@ -152,7 +157,7 @@ let content dir _pkg libs _src subdirs all_libs pfp = all_libs) let make_custom dirs index_of (pkg : Packages.t) : - Odoc_unit.mld Odoc_unit.unit list = + Odoc_unit.mld Odoc_unit.t list = let pkgs = [ pkg ] in let pkg_dirs = List.fold_right @@ -278,7 +283,7 @@ let make_custom dirs index_of (pkg : Packages.t) : let idx = make_index ~dirs ~rel_dir:p ~libs ~pkgs ~content:(content p pkg libs src subdirs all_libs) - ?index () + ~index ~enable_warnings:false in idx :: acc) all_dirs [] diff --git a/src/driver/landing_pages.mli b/src/driver/landing_pages.mli index b14dc95258..886d904df5 100644 --- a/src/driver/landing_pages.mli +++ b/src/driver/landing_pages.mli @@ -1,13 +1,23 @@ open Odoc_unit +val make_index : + dirs:dirs -> + rel_dir:Fpath.t -> + libs:(Packages.t * Packages.libty) list -> + pkgs:Packages.t list -> + index:index option -> + enable_warnings:bool -> + content:(Format.formatter -> unit) -> + mld Odoc_unit.t + val library : - dirs:dirs -> pkg:Packages.t -> index:index -> Packages.libty -> mld unit + dirs:dirs -> pkg:Packages.t -> index:index -> Packages.libty -> mld t -val package : dirs:dirs -> pkg:Packages.t -> index:index -> mld unit +val package : dirs:dirs -> pkg:Packages.t -> index:index -> mld t -val src : dirs:dirs -> pkg:Packages.t -> index:index -> mld unit +val src : dirs:dirs -> pkg:Packages.t -> index:index -> mld t -val package_list : dirs:dirs -> remap:bool -> Packages.t list -> mld unit +val package_list : dirs:dirs -> remap:bool -> Packages.t list -> mld t val make_custom : - dirs -> (Packages.t -> Odoc_unit.index) -> Packages.t -> mld unit list + dirs -> (Packages.t -> Odoc_unit.index) -> Packages.t -> mld t list diff --git a/src/driver/odoc_unit.ml b/src/driver/odoc_unit.ml index f4be815132..3305285acd 100644 --- a/src/driver/odoc_unit.ml +++ b/src/driver/odoc_unit.ml @@ -71,7 +71,7 @@ let pp_index fmt x = (Fmt.list Fpath.pp) x.roots Fpath.pp x.output_file x.json Fpath.pp x.search_dir -type 'a unit = { +type 'a t = { parent_id : Odoc.Id.t; input_file : Fpath.t; output_dir : Fpath.t; @@ -101,7 +101,7 @@ type md = [ `Md ] type asset = [ `Asset ] type all_kinds = [ impl | intf | mld | asset | md ] -type t = all_kinds unit +type any = all_kinds t let rec pp_kind : all_kinds Fmt.t = fun fmt x -> @@ -122,7 +122,7 @@ and pp_impl_extra fmt x = (Odoc.Id.to_string x.src_id) Fpath.pp x.src_path -and pp : all_kinds unit Fmt.t = +and pp : all_kinds t Fmt.t = fun fmt x -> Format.fprintf fmt "@[parent_id: %s@;\ @@ -160,8 +160,8 @@ type dirs = { mld_dir : Fpath.t; } -let fix_virtual ~(precompiled_units : intf unit list Util.StringMap.t) - ~(units : intf unit list Util.StringMap.t) = +let fix_virtual ~(precompiled_units : intf t list Util.StringMap.t) + ~(units : intf t list Util.StringMap.t) = Logs.debug (fun m -> m "Fixing virtual libraries: %d precompiled units, %d other units" (Util.StringMap.cardinal precompiled_units) @@ -189,13 +189,13 @@ let fix_virtual ~(precompiled_units : intf unit list Util.StringMap.t) "Virtual library check: Selecting cmti for hash %s from \ %d possibilities: %a" uhash (List.length xs) (Fmt.Dump.list pp) - (xs :> t list)); + (xs :> any list)); let unit_name = Fpath.rem_ext unit.input_file |> Fpath.basename in match List.filter - (fun (x : intf unit) -> + (fun (x : intf t) -> (match x.kind with `Intf { hash; _ } -> uhash = hash) && Fpath.has_ext "cmti" x.input_file && Fpath.rem_ext x.input_file |> Fpath.basename diff --git a/src/driver/odoc_unit.mli b/src/driver/odoc_unit.mli index 758c071cd6..fd0bb19876 100644 --- a/src/driver/odoc_unit.mli +++ b/src/driver/odoc_unit.mli @@ -29,7 +29,7 @@ type index = { sidebar : sidebar option; } -type 'a unit = { +type 'a t = { parent_id : Odoc.Id.t; input_file : Fpath.t; output_dir : Fpath.t; @@ -57,9 +57,9 @@ type mld = [ `Mld ] type md = [ `Md ] type asset = [ `Asset ] -type t = [ impl | intf | mld | asset | md ] unit +type any = [ impl | intf | mld | asset | md ] t -val pp : t Fmt.t +val pp : any Fmt.t val pkg_dir : Packages.t -> Fpath.t val lib_dir : Packages.t -> Packages.libty -> Fpath.t @@ -75,9 +75,9 @@ type dirs = { } val fix_virtual : - precompiled_units:intf unit list Util.StringMap.t -> - units:intf unit list Util.StringMap.t -> - intf unit list Util.StringMap.t + precompiled_units:intf t list Util.StringMap.t -> + units:intf t list Util.StringMap.t -> + intf t list Util.StringMap.t (** [fix_virtual ~precompiled_units ~units] replaces the input file in units representing implementations of virtual libraries. Implementation units have a [cmt] but no [cmti], even though diff --git a/src/driver/odoc_units_of.ml b/src/driver/odoc_units_of.ml index 3f951f9823..af44d0bdef 100644 --- a/src/driver/odoc_units_of.ml +++ b/src/driver/odoc_units_of.ml @@ -1,9 +1,12 @@ open Odoc_unit -type indices_style = Voodoo | Normal | Automatic +type indices_style = + | Voodoo + | Normal of { toplevel_content : string option } + | Automatic let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : - t list = + any list = let { odoc_dir; odocl_dir; index_dir; mld_dir = _ } = dirs in (* [module_of_hash] Maps a hash to the corresponding [Package.t], library name and [Packages.modulety]. [lib_dirs] maps a library name to the odoc dir containing its @@ -99,7 +102,7 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : in let make_unit ~name ~kind ~rel_dir ~input_file ~pkg ~lib_deps ~enable_warnings - ~to_output : _ unit = + ~to_output : _ t = let to_output = to_output || not remap in (* If we haven't got active remapping, we output everything *) let ( // ) = Fpath.( // ) in @@ -129,7 +132,7 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : in let of_intf hidden pkg (lib : Packages.libty) lib_deps (intf : Packages.intf) - : intf unit = + : intf t = let rel_dir = lib_dir pkg lib in let kind = let deps = intf.mif_deps in @@ -140,7 +143,7 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : make_unit ~name ~kind ~rel_dir ~input_file:intf.mif_path ~pkg ~lib_deps ~enable_warnings:pkg.selected ~to_output:pkg.selected in - let of_impl pkg lib lib_deps (impl : Packages.impl) : impl unit option = + let of_impl pkg lib lib_deps (impl : Packages.impl) : impl t option = match impl.mip_src_info with | None -> None | Some { src_path } -> @@ -164,9 +167,9 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : in let of_module pkg (lib : Packages.libty) lib_deps (m : Packages.modulety) : - t list = - let i :> t = of_intf m.m_hidden pkg lib lib_deps m.m_intf in - let m :> t list = + any list = + let i :> any = of_intf m.m_hidden pkg lib lib_deps m.m_intf in + let m :> any list = Option.bind m.m_impl (of_impl pkg lib lib_deps) |> Option.to_list in i :: m @@ -177,10 +180,10 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : let units = List.concat_map (of_module pkg lib lib_deps) lib.modules in if remap && not pkg.selected then units else - let landing_page :> t = Landing_pages.library ~dirs ~pkg ~index lib in + let landing_page :> any = Landing_pages.library ~dirs ~pkg ~index lib in landing_page :: units in - let of_mld pkg (mld : Packages.mld) : mld unit list = + let of_mld pkg (mld : Packages.mld) : mld t list = let open Fpath in let { Packages.mld_path; mld_rel_path } = mld in let rel_dir = doc_dir pkg // Fpath.parent mld_rel_path |> Fpath.normalize in @@ -197,7 +200,7 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : in [ unit ] in - let of_md pkg (md : Packages.md) : md unit list = + let of_md pkg (md : Packages.md) : md t list = let ext = Fpath.get_ext md.md_path in match ext with | ".md" -> @@ -221,7 +224,7 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : m "Skipping non-markdown doc file %a" Fpath.pp md.md_path); [] in - let of_asset pkg (asset : Packages.asset) : asset unit list = + let of_asset pkg (asset : Packages.asset) : asset t list = let open Fpath in let { Packages.asset_path; asset_rel_path } = asset in let rel_dir = @@ -236,12 +239,12 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : [ unit ] in - let of_package (pkg : Packages.t) : t list = - let lib_units :> t list list = List.map (of_lib pkg) pkg.libraries in - let mld_units :> t list list = List.map (of_mld pkg) pkg.mlds in - let asset_units :> t list list = List.map (of_asset pkg) pkg.assets in - let md_units :> t list list = List.map (of_md pkg) pkg.other_docs in - let pkg_index () :> t list = + let of_package (pkg : Packages.t) : any list = + let lib_units :> any list list = List.map (of_lib pkg) pkg.libraries in + let mld_units :> any list list = List.map (of_mld pkg) pkg.mlds in + let asset_units :> any list list = List.map (of_asset pkg) pkg.assets in + let md_units :> any list list = List.map (of_md pkg) pkg.other_docs in + let pkg_index () :> any list = let has_index_page = List.exists (fun mld -> @@ -255,7 +258,7 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : let index = index_of pkg in [ Landing_pages.package ~dirs ~pkg ~index ] in - let src_index () :> t list = + let src_index () :> any list = if remap && not pkg.selected then [] else if (* Some library has a module which has an implementation which has a source *) @@ -276,17 +279,31 @@ let packages ~dirs ~extra_paths ~remap ~indices_style (pkgs : Packages.t list) : let std_units = mld_units @ asset_units @ md_units @ lib_units in match indices_style with | Automatic when pkg.name = Monorepo_style.monorepo_pkg_name -> - let others :> t list = + let others :> any list = Landing_pages.make_custom dirs index_of (List.find (fun p -> p.Packages.name = Monorepo_style.monorepo_pkg_name) pkgs) in others @ List.concat std_units - | Normal | Voodoo | Automatic -> + | Normal _ | Voodoo | Automatic -> List.concat (pkg_index () :: src_index () :: std_units) in - if indices_style = Normal then - let gen_indices :> t = Landing_pages.package_list ~dirs ~remap pkgs in - gen_indices :: List.concat_map of_package pkgs - else List.concat_map of_package pkgs + match indices_style with + | Normal { toplevel_content = None } -> + let gen_indices :> any = Landing_pages.package_list ~dirs ~remap pkgs in + gen_indices :: List.concat_map of_package pkgs + | Normal { toplevel_content = Some content } -> + let content ppf = Format.fprintf ppf "%s" content in + let libs = + List.concat_map + (fun pkg -> List.map (fun lib -> (pkg, lib)) pkg.Packages.libraries) + pkgs + in + let index :> any = + Landing_pages.make_index ~dirs + ~rel_dir:Fpath.(v "./") + ~libs ~pkgs ~enable_warnings:true ~content ~index:None + in + index :: List.concat_map of_package pkgs + | Voodoo | Automatic -> List.concat_map of_package pkgs diff --git a/src/driver/odoc_units_of.mli b/src/driver/odoc_units_of.mli index c3ada3b4ae..655ba58797 100644 --- a/src/driver/odoc_units_of.mli +++ b/src/driver/odoc_units_of.mli @@ -1,6 +1,9 @@ open Odoc_unit -type indices_style = Voodoo | Normal | Automatic +type indices_style = + | Voodoo + | Normal of { toplevel_content : string option } + | Automatic val packages : dirs:dirs -> @@ -8,4 +11,4 @@ val packages : remap:bool -> indices_style:indices_style -> Packages.t list -> - t list + any list