diff --git a/src/document/generator.ml b/src/document/generator.ml index 81d9ece494..3ada068815 100644 --- a/src/document/generator.ml +++ b/src/document/generator.ml @@ -1810,7 +1810,7 @@ module Make (Syntax : SYNTAX) = struct Utils.filter_map (function | `Resolved (`Identifier id) -> - Some Url.(from_path @@ Path.from_identifier id) + Some (Url.from_path @@ Url.Path.from_identifier id) | _ -> None) t.search_assets in diff --git a/src/html/generator.ml b/src/html/generator.ml index 34c0e9fdd6..22cad5928d 100644 --- a/src/html/generator.ml +++ b/src/html/generator.ml @@ -35,7 +35,10 @@ let mk_anchor_link id = let mk_anchor config anchor = match anchor with | None -> ([], [], []) - | _ when Config.search_result config -> ([], [], []) + | _ when Config.search_result config -> + (* When displaying for a search result, anchor are not added as it would + make no sense to add them. *) + ([], [], []) | Some { Url.Anchor.anchor; _ } -> let link = mk_anchor_link anchor in let extra_attr = [ Html.a_id anchor ] in @@ -101,7 +104,10 @@ let rec internallink ~config ~emph_level ~resolve ?(a = []) | Resolved uri -> let href = Link.href ~config ~resolve uri in let content = inline_nolink ~emph_level content in - if Config.search_result config then Html.span ~a content + if Config.search_result config then + (* When displaying for a search result, links are displayed as regular + text. *) + Html.span ~a content else let a = Html.a_href href :: (a :> Html_types.a_attrib Html.attrib list) @@ -172,7 +178,10 @@ and inline_nolink ?(emph_level = 0) (l : Inline.t) : let heading ~config ~resolve (h : Heading.t) = let a, anchor = match h.label with - | Some _ when Config.search_result config -> ([], []) + | Some _ when Config.search_result config -> + (* When displaying for a search result, anchor are not added as it would + make no sense to add them. *) + ([], []) | Some id -> ([ Html.a_id id ], mk_anchor_link id) | None -> ([], []) in diff --git a/src/html_support_files/odoc.css b/src/html_support_files/odoc.css index f34aace166..28c0d3a739 100644 --- a/src/html_support_files/odoc.css +++ b/src/html_support_files/odoc.css @@ -364,7 +364,6 @@ a:hover { *:hover > a.anchor { visibility: visible; - z-index: -1; } a.anchor:before { @@ -554,14 +553,7 @@ div.odoc-spec,.odoc-include { margin-bottom: 2em; } -.odoc-include { - /* Otherwise it will appear above search results */ - z-index: -1; - position: relative; -} - -.spec.type .variant p, -.spec.type .record p { +.spec.type .variant p, .spec.type .record p { margin: 5px; } @@ -793,6 +785,7 @@ td.def-doc *:first-child { background: var(--main-background); width: 100%; padding-top: 1rem; + z-index: 1; } @@ -804,6 +797,8 @@ td.def-doc *:first-child { } .odoc-search:focus-within .search-inner { + /* Search inner is bigger than its parent, but the overflow needs to be + centered. */ left: 50%; transform: translateX(-50%); width: 110%; @@ -812,7 +807,7 @@ td.def-doc *:first-child { .odoc-search .search-bar { position: relative; z-index: 2; - font-size: 1; + font-size: 1em; transition: font-size 0.3s; } @@ -834,7 +829,6 @@ td.def-doc *:first-child { position: absolute; left: 0; right: 0; - z-index: 1; } .odoc-search .search-result-inner { @@ -849,12 +843,17 @@ td.def-doc *:first-child { } .search-bar { + /* inputs are of fixed size by default, even if you display:block them */ width: 100%; } .odoc-search .search-entry { color: var(--color); display: grid; + /* This constant of 59px was carefully chosen to accomodate every possible + "kind". We cannot ask CSS to compute it because not every kind will be + present in every search result list, and we do not want the size of the + column to change with different results. */ grid-template-columns: [kinds] 59px [titles] 1fr; flex-wrap: nowrap; flex-direction: row; diff --git a/src/model/fold.ml b/src/model/fold.ml index 33e62ed1e8..a63a2b0452 100644 --- a/src/model/fold.ml +++ b/src/model/fold.ml @@ -105,7 +105,9 @@ and module_type ~f acc mt = and simple_expansion ~f acc s_e = match s_e with | Signature sg -> signature ~f acc sg - | Functor (_, s_e) -> simple_expansion ~f acc s_e + | Functor (p, s_e) -> + let acc = functor_parameter ~f acc p in + simple_expansion ~f acc s_e and module_type_expr ~f acc mte = match mte with diff --git a/src/model/fold.mli b/src/model/fold.mli index 560f83c759..6f68d49fde 100644 --- a/src/model/fold.mli +++ b/src/model/fold.mli @@ -1,5 +1,7 @@ (** This module allows to fold over odoc values. It is notably used to construct - a search database of every relevant item. *) + a search database of every relevant item. It appear to be very generic but + in reality it is quite specialized to fold over searchable items, and not + every kind of odoc value you could fold over.*) open Lang @@ -22,6 +24,8 @@ type item = val unit : f:('a -> item -> 'a) -> 'a -> Compilation_unit.t -> 'a val page : f:('a -> item -> 'a) -> 'a -> Page.t -> 'a + + val signature : f:('a -> item -> 'a) -> 'a -> Signature.t -> 'a val signature_item : f:('a -> item -> 'a) -> 'a -> Signature.item -> 'a val docs : f:('a -> item -> 'a) -> 'a -> Comment.docs_or_stop -> 'a diff --git a/src/odoc/bin/main.ml b/src/odoc/bin/main.ml index 9e0a1f3f87..4ab31c019c 100644 --- a/src/odoc/bin/main.ml +++ b/src/odoc/bin/main.ml @@ -385,9 +385,9 @@ module Indexing = struct | Some file -> Fs.File.of_string file | None -> Fs.File.of_string "index.json" - let index directories dst warnings_options = + let index directories dst = let output = output_file ~dst in - Indexing.compile ~output ~warnings_options ~resolver:() ~parent:() + Indexing.compile ~output directories let cmd = @@ -401,7 +401,7 @@ module Indexing = struct in Term.( const handle_error - $ (const index $ odoc_file_directories $ dst $ warnings_options)) + $ (const index $ odoc_file_directories $ dst )) let info ~docs = let doc = diff --git a/src/odoc/compile.ml b/src/odoc/compile.ml index 9c0ce05bf9..11fd8bdd63 100644 --- a/src/odoc/compile.ml +++ b/src/odoc/compile.ml @@ -295,9 +295,9 @@ let compile ~resolver ~parent_cli_spec ~hidden ~children ~output parent resolver parent_cli_spec >>= fun parent_spec -> let search_assets : Paths.Reference.Asset.t list = List.map (fun a -> `Root (a, `TAsset)) search_assets - (* Assets references are considered as "simple" reference, no way to specify - the parent page of an asset. Therefore, seach assets need to be children - of a page ancestor. *) + (* Assets references are considered as "simple" reference, there is no way + to specify the parent page of an asset. Therefore, search assets need to + be children of a page ancestor. *) in let ext = Fs.File.get_ext input in if ext = ".mld" then diff --git a/src/odoc/indexing.ml b/src/odoc/indexing.ml index edd4045a2f..6c8a9079cd 100644 --- a/src/odoc/indexing.ml +++ b/src/odoc/indexing.ml @@ -26,7 +26,7 @@ let fold_dirs ~dirs ~unit ~page ~init = acc dir) (Ok init) -let compile ~resolver:_ ~parent:_ ~output ~warnings_options:_ dirs = +let compile ~output dirs = let output_channel = Fs.Directory.mkdir_p (Fs.File.dirname output); open_out_bin (Fs.File.to_string output) diff --git a/src/odoc/indexing.mli b/src/odoc/indexing.mli index 8713cc6dbb..1b3edde37b 100644 --- a/src/odoc/indexing.mli +++ b/src/odoc/indexing.mli @@ -9,9 +9,6 @@ val handle_file : to generate their search index *) val compile : - resolver:'a -> - parent:'b -> output:Fs.file -> - warnings_options:Odoc_model.Error.warnings_options -> Fs.directory list -> (unit, [> msg ]) result diff --git a/src/odoc/support_files.mli b/src/odoc/support_files.mli index 3f5ecace8c..f61a81b558 100644 --- a/src/odoc/support_files.mli +++ b/src/odoc/support_files.mli @@ -2,9 +2,9 @@ location. *) val write : ?without_theme:bool -> Fs.Directory.t -> unit -(** [write ?without_theme search_files output_dir] copies the support and search - files to the [output_dir]. If [without_theme] is [true] the theme will {e - not} be copied, the default value is [false]. *) +(** [write ?without_theme output_dir] copies the support files to the + [output_dir]. If [without_theme] is [true] the theme will {e not} be + copied, the default value is [false]. *) val print_filenames : ?without_theme:bool -> Fs.Directory.t -> unit (** Prints, to STDOUT, the names of the files that calling [Support_files.write] diff --git a/src/search/entry.ml b/src/search/entry.ml index 2003f524d5..0fd9e1c8f7 100644 --- a/src/search/entry.ml +++ b/src/search/entry.ml @@ -72,8 +72,6 @@ type t = { kind : kind; } -type with_html = { entry : t; html : [ `Code | `Div ] Tyxml.Html.elt list } - let entry ~id ~doc ~kind = let id = (id :> Odoc_model.Paths.Identifier.Any.t) in { id; kind; doc } diff --git a/src/search/entry.mli b/src/search/entry.mli index 53419fc649..52e9f9a470 100644 --- a/src/search/entry.mli +++ b/src/search/entry.mli @@ -61,8 +61,5 @@ type t = { kind : kind; } -type with_html = { entry : t; html : [ `Code | `Div ] Tyxml.Html.elt list } -(** You can use {!Generator.with_html} to get a value of this type. *) - val entries_of_item : Odoc_model.Paths.Identifier.Any.t -> Odoc_model.Fold.item -> t list diff --git a/src/search/generator.mli b/src/search/generator.mli deleted file mode 100644 index 3d9591625f..0000000000 --- a/src/search/generator.mli +++ /dev/null @@ -1,51 +0,0 @@ -open Odoc_model - -module Html = Tyxml_html - -val title_of_id : Paths.Identifier.t -> string * string -val html_of_doc : Comment.docs -> [> Html_types.div ] Tyxml_html.elt -val html_string_of_doc : Comment.docs -> string - -val html_of_entry : Entry.t -> [> `Code | `Div ] Tyxml_html.elt list - -val with_html : Entry.t -> Entry.with_html - -(** Right-hand sides *) - -val type_expr : ?needs_parentheses:bool -> Lang.TypeExpr.t -> string - -val constructor_rhs : Entry.constructor_entry -> string -val field_rhs : Entry.field_entry -> string - -val typedecl_rhs : Entry.type_decl_entry -> string option - -val value_rhs : Entry.value_entry -> string -val html_of_strings : - kind:string -> - prefix_name:string option -> - name:string option -> - rhs:string option -> - typedecl_params:string option -> - doc:string -> - [> `Code | `Div ] Tyxml_html.elt list - -val rhs_of_kind : Entry.kind -> string option - -(** Kinds *) - -val string_of_kind : Entry.kind -> string -(** Does not include the rhs. *) - -val kind_doc : string -val kind_typedecl : string -val kind_module : string -val kind_exception : string -val kind_class_type : string -val kind_class : string -val kind_method : string -val kind_extension_constructor : string -val kind_module_type : string -val kind_constructor : string -val kind_field : string -val kind_value : string -val kind_extension : string diff --git a/src/search/generator.ml b/src/search/html.ml similarity index 85% rename from src/search/generator.ml rename to src/search/html.ml index 026b31cb62..32ef5bcda6 100644 --- a/src/search/generator.ml +++ b/src/search/html.ml @@ -1,9 +1,23 @@ -module Html = Tyxml.Html +type html = [ `Code | `Div ] Tyxml.Html.elt open Odoc_model open Lang open Printf +let url id = + match + Odoc_document.Url.from_identifier ~stop_before:false + (id :> Odoc_model.Paths.Identifier.t) + with + | Ok url -> + let config = + Odoc_html.Config.v ~search_result:true ~semantic_uris:false + ~indent:false ~flat:false ~open_details:false ~as_json:false () + in + let url = Odoc_html.Link.href ~config ~resolve:(Base "") url in + url + | Error _ -> assert false (* TODO fix *) + let map_option f = function Some x -> Some (f x) | None -> None let type_from_path : Paths.Path.Type.t -> string = @@ -135,7 +149,7 @@ let typedecl_repr ~private_ (repr : TypeDecl.Representation.t) = name ^ constructor_rhs ~args ~res in let private_ = if private_ then "private " else "" in - "= " ^ private_ + " = " ^ private_ ^ match repr with | Extensible -> ".." @@ -213,21 +227,29 @@ let string_of_kind = let value_rhs (t : Entry.value_entry) = " : " ^ type_expr t.type_ -let html_of_strings ~kind ~prefix_name ~name ~rhs ~typedecl_params ~doc = +let of_strings ~kind ~prefix_name ~name ~rhs ~typedecl_params ~doc = let open Tyxml.Html in let kind = code ~a:[ a_class [ "entry-kind" ] ] [ txt kind ] - and prefix_name = - match prefix_name with - | Some prefix_name -> + and typedecl_params = + match typedecl_params with + | None -> [] + | Some p -> [ span - ~a:[ a_class [ "prefix-name" ] ] - [ - txt - ((match typedecl_params with None -> "" | Some p -> p ^ " ") - ^ prefix_name ^ "."); - ]; + ~a: + [ + a_class + [ + (* the parameter of the typedecl are highlighted as if part of main entry name. *) + "entry-name"; + ]; + ] + [ txt (p ^ " ") ]; ] + and prefix_name = + match prefix_name with + | Some prefix_name -> + [ span ~a:[ a_class [ "prefix-name" ] ] [ txt (prefix_name ^ ".") ] ] | None -> [] and name = match name with @@ -240,7 +262,9 @@ let html_of_strings ~kind ~prefix_name ~name ~rhs ~typedecl_params ~doc = in [ kind; - code ~a:[ a_class [ "entry-title" ] ] (prefix_name @ name @ rhs); + code + ~a:[ a_class [ "entry-title" ] ] + (typedecl_params @ prefix_name @ name @ rhs); div ~a:[ a_class [ "entry-comment" ] ] [ Unsafe.data doc ]; ] @@ -255,7 +279,7 @@ let rhs_of_kind (entry : Entry.kind) = | Doc _ -> None -let title_of_id id = +let names_of_id id = let fullname = Paths.Identifier.fullname id in let prefix_name, name = let rev_fullname = List.rev fullname in @@ -263,7 +287,7 @@ let title_of_id id = List.hd rev_fullname ) in (prefix_name, name) -let html_of_doc doc = +let of_doc doc = let config = Odoc_html.Config.v ~search_result:true ~semantic_uris:false ~indent:false ~flat:false ~open_details:false ~as_json:false () @@ -273,15 +297,13 @@ let html_of_doc doc = @@ Odoc_document.Comment.to_ir doc let html_string_of_doc doc = - doc |> html_of_doc |> Format.asprintf "%a" (Html.pp_elt ()) -let html_of_entry (entry : Entry.t) = + doc |> of_doc |> Format.asprintf "%a" (Tyxml.Html.pp_elt ()) +let of_entry (entry : Entry.t) = let ({ id; doc; kind } : Entry.t) = entry in let rhs = rhs_of_kind kind in - let prefix_name, name = title_of_id id in + let prefix_name, name = names_of_id id in let prefix_name = Some prefix_name and name = Some name in let doc = html_string_of_doc doc in let kind = string_of_kind kind in let typedecl_params = typedecl_params_of_entry entry in - html_of_strings ~kind ~prefix_name ~name ~rhs ~doc ~typedecl_params - -let with_html entry : Entry.with_html = { entry; html = html_of_entry entry } + of_strings ~kind ~prefix_name ~name ~rhs ~doc ~typedecl_params diff --git a/src/search/html.mli b/src/search/html.mli new file mode 100644 index 0000000000..d14315de1a --- /dev/null +++ b/src/search/html.mli @@ -0,0 +1,66 @@ +open Odoc_model + +type html = [ `Code | `Div ] Tyxml.Html.elt + +(* todo use a shorted alias for this ugly type *) +val of_entry : Entry.t -> html list + +val url : Odoc_model.Paths.Identifier.Any.t -> string + +(** The below is intended for search engine that do not use the Json output but + Odoc as a library. Most search engine will use their own representation + instead of {!Entry.t}, and may not want to store the whole HTML in their + database. The following functions help rebuild the HTML from any + represention. *) + +val of_strings : + kind:string -> + prefix_name:string option -> + name:string option -> + rhs:string option -> + typedecl_params:string option -> + doc:string -> + html list +(** [of_string] generates the html of an entry using strings associated to + the relevant parts of the entry. If the strings have the correct values, + it will return the same as {!of_entry} *) + +val names_of_id : Paths.Identifier.t -> string * string +(** [names_of_id id] is [("X.Y", "foo")] if [id] corresponds to [X.Y.foo]. + The tuple is intended to be given respectively to the [prefix_name] and + [name] arguments of {!html_of_strings}. *) + +val of_doc : Comment.docs -> html +(** [of_doc d] returns the HTML associated of the documentation comment [d], + generated correctly for search (no links or anchors). *) + +val html_string_of_doc : Comment.docs -> string +(** [html_string_of_doc d] is the same as {!of_doc} converted to a + string. *) + +(** Right-hand sides *) + +val rhs_of_kind : Entry.kind -> string option +(** [rhs_of_kind k] is the right-hand-side string associated with the metadata + included in the kind [k]. If [k] is [Value _], it may be [": int"] *) + +val typedecl_params_of_entry : Entry.t -> string option +(** [typedecl_params_of_entry e] is [Some "'a"] if the entry correspond to + ['a t]. If the entry is not a typedecl, or if the typedecl does not have a + type parameter, then it returns [None]. *) + +(** Kinds *) + +val kind_doc : string +val kind_typedecl : string +val kind_module : string +val kind_exception : string +val kind_class_type : string +val kind_class : string +val kind_method : string +val kind_extension_constructor : string +val kind_module_type : string +val kind_constructor : string +val kind_field : string +val kind_value : string +val kind_extension : string diff --git a/src/search/json_display.ml b/src/search/json_display.ml index 8a2f2b1bb9..871f19988e 100644 --- a/src/search/json_display.ml +++ b/src/search/json_display.ml @@ -1,9 +1,7 @@ -module Html = Tyxml.Html -let of_entry ({ entry = { id; doc = _; kind = _ }; html } : Entry.with_html) : +let of_entry { Entry.id; doc = _; kind = _ } h : Odoc_html.Json.json = - let url = Render.url id in - - let html = Html.div ~a:[ Html.a_class [ "search-entry" ] ] html in + let url = Html.url id in + let html = Tyxml.Html.(div ~a:[ a_class [ "search-entry" ] ] h) in let html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) html in `Object [ ("url", `String url); ("html", `String html) ] diff --git a/src/search/json_display.mli b/src/search/json_display.mli index e0e0df74c7..57c5d6e4a8 100644 --- a/src/search/json_display.mli +++ b/src/search/json_display.mli @@ -1 +1,4 @@ -val of_entry : Entry.with_html -> Odoc_html.Json.json +val of_entry : + Entry.t -> + [< Html_types.div_content_fun ] Tyxml.Html.elt list -> + Odoc_html.Json.json diff --git a/src/search/json_search.ml b/src/search/json_search.ml index 68d94f9416..2c8591abcb 100644 --- a/src/search/json_search.ml +++ b/src/search/json_search.ml @@ -84,12 +84,10 @@ let of_doc (doc : Odoc_model.Comment.docs) = let txt = Render.text_of_doc doc in `String txt -let of_entry - ({ entry = { id; doc; kind }; html = _ } as entry : Entry.with_html) : - Odoc_html.Json.json = +let of_entry ({ Entry.id; doc; kind } as entry) html : Odoc_html.Json.json = let j_id = of_id id in let doc = of_doc doc in - let display = Json_display.of_entry entry in + let display = Json_display.of_entry entry html in let kind = let return kind arr = `Object (("kind", `String kind) :: arr) in match kind with @@ -176,8 +174,8 @@ let output_json ppf first entries = Format.fprintf ppf "%s\n" str in List.fold_left - (fun first entry -> - let json = of_entry entry in + (fun first (entry, html) -> + let json = of_entry entry html in if not first then Format.fprintf ppf ","; output_json json; false) @@ -186,7 +184,9 @@ let output_json ppf first entries = let unit ppf u = let f (first, id) i = let entries = Entry.entries_of_item id i in - let entries = List.map Generator.with_html entries in + let entries = + List.map (fun entry -> (entry, Html.of_entry entry)) entries + in let id = match i with | CompilationUnit u -> (u.id :> Odoc_model.Paths.Identifier.t) @@ -218,7 +218,9 @@ let page ppf (page : Odoc_model.Lang.Page.t) = let entries = Entry.entries_of_item (page.name :> Odoc_model.Paths.Identifier.t) i in - let entries = List.map Generator.with_html entries in + let entries = + List.map (fun entry -> (entry, Html.of_entry entry)) entries + in output_json ppf first entries in let _first = Odoc_model.Fold.page ~f true page in diff --git a/src/search/render.ml b/src/search/render.ml index c46484c08f..3f286a69f6 100644 --- a/src/search/render.ml +++ b/src/search/render.ml @@ -1,4 +1,3 @@ -type html = Html_types.div Tyxml.Html.elt module Of_document = struct (** Get plain text doc-comment from a doc comment *) @@ -96,24 +95,7 @@ let text_of_type te = let text_of_doc doc = Of_comments.string_of_doc doc -let config = - Odoc_html.Config.v ~search_result:true ~semantic_uris:false ~indent:false - ~flat:false ~open_details:false ~as_json:false () - -let html_of_doc doc = - Tyxml.Html.div ~a:[] - @@ Odoc_html.Generator.doc ~config ~xref_base_uri:"" - @@ Odoc_document.Comment.to_ir doc - -let url id = - match - Odoc_document.Url.from_identifier ~stop_before:false - (id :> Odoc_model.Paths.Identifier.t) - with - | Ok url -> - let url = Odoc_html.Link.href ~config ~resolve:(Base "") url in - url - | Error _ -> assert false + let text_of_record fields = let te_text = Odoc_document.ML.record fields in diff --git a/src/search/render.mli b/src/search/render.mli index 7c1a3fbba6..b5e85edd69 100644 --- a/src/search/render.mli +++ b/src/search/render.mli @@ -1,10 +1,8 @@ -type html = Html_types.div Tyxml.Html.elt val text_of_type : Odoc_model.Lang.TypeExpr.t -> string -val html_of_doc : Odoc_model.Comment.docs -> html val text_of_doc : Odoc_model.Comment.docs -> string val text_of_record : Odoc_model.Lang.TypeDecl.Field.t list -> string -val url : Odoc_model.Paths.Identifier.Any.t -> string +