diff --git a/src/document/sidebar.ml b/src/document/sidebar.ml index 597142835c..8db115237a 100644 --- a/src/document/sidebar.ml +++ b/src/document/sidebar.ml @@ -15,56 +15,31 @@ module Toc : sig val of_lang : Odoc_model.Sidebar.PageToc.t -> t - val of_skeleton : Odoc_index.Entry.t Odoc_index.Skeleton.node -> t + val of_skeleton : Odoc_index.Entry.t Tree.t -> t - val to_sidebar : Url.Path.t -> t -> Block.t + val to_block : prune:bool -> Url.Path.t -> t -> Block.t end = struct - type t = Item of (Url.t * Inline.one) option * t list + type t = (Url.t * Inline.one) option Tree.t module Sidebar = Odoc_model.Sidebar - open Odoc_model.Paths + module Id = Odoc_model.Paths.Identifier let of_lang (dir : Sidebar.PageToc.t) = - let rec of_lang ~parent_id ((content, index) : Sidebar.PageToc.t) = - let title, parent_id = + let fun_ index = + let payload = match index with + | None -> None | Some (index_id, title) -> - (Some title, Some (index_id :> Identifier.Page.t)) - | None -> (None, (parent_id :> Identifier.Page.t option)) - in - let entries = - List.filter_map - (fun id -> - match id with - | id, Sidebar.PageToc.Entry title -> - let payload = - let path = - Url.from_identifier ~stop_before:false - (id : Identifier.Page.t :> Identifier.t) - |> Result.get_ok - in - let content = Comment.link_content title in - Some (path, sidebar_toc_entry id content) - in - Some (Item (payload, [])) - | id, Sidebar.PageToc.Dir dir -> - Some (of_lang ~parent_id:(Some id) dir)) - content - in - let payload = - match (title, parent_id) with - | None, _ | _, None -> None - | Some title, Some parent_id -> let path = - Url.from_identifier ~stop_before:false (parent_id :> Identifier.t) + Url.from_identifier ~stop_before:false (index_id :> Id.t) |> Result.get_ok in let content = Comment.link_content title in - Some (path, sidebar_toc_entry parent_id content) + Some (path, sidebar_toc_entry index_id content) in - Item (payload, entries) + payload in - of_lang ~parent_id:None dir + Tree.map_t fun_ dir let rec is_prefix (url1 : Url.Path.t) (url2 : Url.Path.t) = if url1 = url2 then true @@ -78,55 +53,59 @@ end = struct | { anchor = ""; page = { parent = Some parent; _ }; _ } -> parent | { page; _ } -> page - let rec to_sidebar (current_url : Url.Path.t) (Item (name, content)) = - let content = - List.filter - (fun (Item (name, _)) -> - match name with - | None -> false - | Some (url, _) -> is_prefix (parent url) current_url) - content - in - let convert ((url : Url.t), b) = - let link = - let is_parent (url : Url.t) (current_url : Url.Path.t) = - match url.page.parent with None -> false | Some p -> p = current_url + let to_block ~prune (current_url : Url.Path.t) tree = + let block_tree_of_t (current_url : Url.Path.t) tree = + (* When transforming the tree, we use a filter_map to remove the nodes that + are irrelevant for the current url. However, we always want to keep the + root. So we apply the filter_map starting from the first children. *) + let convert ((url : Url.t), b) = + let link = + if url.page = current_url && String.equal url.anchor "" then + { b with Inline.attr = [ "current_unit" ] } + else b in - if url.page = current_url && String.equal url.anchor "" then - { b with Inline.attr = [ "current_unit" ] } - else if - is_parent url current_url - || ((not (String.equal url.anchor "")) && url.page = current_url) - then { b with Inline.attr = [ "in_current_unit" ] } - else b + Types.block @@ Inline [ link ] in - Types.block @@ Inline [ link ] - in - let name = - match name with - | Some v -> convert v - | None -> block (Block.Inline [ inline (Text "root") ]) + let fun_ name = + match name with + | Some ((url, _) as v) + when (not prune) || is_prefix (parent url) current_url -> + Some (convert v) + | _ -> None + in + let root_entry = + match tree.Tree.entry with + | Some v -> convert v + | None -> block (Block.Inline [ inline (Text "root") ]) + in + { + Tree.entry = root_entry; + children = Tree.filter_map_f fun_ tree.children; + } in - let content = - match content with - | [] -> [] - | _ :: _ -> - let content = List.map (to_sidebar current_url) content in - [ block (Block.List (Block.Unordered, content)) ] + let rec block_of_block_tree { Tree.entry = name; children = content } = + let content = + match content with + | [] -> [] + | _ :: _ -> + let content = List.map block_of_block_tree content in + [ block (Block.List (Block.Unordered, content)) ] + in + name :: content in - name :: content + let block_tree = block_tree_of_t current_url tree in + block_of_block_tree block_tree - let rec of_skeleton - ({ entry; children } : Odoc_index.Entry.t Odoc_index.Skeleton.node) = - let stop_before = - match entry.kind with - | ModuleType { has_expansion } | Module { has_expansion } -> - not has_expansion - | _ -> false - in - let path = Url.from_identifier ~stop_before entry.id in - let name = Odoc_model.Paths.Identifier.name entry.id in - let payload = + let of_skeleton ({ entry; children } : Odoc_index.Entry.t Tree.t) = + let map_entry entry = + let stop_before = + match entry.Odoc_index.Entry.kind with + | ModuleType { has_expansion } | Module { has_expansion } -> + not has_expansion + | _ -> false + in + let path = Url.from_identifier ~stop_before entry.id in + let name = Odoc_model.Paths.Identifier.name entry.id in match path with | Ok path -> let content = @@ -137,24 +116,15 @@ end = struct Some (path, content) | Error _ -> None in - let children = - List.filter - (function - | { - Odoc_index.Skeleton.entry = - { - Odoc_index.Entry.kind = - Module _ | Class_type _ | Class _ | ModuleType _; - _; - }; - _; - } -> - true - | _ -> false) - children + let fun_ entry = + match entry.Odoc_index.Entry.kind with + | Module _ | Class_type _ | Class _ | ModuleType _ -> + Some (map_entry entry) + | _ -> None in - let entries = List.map of_skeleton children in - Item (payload, entries) + let entry = map_entry entry in + let children = Tree.filter_map_f fun_ children in + { Tree.entry; children } end type pages = { name : string; pages : Toc.t } @@ -172,18 +142,6 @@ let of_lang (v : Odoc_index.Index.t) = Odoc_utils.List.filter_map page_hierarchy v.pages in let units = - (* let item id = *) - (* let content = [ inline @@ Text (Odoc_model.Paths.Identifier.name id) ] in *) - (* (Url.Path.from_identifier id, sidebar_toc_entry id content) *) - (* in *) - (* let units = *) - (* List.map *) - (* (fun { Odoc_model.Sidebar.units; name } -> *) - (* let units = List.map item units in *) - (* { name; units }) *) - (* v.libraries *) - (* in *) - (* units *) List.map (fun sk -> { units = Toc.of_skeleton sk; name = "yo" }) index in { pages; libraries = units } @@ -197,7 +155,7 @@ let to_block (sidebar : t) path = let pages = Odoc_utils.List.concat_map ~f:(fun (p : pages) -> - let pages = Toc.to_sidebar path p.pages in + let pages = Toc.to_block ~prune:false path p.pages in let pages = [ block (Block.List (Block.Unordered, [ pages ])) ] in let pages = [ title @@ p.name ^ "'s Pages" ] @ pages in pages) @@ -207,17 +165,10 @@ let to_block (sidebar : t) path = let units = List.map (fun { units; name } -> - (* match Toc.prune units path with *) - (* | Some units -> *) - let units = Toc.to_sidebar path units in + let units = Toc.to_block ~prune:true path units in let units = [ block (Block.List (Block.Unordered, [ units ])) ] in let units = [ title @@ name ^ "'s Units" ] @ units in - units - (* | None -> [] *) - (* [ *) - (* title name; *) - (* block (List (Block.Unordered, [ List.map render_entry units ])); *) - (* ] *)) + units) libraries in let units = block (Block.List (Block.Unordered, units)) in diff --git a/src/model/fold.ml b/src/model/fold.ml index 932e87f32c..2ee46ea6b9 100644 --- a/src/model/fold.ml +++ b/src/model/fold.ml @@ -3,7 +3,6 @@ open Lang type item = | CompilationUnit of Compilation_unit.t | TypeDecl of TypeDecl.t - | Constructor of TypeDecl.t | Module of Module.t | Value of Value.t | Exception of Exception.t diff --git a/src/model/sidebar.ml b/src/model/sidebar.ml index 4780cb9ba1..f40308f738 100644 --- a/src/model/sidebar.ml +++ b/src/model/sidebar.ml @@ -77,10 +77,10 @@ module PageToc = struct | None -> None type index = Id.Page.t * title - type t = (Id.Page.t * content) list * index option - and content = Entry of title | Dir of t - let rec t_of_in_progress (dir : in_progress) = + type t = index option Odoc_utils.Tree.t + + let rec t_of_in_progress (dir : in_progress) : t = let children_order, index = match dir_index dir with | Some ({ children_order; _ }, index_id, index_title) -> @@ -103,12 +103,15 @@ module PageToc = struct let contents = let leafs = leafs dir - |> List.map (fun (id, payload) -> ((id :> Id.Page.t), Entry payload)) + |> List.map (fun (id, payload) -> + let id :> Id.Page.t = id in + (id, Tree.leaf (Some (id, payload)))) in let dirs = dirs dir |> List.map (fun (id, payload) -> - ((id :> Id.Page.t), Dir (t_of_in_progress payload))) + let id :> Id.Page.t = id in + (id, t_of_in_progress payload)) in leafs @ dirs in @@ -179,11 +182,13 @@ module PageToc = struct String.compare (Paths.Identifier.name x) (Paths.Identifier.name y)) unordered in - let contents = ordered @ unordered in - (contents, index) + let contents = ordered @ unordered |> List.map snd in + { Tree.entry = index; children = contents } let rec remove_common_root (v : t) = - match v with [ (_, Dir v) ], None -> remove_common_root v | _ -> v + match v with + | { Tree.children = [ v ]; entry = None } -> remove_common_root v + | _ -> v let of_list l = let dir = empty_t None in diff --git a/src/model/sidebar.mli b/src/model/sidebar.mli index 2746abd3ee..0ecc82b651 100644 --- a/src/model/sidebar.mli +++ b/src/model/sidebar.mli @@ -4,8 +4,8 @@ module PageToc : sig type title = Comment.link_content type index = Id.Page.t * title - type t = (Id.Page.t * content) list * index option - and content = Entry of title | Dir of t + + type t = index option Odoc_utils.Tree.t val of_list : (Id.LeafPage.t * title * Frontmatter.children_order option) list -> t diff --git a/src/odoc/indexing.ml b/src/odoc/indexing.ml index a9bfd59136..e59372e83d 100644 --- a/src/odoc/indexing.ml +++ b/src/odoc/indexing.ml @@ -84,7 +84,7 @@ let compile_to_marshall ~output sidebar files = (* (fun entry -> H.add final_index entry.Odoc_search.Entry.id entry) *) (* entries) *) (* () u *) - node + Some node in let page _p = None diff --git a/src/odoc/indexing.mli b/src/odoc/indexing.mli index 7c1f52fd91..a175bae401 100644 --- a/src/odoc/indexing.mli +++ b/src/odoc/indexing.mli @@ -4,7 +4,7 @@ val handle_file : Fpath.t -> unit:(Odoc_model.Lang.Compilation_unit.t -> 'a) -> page:(Odoc_model.Lang.Page.t -> 'a) -> - occ:(Odoc_index.Entry.t Odoc_index.Skeleton.node list -> 'a) -> + occ:(Odoc_index.Entry.t Odoc_utils.Tree.t list -> 'a) -> ('a, [> msg ]) result (** This function is exposed for custom indexers that uses [odoc] as a library to generate their search index *) diff --git a/src/search/index.ml b/src/search/index.ml index 0ced457f03..01e672d081 100644 --- a/src/search/index.ml +++ b/src/search/index.ml @@ -1 +1,4 @@ -type t = { sidebar : Odoc_model.Sidebar.t; index : Entry.t Skeleton.node list } +type t = { + sidebar : Odoc_model.Sidebar.t; + index : Entry.t Odoc_utils.Tree.t list; +} diff --git a/src/search/skeleton.ml b/src/search/skeleton.ml index 1d4a79adfd..555af0f0d6 100644 --- a/src/search/skeleton.ml +++ b/src/search/skeleton.ml @@ -1,11 +1,9 @@ open Odoc_model.Lang open Odoc_model.Paths -type 'a node = { entry : 'a; children : 'a node list } +open Odoc_utils module Entry = struct - type t = Entry.t - let of_comp_unit (u : Compilation_unit.t) = let has_expansion = true in let doc = match u.content with Pack _ -> [] | Module m -> m.doc in @@ -57,13 +55,32 @@ module Entry = struct let of_value (v : Value.t) = let kind = Entry.Value { value = v.value; type_ = v.type_ } in Entry.entry ~id:v.id ~doc:v.doc ~kind + + let of_class (cl : Class.t) = + let kind = Entry.Class { virtual_ = cl.virtual_; params = cl.params } in + Entry.entry ~id:cl.id ~doc:cl.doc ~kind + + let of_class_type (ct : ClassType.t) = + let kind = + Entry.Class_type { virtual_ = ct.virtual_; params = ct.params } + in + Entry.entry ~id:ct.id ~doc:ct.doc ~kind + + let _of_doc = [ "TODO" ] + + let of_method (m : Method.t) = + let kind = + Entry.Method + { virtual_ = m.virtual_; private_ = m.private_; type_ = m.type_ } + in + Entry.entry ~id:m.id ~doc:m.doc ~kind end let if_non_hidden id f = if Identifier.is_hidden (id :> Identifier.t) then [] else f () -let entry_of_item i f = - match Entry.entries_of_item i with [] -> [] | e :: _ -> f e +(* let entry_of_item i f = *) +(* match Entry.entries_of_item i with [] -> [] | e :: _ -> f e *) let rec unit (u : Compilation_unit.t) = let entry = Entry.of_comp_unit u in @@ -72,10 +89,10 @@ let rec unit (u : Compilation_unit.t) = | Pack _ -> [] | Module m -> signature (u.id :> Identifier.LabelParent.t) m in - { entry; children } + { Tree.entry; children } and signature id (s : Signature.t) = - List.concat_map (signature_item (id :> Identifier.LabelParent.t)) s.items + List.concat_map ~f:(signature_item (id :> Identifier.LabelParent.t)) s.items and signature_item id s_item = match s_item with @@ -86,7 +103,7 @@ and signature_item id s_item = | Open _ -> [] | Type (_, t_decl) -> type_decl t_decl | TypeSubstitution _ -> [] - | TypExt te -> type_extension te + | TypExt _te -> [] | Exception exc -> exception_ exc | Value v -> value v | Class (_, cl) -> class_ (cl.id :> Identifier.LabelParent.t) cl @@ -103,7 +120,7 @@ and module_ id m = | Alias (_, Some s_e) -> simple_expansion id s_e | ModuleType mte -> module_type_expr id mte in - [ { entry; children } ] + [ { Tree.entry; children } ] and module_type id mt = if_non_hidden mt.id @@ fun () -> @@ -113,64 +130,62 @@ and module_type id mt = | None -> [] | Some mt_expr -> module_type_expr id mt_expr in - [ { entry; children } ] - -and leaf id l = - let id :> Identifier.t = id in - let entry = - match Entry.entries_of_item l with - | [] -> - { - Entry.id; - doc = []; - kind = - Method { private_ = true; virtual_ = true; type_ = TypeExpr.Any }; - } - | a :: _ -> a - in - let children = [] in - { entry; children } + [ { Tree.entry; children } ] + +(* and leaf id l = *) +(* let id :> Identifier.t = id in *) +(* let entry = *) +(* match Entry.entries_of_item l with *) +(* | [] -> *) +(* { *) +(* Entry.id; *) +(* doc = []; *) +(* kind = *) +(* Method { private_ = true; virtual_ = true; type_ = TypeExpr.Any }; *) +(* } *) +(* | a :: _ -> a *) +(* in *) +(* let children = [] in *) +(* { Tree.entry; children } *) and type_decl td = if_non_hidden td.id @@ fun () -> let entry = Entry.of_type_decl td in - [ { entry; children = [] } ] + [ { Tree.entry; children = [] } ] -and type_extension _te = [ (* leaf te.id (Extension te) *) ] +and _type_extension _te = [ (* leaf te.id (Extension te) *) ] and exception_ exc = if_non_hidden exc.id @@ fun () -> let entry = Entry.of_exception exc in - [ { entry; children = [] } ] + [ { Tree.entry; children = [] } ] and value v = - if_non_hidden v.id @@ fun () -> (* [ leaf (v.id :> Identifier.t) (Value v) ] *) + if_non_hidden v.id @@ fun () -> + let entry = Entry.of_value v in + [ { Tree.entry; children = [] } ] and class_ id cl = if_non_hidden cl.id @@ fun () -> - entry_of_item (Class cl) @@ fun entry -> + let entry = Entry.of_class cl in let children = match cl.expansion with | None -> [] | Some cl_signature -> class_signature id cl_signature in - [ { entry; children } ] + [ { Tree.entry; children } ] and class_type id ct = - (* This check is important because [is_internal] does not work on children of - internal items. This means that if [Fold] did not make this check here, - it would be difficult to filter for internal items afterwards. This also - applies to the same check in functions bellow. *) if_non_hidden ct.id @@ fun () -> - entry_of_item (ClassType ct) @@ fun entry -> + let entry = Entry.of_class_type ct in let children = match ct.expansion with None -> [] | Some cs -> class_signature id cs in - [ { entry; children } ] + [ { Tree.entry; children } ] and include_ id inc = signature id inc.expansion.content -and docs id d = [ leaf (id :> Identifier.t) (Doc (id, d)) ] +and docs _id _d = (* TODO *) [] and simple_expansion id s_e = match s_e with @@ -193,11 +208,13 @@ and module_type_expr id mte = | TypeOf { t_expansion = None; _ } -> [] and class_signature id ct_expr = - List.concat_map (class_signature_item id) ct_expr.items + List.concat_map ~f:(class_signature_item id) ct_expr.items and class_signature_item id item = match item with - | Method m -> [ leaf (m.id :> Identifier.t) (Method m) ] + | Method m -> + let entry = Entry.of_method m in + [ { Tree.entry; children = [] } ] | InstanceVariable _ -> [] | Constraint _ -> [] | Inherit _ -> [] diff --git a/src/search/skeleton.mli b/src/search/skeleton.mli index 2dc09a5e72..93827d415b 100644 --- a/src/search/skeleton.mli +++ b/src/search/skeleton.mli @@ -1,9 +1,8 @@ (** Skeletons are a hierarchy organized map *) open Odoc_model.Lang +open Odoc_utils -type 'a node = { entry : 'a; children : 'a node list } +val from_unit : Compilation_unit.t -> Entry.t Tree.t -val from_unit : Compilation_unit.t -> Entry.t node option - -val from_page : Page.t -> Entry.t node option +val from_page : Page.t -> Entry.t Tree.t option diff --git a/src/utils/odoc_utils.ml b/src/utils/odoc_utils.ml index a574797f75..4623fc9035 100644 --- a/src/utils/odoc_utils.ml +++ b/src/utils/odoc_utils.ml @@ -104,3 +104,5 @@ module Fun = struct finally_no_exn (); raise work_exn end + +module Tree = Tree diff --git a/src/utils/tree.ml b/src/utils/tree.ml new file mode 100644 index 0000000000..bce0cd1653 --- /dev/null +++ b/src/utils/tree.ml @@ -0,0 +1,26 @@ +type 'a t = { entry : 'a; children : 'a forest } +and 'a forest = 'a t list + +let leaf entry = { entry; children = [] } + +let rec fold_t fun_ acc { entry; children } = + let acc = fun_ acc entry in + fold_f fun_ acc children + +and fold_f fun_ acc f = List.fold_left (fold_t fun_) acc f + +let rec map_t fun_ { entry; children } = + let entry = fun_ entry in + let children = map_f fun_ children in + { entry; children } + +and map_f fun_ f = List.map (map_t fun_) f + +let rec filter_map_t fun_ { entry; children } = + match fun_ entry with + | None -> None + | Some entry -> + let children = filter_map_f fun_ children in + Some { entry; children } + +and filter_map_f fun_ f = List.filter_map (filter_map_t fun_) f