diff --git a/cli/search.ml b/cli/search.ml index 820b3181..f306d069 100644 --- a/cli/search.ml +++ b/cli/search.ml @@ -17,6 +17,8 @@ let string_of_kind = | Constructor _ -> "cons" | Field _ -> "field" | Val _ -> "val" + | Page -> "page" + | Impl -> "source" let print_result ~print_cost ~print_docstring ~no_rhs (elt : Db.Entry.t) = let cost = if print_cost then string_of_int elt.cost ^ " " else "" in diff --git a/db/dune b/db/dune index 2f917f09..e3cb6f42 100644 --- a/db/dune +++ b/db/dune @@ -1,2 +1,3 @@ (library - (name db)) + (name db) + (libraries fmt)) diff --git a/db/entry.ml b/db/entry.ml index 17c9c1c9..1e9e7e0d 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -6,7 +6,9 @@ let non_empty_string s = module Kind = struct type t = - | Doc + | Doc (** Standalone doc comment *) + | Page (** Mld page *) + | Impl (** Source page *) | Module | Module_type | Class @@ -26,7 +28,7 @@ module Kind = struct match t with | Val typ | Extension_constructor typ | Exception typ | Constructor typ | Field typ -> Some typ - | Doc | Module | Module_type | Class | Class_type | Method | Type_decl _ + | Doc | Page | Impl | Module | Module_type | Class | Class_type | Method | Type_decl _ | Type_extension -> None end @@ -54,6 +56,17 @@ type t = ; pkg : Package.t } +let pp fmt { name; rhs; url; kind; cost; doc_html; pkg } = + Format.fprintf + fmt + "{ name = %s ; rhs = %a ; url = %s ; kind = . ; cost = %d ; doc_html = %s ; pkg = . }\n" + name + (Fmt.option Fmt.string) + rhs + url + cost + doc_html + let string_compare_shorter a b = match Int.compare (String.length a) (String.length b) with | 0 -> String.compare a b diff --git a/db/entry.mli b/db/entry.mli index 4cc1904e..a88319b0 100644 --- a/db/entry.mli +++ b/db/entry.mli @@ -1,6 +1,8 @@ module Kind : sig type t = - | Doc + | Doc (** Standalone doc comment *) + | Page (** Mld page *) + | Impl (** Source page *) | Module | Module_type | Class @@ -38,6 +40,8 @@ type t = ; pkg : Package.t } +val pp : t Fmt.t + val v : name:string -> kind:Kind.t diff --git a/dune-project b/dune-project index 6b85aa6f..d5df3c2b 100644 --- a/dune-project +++ b/dune-project @@ -25,7 +25,7 @@ (synopsis "Search engine for OCaml documentation") (depends (ocaml (>= 4.0.8)) - (odoc (>= 2.4.0)) + (odoc (>= 3.0.0)) (base64 (>= 3.5.1)) (bigstringaf (>= 0.9.1)) (js_of_ocaml (>= 5.6.0)) diff --git a/index/index.ml b/index/index.ml index 10c017b6..28f1a327 100644 --- a/index/index.ml +++ b/index/index.ml @@ -1,19 +1,32 @@ +let handle_file register file = + let ( >>= ) = Result.bind in + let open Odoc_odoc in + let open Odoc_index in + match Fpath.get_ext file with + | ".odoc-index" -> Odoc_file.load_index file >>= fun index -> Ok (register index) + | ".odocl" -> + Odoc_file.load file + >>= fun unit' -> + (match unit' with + | { Odoc_file.content = Unit_content unit'; _ } when unit'.hidden -> + Error (`Msg "Hidden units are ignored when generating an index") + | { content = Unit_content u; _ } -> Ok (register [ Skeleton.from_unit u ]) + | { content = Page_content p; _ } -> Ok (register [ Skeleton.from_page p ]) + | _ -> + Error (`Msg "Only pages and unit are allowed as input when generating an index")) + | _ -> + Error + (`Msg "Only .odocl and .odoc-index are allowed as input when generating an index") + let index_file register filename = match Fpath.of_string filename with | Error (`Msg msg) -> Format.printf "FILE ERROR %s: %s@." filename msg | Ok file -> let open Odoc_model in - let page p = - let id = p.Lang.Page.name in - Fold.page ~f:(register (id :> Paths.Identifier.t)) () p - in - let unit u = - let id = u.Lang.Compilation_unit.id in - Fold.unit ~f:(register (id :> Paths.Identifier.t)) () u - in - (match Odoc_odoc.Indexing.handle_file ~page ~unit file with + (match handle_file register file with | Ok result -> result - | Error (`Msg msg) -> Format.printf "Odoc warning or error %s: %s@." filename msg) + | Error (`Msg msg) -> + Format.printf "Odoc warning or error %a: %s@." Fpath.pp file msg) let main files @@ -29,17 +42,18 @@ let main let module Storage = (val Db_store.storage_module db_format) in let db = Db_writer.make () in let no_pkg = Db.Entry.Package.v ~name:"" ~version:"" in - let register ~pkg ~favourite id () item = + let register ~pkg ~favourite = List.iter - (Load_doc.register_entry - ~db - ~index_docstring - ~index_name - ~type_search - ~favourite - ~favoured_prefixes - ~pkg) - (Odoc_search.Entry.entries_of_item id item) + @@ Odoc_utils.Tree.iter + ~f: + (Load_doc.register_entry + ~db + ~index_docstring + ~index_name + ~type_search + ~favourite + ~favoured_prefixes + ~pkg) in let files = match file_list with @@ -109,7 +123,7 @@ let odoc_favourite_file = Arg.(value & opt_all file [] & info [ "favoured" ] ~doc) let odoc_files = - let doc = "Path to a .odocl file" in + let doc = "Path to a .odocl file or a .odoc-index file" in Arg.(value & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) let term = diff --git a/index/load_doc.ml b/index/load_doc.ml index 3aa96025..1a0b9705 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -99,7 +99,7 @@ let searchable_type_of_constructor args res = let searchable_type_of_record parent_type type_ = Odoc_model.Lang.TypeExpr.Arrow (None, parent_type, type_) -let convert_kind ~db (Odoc_search.Entry.{ kind; _ } as entry) = +let convert_kind ~db (Odoc_index.Entry.{ kind; _ } as entry) = match kind with | TypeDecl _ -> Entry.Kind.Type_decl (Odoc_search.Html.typedecl_params_of_entry entry) | Value { value = _; type_ } -> @@ -121,13 +121,16 @@ let convert_kind ~db (Odoc_search.Entry.{ kind; _ } as entry) = let typ = searchable_type_of_record parent_type type_ in let typ = Db_writer.type_of_odoc ~db typ in Entry.Kind.Field typ - | Doc _ -> Doc + | Doc -> Doc + | Dir -> Doc + | Page _ -> Doc | Class_type _ -> Class_type | Method _ -> Method | Class _ -> Class | TypeExtension _ -> Type_extension - | Module -> Entry.Kind.Module - | ModuleType -> Module_type + | Module _ -> Entry.Kind.Module + | ModuleType _ -> Module_type + | Impl -> Doc let register_type_expr ~db elt typ = let type_polarities = Db.Type_polarity.of_typ ~any_is_poly:true typ in @@ -142,7 +145,7 @@ let register_kind ~db elt = let rec categorize id = let open Odoc_model.Paths in match id.Identifier.iv with - | `CoreType _ | `CoreException _ | `Root _ | `Page _ | `LeafPage _ -> `definition + | `Root _ | `Page _ | `LeafPage _ -> `definition | `ModuleType _ -> `declaration | `Parameter _ -> `ignore (* redundant with indexed signature *) | ( `InstanceVariable _ | `Method _ | `Field _ | `Result _ | `Label _ | `Type _ @@ -150,11 +153,11 @@ let rec categorize id = | `ExtensionDecl _ | `Module _ ) as x -> let parent = Identifier.label_parent { id with iv = x } in categorize (parent :> Identifier.Any.t) - | `AssetFile _ | `SourceDir _ | `SourceLocationMod _ | `SourceLocation _ | `SourcePage _ + | `AssetFile _ | `SourceLocationMod _ | `SourceLocation _ | `SourcePage _ | `SourceLocationInternal _ -> `ignore (* unclear what to do with those *) -let categorize Odoc_search.Entry.{ id; _ } = +let categorize Odoc_index.Entry.{ id; _ } = match id.iv with | `ModuleType (parent, _) -> (* A module type itself is not *from* a module type, but it might be if one @@ -171,7 +174,7 @@ let register_entry ~favoured_prefixes ~pkg ~cat - (Odoc_search.Entry.{ id; doc; kind } as entry) + (Odoc_index.Entry.{ id; doc; kind } as entry) = let module Sherlodoc_entry = Entry in let open Odoc_search in @@ -185,7 +188,7 @@ let register_entry let rhs = Html.rhs_of_kind kind in let kind = convert_kind ~db entry in let cost = cost ~name ~kind ~doc_html ~rhs ~cat ~favourite ~favoured_prefixes in - let url = Result.get_ok (Html.url id) in + let url = Html.url entry in let elt = Sherlodoc_entry.v ~name ~kind ~rhs ~doc_html ~cost ~url ~pkg () in if index_docstring then register_doc ~db elt doc_txt ; if index_name && kind <> Doc then register_full_name ~db elt ; @@ -199,15 +202,15 @@ let register_entry ~favourite ~favoured_prefixes ~pkg - (Odoc_search.Entry.{ id; kind; _ } as entry) + (Odoc_index.Entry.{ id; kind; _ } as entry) = let cat = categorize entry in let is_pure_documentation = match kind with - | Doc _ -> true + | Doc | Page _ | Dir | Impl -> true | _ -> false in - if is_pure_documentation || cat = `ignore || Odoc_model.Paths.Identifier.is_internal id + if is_pure_documentation || cat = `ignore || Odoc_model.Paths.Identifier.is_hidden id then () else register_entry diff --git a/index/load_doc.mli b/index/load_doc.mli index 4012b9bf..a2a11126 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -6,7 +6,7 @@ val register_entry -> favourite:bool -> favoured_prefixes:string list -> pkg:Db.Entry.Package.t - -> Odoc_search.Entry.t + -> Odoc_index.Entry.t -> unit (** [register_entry ~db ~index_name ~type_search ~index_docstring e] register the entry [e] in [db]. *) diff --git a/index/typename.ml b/index/typename.ml index 3f052927..5d3af2b3 100644 --- a/index/typename.ml +++ b/index/typename.ml @@ -5,7 +5,6 @@ module ModuleName = Odoc_model.Names.ModuleName let rec show_ident_long h (r : Identifier.t_pv Identifier.id) = match r.iv with - | `CoreType n -> Format.fprintf h "Stdlib.%s" (TypeName.to_string n) | `Type (md, n) -> Format.fprintf h "%a.%s" show_signature md (TypeName.to_string n) | _ -> Format.fprintf h "%S" (r |> Identifier.fullname |> String.concat ".") @@ -19,13 +18,23 @@ and show_signature h sig_ = | `ModuleType (_, p) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) -let show_type_name_verbose h : Path.Type.t -> _ = function +let rec show_type_name_verbose h : Path.Type.t -> _ = function | `Resolved t -> - Format.fprintf h "%a" show_ident_long Path.Resolved.(identifier (t :> t)) + (match Path.Resolved.(identifier (t :> t)) with + | Some i -> Format.fprintf h "%a" show_ident_long i + | None -> + (match t with + | `CoreType n -> Format.fprintf h "%s" (Odoc_model.Names.TypeName.to_string n) + | _ -> Format.fprintf h "%s" "Core type")) | `Identifier (path, _hidden) -> let name = String.concat "." @@ Identifier.fullname path in Format.fprintf h "%s" name - | `Dot (mdl, x) -> - Format.fprintf h "%s.%s" (Odoc_document.Url.render_path (mdl :> Path.t)) x + | `DotT (mdl, x) -> + Format.fprintf + h + "%s.%s" + (Odoc_document.Url.render_path (mdl :> Path.t)) + (Odoc_model.Names.TypeName.to_string x) + | `SubstitutedT x -> show_type_name_verbose h x let to_string t = Format.asprintf "%a" show_type_name_verbose t diff --git a/jsoo/main.ml b/jsoo/main.ml index d14fb229..1f7315ea 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -81,6 +81,8 @@ let string_of_kind = let open Odoc_html_frontend in function | Db.Entry.Kind.Doc -> kind_doc + | Page -> kind_doc + | Impl -> kind_impl | Type_decl _ -> kind_typedecl | Module -> kind_module | Exception _ -> kind_exception diff --git a/jsoo/odoc_html_frontend.ml b/jsoo/odoc_html_frontend.ml index c24c6ba2..9496d0d2 100644 --- a/jsoo/odoc_html_frontend.ml +++ b/jsoo/odoc_html_frontend.ml @@ -49,3 +49,4 @@ let kind_constructor = "cons" let kind_field = "field" let kind_value = "val" let kind_extension = "ext" +let kind_impl = "source" diff --git a/sherlodoc.opam b/sherlodoc.opam index c3b67571..46be9538 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -10,7 +10,7 @@ bug-reports: "https://github.com/art-w/sherlodoc/issues" depends: [ "dune" {>= "3.5"} "ocaml" {>= "4.0.8"} - "odoc" {>= "2.4.0"} + "odoc" {>= "3.0.0"} "base64" {>= "3.5.1"} "bigstringaf" {>= "0.9.1"} "js_of_ocaml" {>= "5.6.0"} diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index f7cea656..011a36a9 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -262,12 +262,12 @@ Partial name search: 175 val Base.String.uppercase : t -> t 176 type Base.String.Caseless.t = t 176 val Base.String.capitalize : t -> t - 177 mod Base.StringLabels 177 mod Caml.StringLabels 177 val Base.String.append : t -> t -> t 177 val Base.Exn.to_string_mach : t -> string 177 val Base.Info.to_string_hum : t -> string 177 val Base.Sign.to_string_hum : t -> string + 178 val Base.Info.to_string_mach : t -> string $ sherlodoc search --print-cost "tring" 177 type Base.string = String.t 182 type Base.String.t = string diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 93d2faf3..c5e31762 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -3,9 +3,10 @@ $ odoc compile -I . page.mld $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc + $ odoc compile-index -o index.odoc-index --root ./ $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal - $ sherlodoc index $(find . -name '*.odocl') + $ sherlodoc index index.odoc-index $ sherlodoc search "unique_name" val Main.unique_name : foo $ sherlodoc search "multiple_hit" @@ -59,6 +60,8 @@ $ sherlodoc search "modtype" sig Main.Modtype val Main.Modtype.v_modtype : foo + $ sherlodoc search "extensible" + type Main.extensible_type = .. $ sherlodoc search "S" mod Main.S_to_S1 sig Main.S @@ -67,7 +70,6 @@ mod Main.List mod Main.Nest type 'a Main.list - type Main.MyExtension cons Main.MyExtension : moo -> extensible_type val Main.consume : moo -> unit val Main.Map.to_list : foo diff --git a/test/cram/multi_package.t b/test/cram/multi_package.t index e0dd47ce..884961a9 100644 --- a/test/cram/multi_package.t +++ b/test/cram/multi_package.t @@ -264,12 +264,12 @@ Partial name search: 175 val Base.String.uppercase : t -> t 176 type Base.String.Caseless.t = t 176 val Base.String.capitalize : t -> t - 177 mod Base.StringLabels 177 mod Caml.StringLabels 177 val Base.String.append : t -> t -> t 177 val Base.Exn.to_string_mach : t -> string 177 val Base.Info.to_string_hum : t -> string 177 val Base.Sign.to_string_hum : t -> string + 178 val Base.Info.to_string_mach : t -> string $ sherlodoc search --print-cost "base strin" 162 type Base.string = String.t 174 type Base.Export.string = String.t @@ -289,13 +289,13 @@ Partial name search: 190 val Base.String.uppercase : t -> t 191 type Base.String.Caseless.t = t 191 val Base.String.capitalize : t -> t - 192 mod Base.StringLabels 192 val Base.String.append : t -> t -> t 192 val Base.Exn.to_string_mach : t -> string 192 val Base.Info.to_string_hum : t -> string 192 val Base.Sign.to_string_hum : t -> string 193 val Base.Error.to_string_hum : t -> string 193 val Base.Info.to_string_mach : t -> string + 194 val Base.Error.to_string_mach : t -> string $ sherlodoc search --print-cost "tring" 177 type Base.string = String.t @@ -348,5 +348,5 @@ Partial name search: 212 val Base.String.ascending : t -> t -> int 212 val Base.String.split_lines : t -> t list 212 val Base.Sys.max_string_length : int - 214 val Base.String.common_prefix : t list -> t + 214 val Base.String.common_suffix : t list -> t diff --git a/test/cram/prefix_favouritism.t b/test/cram/prefix_favouritism.t index f9db8ed7..1b98e182 100644 --- a/test/cram/prefix_favouritism.t +++ b/test/cram/prefix_favouritism.t @@ -25,9 +25,9 @@ 165 val Base.List.ignore_m : 'a t -> unit t 166 val Base.List.drop : 'a t -> int -> 'a t 166 val Base.List.take : 'a t -> int -> 'a t - 175 mod Base.ListLabels 175 mod Caml.ListLabels 394 mod Base + 397 type Base.Nothing.t = $ sherlodoc index --favoured-prefixes=Base $ODOCLS > /dev/null $ sherlodoc search --print-cost "list" 81 type 'a Base.list = 'a List.t @@ -50,11 +50,11 @@ 115 val Base.List.ignore_m : 'a t -> unit t 116 val Base.List.drop : 'a t -> int -> 'a t 116 val Base.List.take : 'a t -> int -> 'a t - 125 mod Base.ListLabels 344 mod Base 347 type Base.Nothing.t = 362 val Base.String.append : t -> t -> t 364 val Base.Int.ascending : t -> t -> int + 365 val Base.Bool.ascending : t -> t -> int $ sherlodoc index --favoured-prefixes=Caml $ODOCLS > /dev/null $ sherlodoc search --print-cost "list" 104 mod Caml.List @@ -80,8 +80,8 @@ 165 val Base.List.ignore_m : 'a t -> unit t 166 val Base.List.drop : 'a t -> int -> 'a t 166 val Base.List.take : 'a t -> int -> 'a t - 175 mod Base.ListLabels 394 mod Base + 397 type Base.Nothing.t = $ sherlodoc index --favoured-prefixes=Base,Caml $ODOCLS > /dev/null $ sherlodoc search --print-cost "list" 81 type 'a Base.list = 'a List.t @@ -105,10 +105,10 @@ 115 val Base.List.ignore_m : 'a t -> unit t 116 val Base.List.drop : 'a t -> int -> 'a t 116 val Base.List.take : 'a t -> int -> 'a t - 125 mod Base.ListLabels 125 mod Caml.ListLabels 344 mod Base 347 type Base.Nothing.t = + 362 val Base.String.append : t -> t -> t $ sherlodoc index $ODOCLS --favoured-prefixes "" > /dev/null $ sherlodoc search --print-cost "list" 131 type 'a Base.list = 'a List.t @@ -133,8 +133,8 @@ 165 val Base.List.ignore_m : 'a t -> unit t 166 val Base.List.drop : 'a t -> int -> 'a t 166 val Base.List.take : 'a t -> int -> 'a t - 175 mod Base.ListLabels 175 mod Caml.ListLabels 394 mod Base + 397 type Base.Nothing.t = Partial name search: