From 58ad2d43c548b9e50017a9285a3ca80deec651c8 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 22 Oct 2022 16:48:48 +0200 Subject: [PATCH 001/285] prototype --- .ocamlformat | 17 ++++ db/db.ml | 127 ++++++++++++++++++++++++ db/dune | 3 + db/storage.ml | 43 ++++++++ db/trie.ml | 85 ++++++++++++++++ db/types.ml | 73 ++++++++++++++ dune-project | 21 ++++ index/cache.ml | 24 +++++ index/dune | 12 +++ index/files.ml | 57 +++++++++++ index/index.ml | 33 +++++++ index/load_doc.ml | 204 ++++++++++++++++++++++++++++++++++++++ index/pretty.ml | 223 ++++++++++++++++++++++++++++++++++++++++++ query/dune | 9 ++ query/lexer.mll | 15 +++ query/parser.mly | 50 ++++++++++ query/query.ml | 115 ++++++++++++++++++++++ query/query_ast.ml | 53 ++++++++++ query/query_parser.ml | 32 ++++++ query/succ.ml | 133 +++++++++++++++++++++++++ sherlodoc.opam | 35 +++++++ static/style.css | 163 ++++++++++++++++++++++++++++++ www/dune | 3 + www/ui.ml | 133 +++++++++++++++++++++++++ www/www.ml | 80 +++++++++++++++ 25 files changed, 1743 insertions(+) create mode 100644 .ocamlformat create mode 100644 db/db.ml create mode 100644 db/dune create mode 100644 db/storage.ml create mode 100644 db/trie.ml create mode 100644 db/types.ml create mode 100644 dune-project create mode 100644 index/cache.ml create mode 100644 index/dune create mode 100644 index/files.ml create mode 100644 index/index.ml create mode 100644 index/load_doc.ml create mode 100644 index/pretty.ml create mode 100644 query/dune create mode 100644 query/lexer.mll create mode 100644 query/parser.mly create mode 100644 query/query.ml create mode 100644 query/query_ast.ml create mode 100644 query/query_parser.ml create mode 100644 query/succ.ml create mode 100644 sherlodoc.opam create mode 100644 static/style.css create mode 100644 www/dune create mode 100644 www/ui.ml create mode 100644 www/www.ml diff --git a/.ocamlformat b/.ocamlformat new file mode 100644 index 0000000000..49b1202627 --- /dev/null +++ b/.ocamlformat @@ -0,0 +1,17 @@ +version = 0.24.1 +let-binding-spacing = compact +sequence-style = separator +doc-comments = after-when-possible +exp-grouping = preserve +break-cases = toplevel +break-separators = before +cases-exp-indent = 4 +cases-matching-exp-indent = normal +if-then-else = keyword-first +parens-tuple = multi-line-only +type-decl = sparse +field-space = loose +space-around-arrays = true +space-around-lists = true +space-around-records = true +dock-collection-brackets = false diff --git a/db/db.ml b/db/db.ml new file mode 100644 index 0000000000..edc4593d2c --- /dev/null +++ b/db/db.ml @@ -0,0 +1,127 @@ +module Types = Types +module Storage = Storage +include Types + +let load_counter = ref 0 +let list_of_string s = List.init (String.length s) (String.get s) +let db = ref (T.empty ()) +let db_names = ref (Tchar.empty ()) + +module Hset2 = Hashtbl.Make (struct + type t = Elt_set.t * Elt_set.t + + let hash = Hashtbl.hash + let equal (a, b) (a', b') = a == a' && b == b' +end) + +module Hocc2 = Hashtbl.Make (struct + type t = Elt_set.t Occ.t * Elt_set.t Occ.t + + let hash = Hashtbl.hash + let equal (a, b) (a', b') = a == a' && b == b' +end) + +let elt_set_union ~hs a b = + try Hset2.find hs (a, b) + with Not_found -> + let r = Elt_set.union a b in + Hset2.add hs (a, b) r ; + Hset2.add hs (b, a) r ; + r + +let occ_merge ~hs a b = + if a == b + then a + else + Occ.merge + (fun _ ox oy -> + match ox, oy with + | Some x, Some y -> Some (elt_set_union ~hs x y) + | opt, None | None, opt -> opt) + a b + +let occ_merge ~ho ~hs a b = + try Hocc2.find ho (a, b) + with Not_found -> + let r = occ_merge ~hs a b in + Hocc2.add ho (a, b) r ; + Hocc2.add ho (b, a) r ; + r + +let export h = + load_counter := 0 ; + let t = { Storage.db = !db; db_names = !db_names } in + let ho = Hocc2.create 16 in + let hs = Hset2.create 16 in + let (_ : Elt_set.t Occ.t) = T.summarize (occ_merge ~ho ~hs) Occ.empty !db in + let (_ : Elt_set.t) = + Tchar.summarize (elt_set_union ~hs) Elt_set.empty !db_names + in + Storage.save ~db:h t ; + db := T.empty () ; + db_names := Tchar.empty () + +module Hset = Hashtbl.Make (struct + type t = Elt_set.t option + + let hash = Hashtbl.hash + let equal x y = Option.equal (fun x y -> x == y) x y +end) + +module Hocc = Hashtbl.Make (struct + type t = Elt_set.t Occ.t option + + let hash = Hashtbl.hash + let equal x y = Option.equal (fun x y -> x == y) x y +end) + +let set_add elt = function + | None -> Elt_set.singleton elt + | Some s -> Elt_set.add elt s + +let set_add ~hs elt opt = + try Hset.find hs opt + with Not_found -> + let r = set_add elt opt in + Hset.add hs opt r ; + r + +let candidates_add ~hs elt ~count = function + | None -> Occ.singleton count (set_add ~hs elt None) + | Some m -> + let s = Occ.find_opt count m in + let s = set_add ~hs elt s in + Occ.add count s m + +let candidates_add ~ho ~hs elt ~count opt = + try Hocc.find ho opt + with Not_found -> + let r = candidates_add ~hs ~count elt opt in + Hocc.add ho opt r ; + r + +let store ~ho ~hs name typ ~count = + let rec go db = function + | [] -> db + | _ :: next as name -> + incr load_counter ; + let db = T.add name (candidates_add ~ho ~hs typ ~count) db in + go db next + in + db := go !db name + +let store_all typ paths = + let ho = Hocc.create 16 in + let hs = Hset.create 16 in + List.iter (fun (path, count) -> store ~ho ~hs ~count path typ) (regroup paths) + +let store_name name typ = + let hs = Hset.create 16 in + let rec go db = function + | [] -> db + | _ :: next as name -> + incr load_counter ; + let db = Tchar.add name (set_add ~hs typ) db in + go db next + in + db_names := go !db_names name diff --git a/db/dune b/db/dune new file mode 100644 index 0000000000..aade4fbf5e --- /dev/null +++ b/db/dune @@ -0,0 +1,3 @@ +(library + (name db) + (libraries unix ancient tyxml)) diff --git a/db/storage.ml b/db/storage.ml new file mode 100644 index 0000000000..a1e4c33915 --- /dev/null +++ b/db/storage.ml @@ -0,0 +1,43 @@ +let base_addr = 0x100000000000n + +type writer = + { mutable write_shard : int + ; ancient : Ancient.md + } + +let open_out filename = + let handle = Unix.openfile filename Unix.[ O_RDWR; O_TRUNC; O_CREAT ] 0o640 in + let ancient = Ancient.attach handle base_addr in + { write_shard = 0; ancient } + +type t = + { db : Types.db + ; db_names : Types.Elt_set.t Types.Tchar.t + } + +let save ~db (t : t) = + ignore (Ancient.share db.ancient db.write_shard t) ; + db.write_shard <- db.write_shard + 1 + +let close_out db = Ancient.detach db.ancient + +type reader = { shards : t array } + +let load_shard md shard = + match Ancient.get md shard with + | t -> Some (Ancient.follow t) + | exception _ -> None + +let load_shards md = + let rec go i = + match load_shard md i with + | None -> [] + | Some t -> t :: go (i + 1) + in + Array.of_list (go 0) + +let db_open_in db : reader = + let filename = db in + let handle = Unix.openfile filename Unix.[ O_RDWR ] 0o640 in + let md = Ancient.attach handle base_addr in + { shards = load_shards md } diff --git a/db/trie.ml b/db/trie.ml new file mode 100644 index 0000000000..1e9ba24f82 --- /dev/null +++ b/db/trie.ml @@ -0,0 +1,85 @@ +module type ELEMENT = sig + type t + + val compare : t -> t -> int +end + +module Make (E : ELEMENT) = struct + module M = Map.Make (E) + + type 'a t = + | Leaf of E.t list * 'a + | Node of + { leaf : 'a option + ; mutable summary : 'a option + ; children : 'a t M.t + } + + let empty () = Node { leaf = None; summary = None; children = M.empty } + + let rec add path leaf t = + match t, path with + | Node t, [] -> Node { t with leaf = Some (leaf t.leaf) } + | Node t, p :: path -> + let child = + match M.find p t.children with + | child -> add path leaf child + | exception Not_found -> Leaf (path, leaf None) + in + Node { t with children = M.add p child t.children } + | Leaf (x :: xs, outcome), y :: ys when E.compare x y = 0 -> + if xs = ys + then Leaf (path, leaf (Some outcome)) + else + Node + { leaf = None + ; summary = None + ; children = M.singleton x (add ys leaf (Leaf (xs, outcome))) + } + | Leaf (x :: xs, outcome), y :: ys -> + assert (E.compare x y <> 0) ; + let children = + M.add y (Leaf (ys, leaf None)) @@ M.singleton x (Leaf (xs, outcome)) + in + Node { leaf = None; summary = None; children } + | Leaf ([], outcome), [] -> Leaf ([], leaf (Some outcome)) + | Leaf ([], outcome), y :: ys -> + Node + { leaf = Some outcome + ; summary = None + ; children = M.singleton y (Leaf (ys, leaf None)) + } + | Leaf (y :: ys, outcome), [] -> + Node + { leaf = Some (leaf None) + ; summary = None + ; children = M.singleton y (Leaf (ys, outcome)) + } + + let rec find path t = + match t, path with + | _, [] -> t + | Node t, p :: path -> begin + match M.find p t.children with + | child -> find path child + | exception Not_found -> empty () + end + | Leaf (x :: xs, outcome), y :: ys when E.compare x y = 0 -> + find ys (Leaf (xs, outcome)) + | _ -> empty () + + let rec summarize fn z t = + match t with + | Leaf (_, outcome) -> outcome + | Node ({ leaf; children; _ } as it) -> + let acc = + match leaf with + | None -> z + | Some z -> z + in + let sum = + M.fold (fun _ c acc -> fn acc (summarize fn z c)) children acc + in + it.summary <- Some sum ; + sum +end diff --git a/db/types.ml b/db/types.ml new file mode 100644 index 0000000000..3c3fc4c259 --- /dev/null +++ b/db/types.ml @@ -0,0 +1,73 @@ +module Elt = struct + type t = + { cost : int + ; name : string + ; str_type : string + ; doc : Html_types.li_content_fun Tyxml.Html.elt option + ; pkg : string * string + } + + let compare_pkg (a_name, _) (b_name, _) = String.compare a_name b_name + + let compare a b = + match Int.compare a.cost b.cost with + | 0 -> begin + match String.compare a.name b.name with + | 0 -> begin + match compare_pkg a.pkg b.pkg with + | 0 -> String.compare a.str_type b.str_type + | c -> c + end + | c -> c + end + | c -> c + + let pkg_link { pkg = pkg, v; _ } = + Printf.sprintf "https://ocaml.org/p/%s/%s" pkg v + + let link t = + let name, path = + match List.rev (String.split_on_char '.' t.name) with + | name :: path -> name, String.concat "/" (List.rev path) + | _ -> "", "" + in + pkg_link t ^ "/doc/" ^ path ^ "/index.html#val-" ^ name +end + +module String_list_map = Map.Make (struct + type t = string list + + let compare = Stdlib.compare +end) + +let regroup lst = + String_list_map.bindings + @@ List.fold_left + (fun acc s -> + let count = try String_list_map.find s acc with Not_found -> 0 in + String_list_map.add s (count + 1) acc) + String_list_map.empty lst + +module Int_map = Map.Make (Int) +module Elt_set = Set.Make (Elt) +module T = Trie.Make (String) +module Tchar = Trie.Make (Char) +module Occ = Int_map + +type candidates = Elt_set.t Occ.t +type db = candidates T.t + +type sgn = + | Pos + | Neg + | Unknown + +let string_of_sgn = function + | Pos -> "+" + | Neg -> "-" + | Unknown -> "+" + +let sgn_not = function + | Pos -> Neg + | Neg -> Pos + | Unknown -> Unknown diff --git a/dune-project b/dune-project new file mode 100644 index 0000000000..34d08e6e8c --- /dev/null +++ b/dune-project @@ -0,0 +1,21 @@ +(lang dune 2.9) + +(using menhir 2.1) + +(generate_opam_files true) +(source (github art-w/sherlodoc)) +(authors "Arthur Wendling") +(maintainers "art.wendling@gmail.com") +(license MIT) +(package + (name sherlodoc) + (synopsis "Fuzzy search in OCaml documentation") + (depends + (ocaml (>= 4.14.0)) + dune + ancient + dream + fpath + (odoc (= 2.1.0)) + opam-core + tyxml)) diff --git a/index/cache.ml b/index/cache.ml new file mode 100644 index 0000000000..a5fb176b2a --- /dev/null +++ b/index/cache.ml @@ -0,0 +1,24 @@ +module type S = sig + type t + + val copy : t -> t +end + +module Make (Element : S) = struct + module H = Hashtbl.Make (struct + type t = Element.t + + let equal = ( = ) + let hash = Hashtbl.hash + end) + + let cache = H.create 16 + let clear () = H.clear cache + + let memo str = + try H.find cache str + with Not_found -> + let str = Element.copy str in + H.add cache str str ; + str +end diff --git a/index/dune b/index/dune new file mode 100644 index 0000000000..e75cb5365b --- /dev/null +++ b/index/dune @@ -0,0 +1,12 @@ +(executable + (name index) + (libraries + db + fpath + tyxml + opam-core + odoc.loader + odoc.model + odoc.xref2 + odoc.odoc + str)) diff --git a/index/files.ml b/index/files.ml new file mode 100644 index 0000000000..a420e17758 --- /dev/null +++ b/index/files.ml @@ -0,0 +1,57 @@ +let packages root = Sys.readdir root +let versions root dir = Array.to_list @@ Sys.readdir @@ Filename.concat root dir + +let untar root = + Array.iter + (fun dir -> + match versions root dir with + | [] -> () + | v :: vs -> + let latest_version = + List.fold_left + (fun v0 v1 -> + if OpamVersionCompare.compare v0 v1 < 0 then v1 else v0) + v vs + in + Sys.chdir Filename.(concat (concat root dir) latest_version) ; + let ok = Sys.command "tar -xvf content.tar" in + assert (ok = 0) ; + ()) + (packages root) + +let contains s1 s2 = + let re = Str.regexp_string s2 in + try + ignore (Str.search_forward re s1 0) ; + true + with Not_found -> false + +let list root_directory = + let cwd = Sys.getcwd () in + Sys.chdir root_directory ; + let h = Unix.open_process_in "find . -name '*.odocl'" in + let rec go acc = + match Stdlib.input_line h with + | exception End_of_file -> + ignore (Unix.close_process_in h) ; + acc + | line -> go (line :: acc) + in + let files = go [] in + Sys.chdir cwd ; + List.filter (fun filename -> + not + (List.exists (contains filename) + [ "page-" + ; "__" + ; "Linalg" + ; "tezos" + ; "archetype" + ; "async" + ; "kernel" + ; "camlp4" + ; "DAGaml" + ; "Luv" + ; "ocapic" + ])) + @@ files diff --git a/index/index.ml b/index/index.ml new file mode 100644 index 0000000000..188a68631c --- /dev/null +++ b/index/index.ml @@ -0,0 +1,33 @@ +module Storage = Db.Storage + +let odoc_directory = Sys.argv.(1) +let db_filename = Sys.argv.(2) + +let of_filename f = + let module_name = + String.capitalize_ascii Filename.(chop_extension (basename f)) + in + module_name, f + +let filenames () = List.map of_filename (Files.list odoc_directory) + +let () = + let files = filenames () in + let total = List.length files in + let h = Storage.open_out db_filename in + let flush () = + Load_doc.clear () ; + Db.export h + in + List.iteri + (fun i file -> + if !Db.load_counter > 10_000_000 + then begin + Printf.printf + "---------------- SHARD %i / %i -----------------------\n%!" i total ; + flush () + end ; + Load_doc.run ~odoc_directory file) + files ; + flush () ; + Storage.close_out h diff --git a/index/load_doc.ml b/index/load_doc.ml new file mode 100644 index 0000000000..2d69307e50 --- /dev/null +++ b/index/load_doc.ml @@ -0,0 +1,204 @@ +module Types = Db.Types +open Odoc_model +module ModuleName = Odoc_model.Names.ModuleName + +let copy str = String.init (String.length str) (String.get str) + +let deep_copy (type t) (x : t) : t = + let buf = Marshal.(to_bytes x [ No_sharing; Closures ]) in + Marshal.from_bytes buf 0 + +module Cache_doc = Cache.Make (struct + type t = Html_types.li_content_fun Tyxml.Html.elt + + let copy x = deep_copy x +end) + +module Cache_name = Cache.Make (struct + type t = string + + let copy = copy +end) + +module Cache = Cache.Make (struct + type t = string + + let copy = copy +end) + +let clear () = + Cache.clear () ; + Cache_name.clear () ; + Cache_doc.clear () + +let rec type_size = function + | Odoc_model.Lang.TypeExpr.Var _ -> 1 + | Any -> 1 + | Arrow (lbl, a, b) -> + (match lbl with + | None -> 0 + | Some _ -> 1) + + type_size a + type_size b + | Constr (_, args) -> List.fold_left (fun acc t -> acc + type_size t) 1 args + | Tuple args -> List.fold_left (fun acc t -> acc + type_size t) 1 args + | _ -> 100 + +let rev_concat lst = + List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst + +let rec tails = function + | [] -> [] + | _ :: xs as lst -> lst :: tails xs + +let all_type_names t = + let fullname = + Pretty.fmt_to_string (fun h -> Pretty.show_type_name_verbose h t) + in + tails (String.split_on_char '.' fullname) + +let rec type_paths ~prefix ~sgn = function + | Odoc_model.Lang.TypeExpr.Var _ -> + [ "POLY" :: Types.string_of_sgn sgn :: prefix ] + | Any -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] + | Arrow (_lbl, a, b) -> + List.rev_append + (type_paths ~prefix ~sgn:(Types.sgn_not sgn) a) + (type_paths ~prefix ~sgn b) + | Constr (name, args) -> + rev_concat + @@ List.map (fun name -> + let name = String.concat "." name in + let prefix = name :: Types.string_of_sgn sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + type_paths ~prefix ~sgn arg) + args + end) + @@ all_type_names name + | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args + | _ -> [] + +let save_item ~pkg ~path_list ~path name type_ doc = + let b = Buffer.create 16 in + let to_b = Format.formatter_of_buffer b in + Format.fprintf to_b "%a%!" + (Pretty.show_type + ~path:(Pretty.fmt_to_string (fun h -> Pretty.pp_path h path)) + ~parens:false) + type_ ; + let str_type = Buffer.contents b in + Buffer.reset b ; + Format.fprintf to_b "%a%s%!" Pretty.pp_path path + (Odoc_model.Names.ValueName.to_string name) ; + let full_name = Buffer.contents b in + let doc = Option.map Cache_doc.memo (Pretty.string_of_docs doc) in + let cost = + String.length full_name + String.length str_type + + (5 * List.length path) + + type_size type_ + + (match doc with + | None -> 1000 + | _ -> 0) + + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 + in + let str_type = + { Db.Elt.name = full_name; cost; str_type = Cache.memo str_type; doc; pkg } + in + let my_full_name = + List.rev_append + (Db.list_of_string (Odoc_model.Names.ValueName.to_string name)) + ('.' :: path_list) + in + Db.store_name my_full_name str_type ; + Db.store_all str_type + (List.map (List.map Cache_name.memo) (type_paths ~prefix:[] ~sgn:Pos type_)) + +let rec item ~pkg ~path_list ~path = + let open Odoc_model.Lang in + function + | Signature.Value { id = `Value (_, name); _ } + when Odoc_model.Names.ValueName.is_internal name -> + () + | Signature.Value { id = `Value (_, name); type_; doc; _ } -> + save_item ~pkg ~path_list ~path name type_ doc + | Module (_, mdl) -> + let name = Paths.Identifier.name mdl.id in + if name = "Stdlib" then () else module_items ~pkg ~path_list ~path mdl + | Type (_, _) -> () + | Include icl -> items ~pkg ~path_list ~path icl.expansion.content.items + | TypeSubstitution _ -> () (* type t = Foo.t = actual_definition *) + | TypExt _ -> () (* type t = .. *) + | Exception _ -> () + | Class _ -> () + | ClassType _ -> () + | Comment _ -> () + | Open _ -> () + | ModuleType _ -> () + | ModuleSubstitution _ -> () + | ModuleTypeSubstitution _ -> () + +and items ~pkg ~path_list ~path item_list = + List.iter (item ~pkg ~path_list ~path) item_list + +and module_items ~pkg ~path_list ~path mdl = + let open Odoc_model.Lang.Module in + let name = Paths.Identifier.name mdl.id in + let path = name :: path in + let path_list = List.rev_append (Db.list_of_string name) ('.' :: path_list) in + match mdl.type_ with + | ModuleType e -> module_type_expr ~pkg ~path_list ~path e + | Alias (_, Some mdl) -> module_items_ty ~pkg ~path_list ~path mdl + | Alias (_, None) -> () + +and module_type_expr ~pkg ~path_list ~path = function + | Signature sg -> items ~pkg ~path_list ~path sg.items + | Functor (_, sg) -> module_type_expr ~pkg ~path_list ~path sg + | With { w_expansion = Some sg; _ } + | TypeOf { t_expansion = Some sg; _ } + | Path { p_expansion = Some sg; _ } -> + simple_expansion ~pkg ~path_list ~path sg + | With _ -> () + | TypeOf _ -> () + | Path _ -> () + | _ -> . + +and simple_expansion ~pkg ~path_list ~path = function + | Signature sg -> items ~pkg ~path_list ~path sg.items + | Functor (_, sg) -> simple_expansion ~pkg ~path_list ~path sg + +and module_items_ty ~pkg ~path_list ~path = function + | Functor (_, mdl) -> module_items_ty ~pkg ~path_list ~path mdl + | Signature sg -> items ~pkg ~path_list ~path sg.items + +module Resolver = Odoc_odoc.Resolver + +let run ~odoc_directory (root_name, filename) = + let ((package, version) as pkg) = + match String.split_on_char '/' filename with + | "." :: package :: version :: _ -> package, version + | _ -> + invalid_arg (Printf.sprintf "not a valid package/version? %S" filename) + in + Format.printf "%s %s => %s@." package version root_name ; + let filename = Filename.concat odoc_directory filename in + let fpath = Result.get_ok @@ Fpath.of_string filename in + let t = + match Odoc_odoc.Odoc_file.load fpath with + | Ok { Odoc_odoc.Odoc_file.content = Unit_content t; _ } -> t + | Ok { Odoc_odoc.Odoc_file.content = Page_content _; _ } -> + failwith "page content" + | Error (`Msg m) -> failwith ("ERROR:" ^ m) + in + let open Odoc_model.Lang.Compilation_unit in + match t.content with + | Pack _ -> () + | Module t -> + let path = [ root_name ] in + let path_list = List.rev (Db.list_of_string root_name) in + items ~pkg ~path_list ~path t.Odoc_model.Lang.Signature.items diff --git a/index/pretty.ml b/index/pretty.ml new file mode 100644 index 0000000000..5effaaf5ef --- /dev/null +++ b/index/pretty.ml @@ -0,0 +1,223 @@ +open Odoc_model +open Odoc_model.Root +module ModuleName = Odoc_model.Names.ModuleName +module H = Tyxml.Html + +let fmt_to_string f = + let b = Buffer.create 16 in + let to_b = Format.formatter_of_buffer b in + f to_b ; + Format.fprintf to_b "%!" ; + Buffer.contents b + +let rec string_of_non_link = function + | `Space -> H.txt " " + | `Word w -> H.txt w + | `Code_span s -> H.code [ H.txt s ] + | `Raw_markup (_, s) -> H.txt s + | `Styled (_, lst) -> string_of_link_content lst + +and string_of_element = function + | `Styled (_, lst) -> string_of_paragraph lst + | `Reference (_, r) -> string_of_link_content r + | `Link (_, r) -> string_of_link_content r + | `Space -> H.txt " " + | `Word w -> H.txt w + | `Code_span s -> H.code [ H.txt s ] + | `Raw_markup (_, s) -> H.txt s + +and string_of_link_content lst = + H.span + (List.map (fun r -> string_of_non_link r.Odoc_model.Location_.value) lst) + +and string_of_paragraph lst = + H.span + (List.map (fun elt -> string_of_element elt.Odoc_model.Location_.value) lst) + +let string_of_doc = function + | `Paragraph p -> Some (H.p [ string_of_paragraph p ]) + | `Heading (_, _, p) -> Some (H.p [ string_of_link_content p ]) + | _ -> None + +let string_of_docs lst = + List.find_map (fun elt -> string_of_doc elt.Odoc_model.Location_.value) lst + +let make_root ~module_name ~digest = + let file = Odoc_file.create_unit ~force_hidden:false module_name in + Ok { id = `Root (None, ModuleName.make_std module_name); file; digest } + +let show_module_name h md = + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) + +let show_module_ident h = function + | `Module (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) + | `Root (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) + | _ -> Format.fprintf h "!!module!!" + +let rec show_module_t h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_module_ident (Resolved.Module.identifier t) + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + | `Root x -> Format.fprintf h "%s" x + | `Apply (m, _) -> Format.fprintf h "%a(_)" show_module_t m + | `Forward str -> Format.fprintf h "%s" str + | `Result _ -> () + | `Identifier _ -> () + +and show_module_path h = function + | `Identifier (`Module (_, md)) -> + Format.fprintf h "" show_module_name md + | `Identifier (`Root (_, md)) -> + Format.fprintf h "" show_module_name md + | `Identifier _ -> Format.fprintf h "" + | `Subst _ -> Format.fprintf h "" + | `Hidden _ -> Format.fprintf h "" + | `Module (pt, md) -> + Format.fprintf h "" show_module_path pt show_module_name + md + | `Canonical (pt, md) -> + Format.fprintf h "" show_module_path pt show_module_t md + | `Apply _ -> Format.fprintf h "" + | `Alias (pt, md) -> + Format.fprintf h "" show_module_path pt show_module_path md + | `OpaqueModule _ -> Format.fprintf h "" + +and show_signature h = function + | `Root (_, name) -> + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) + | `Module (pt, mdl) -> + Format.fprintf h "%a.%a" show_signature pt show_module_name mdl + | `Parameter (_, p) -> + Format.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string p) + | `Result t -> Format.fprintf h "%a" show_signature t + | `ModuleType (_, p) -> + Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) + +let show_ident_verbose h = function + | `Type (md, n) -> + Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) + | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) + | _ -> Format.fprintf h "show_ident?" + +let show_ident_short h = function + | `Type (_, n) -> Format.fprintf h "%s" (Names.TypeName.to_string n) + | `CoreType n -> Format.fprintf h "%s" (Names.TypeName.to_string n) + | _ -> Format.fprintf h "show_ident?" + +let show_type_name_verbose h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_ident_verbose (Resolved.Type.identifier t) + | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + +let show_type_name_short h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_ident_short (Resolved.Type.identifier t) + | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Dot (_mdl, x) -> Format.fprintf h "%s" x + +let strip ~prefix str = + if String.starts_with ~prefix str + then + String.sub str (String.length prefix) + (String.length str - String.length prefix) + else str + +let show_type_name ~path h t = + let blah = fmt_to_string (fun h -> show_type_name_verbose h t) in + let blah = strip ~prefix:path blah in + let blah = strip ~prefix:"Stdlib." blah in + Format.fprintf h "%s" blah + +let show_moduletype_ident h = function + | `ModuleType (_, _) -> Format.fprintf h "ident" + | _ -> Format.fprintf h "moduletype" + +let show_moduletype_name h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_moduletype_ident + (Resolved.ModuleType.identifier t) + | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + +let show_label h = function + | None -> () + | Some (Odoc_model.Lang.TypeExpr.Label lbl) -> Format.fprintf h "%s:" lbl + | Some (Optional lbl) -> Format.fprintf h "?%s:" lbl + +let show_type_id h = function + | `Type (_, name) -> Printf.fprintf h "%s" (Names.TypeName.to_string name) + | `CoreType name -> + Printf.fprintf h "(core)%s" (Names.TypeName.to_string name) + +let show_type_repr h = function + | None -> Printf.fprintf h "no repr" + | Some _ -> Printf.fprintf h "has repr" + +let show_functor_param h = function + | Lang.FunctorParameter.Unit -> Printf.fprintf h "UNIT" + | Named { id = `Parameter (_, md); expr = _ } -> + Printf.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string md) + +let type_no_parens = function + | Odoc_model.Lang.TypeExpr.Var _ | Any | Constr _ | Tuple _ -> true + | _ -> false + +let rec show_type ~path ~parens h = function + | Odoc_model.Lang.TypeExpr.Var x -> Format.fprintf h "'%s" x + | Any -> Format.fprintf h "_" + | Arrow (lbl, a, b) -> + if parens then Format.fprintf h "(" ; + Format.fprintf h "%a%a -> %a" show_label lbl + (show_type ~path ~parens:true) + a + (show_type ~path ~parens:false) + b ; + if parens then Format.fprintf h ")" + | Constr (name, []) -> Format.fprintf h "%a" (show_type_name ~path) name + | Constr (name, ([ x ] as args)) when type_no_parens x -> + Format.fprintf h "%a %a" (show_type_list ~path) args + (show_type_name ~path) name + | Constr (name, args) -> + Format.fprintf h "(%a) %a" (show_type_list ~path) args + (show_type_name ~path) name + | Tuple args -> + Format.fprintf h "(" ; + show_tuple_list ~path h args ; + Format.fprintf h ")" + | Poly (polys, t) -> + if parens then Format.fprintf h "(" ; + Format.fprintf h "%a. %a" show_polys polys + (show_type ~path ~parens:false) + t ; + if parens then Format.fprintf h ")" + | _ -> Format.fprintf h "!!todo!!" + +and show_polys h = function + | [] -> failwith "show_polys: empty list" + | [ x ] -> Format.fprintf h "'%s" x + | x :: xs -> Format.fprintf h "'%s %a" x show_polys xs + +and show_type_list ~path h = function + | [] -> failwith "empty list" + | [ x ] -> show_type ~path ~parens:false h x + | x :: xs -> + Format.fprintf h "%a, %a" + (show_type ~path ~parens:true) + x (show_type_list ~path) xs + +and show_tuple_list ~path h = function + | [] -> failwith "empty list" + | [ x ] -> show_type ~path ~parens:true h x + | x :: xs -> + Format.fprintf h "%a * %a" + (show_type ~path ~parens:true) + x (show_tuple_list ~path) xs + +let rec pp_path h = function + | [] -> Format.fprintf h "" + | x :: xs -> Format.fprintf h "%a%s." pp_path xs x diff --git a/query/dune b/query/dune new file mode 100644 index 0000000000..e8569597d7 --- /dev/null +++ b/query/dune @@ -0,0 +1,9 @@ +(library + (name query) + (libraries lwt db)) + +(menhir + (modules parser) + (flags --explain)) + +(ocamllex lexer) diff --git a/query/lexer.mll b/query/lexer.mll new file mode 100644 index 0000000000..b75f0b619e --- /dev/null +++ b/query/lexer.mll @@ -0,0 +1,15 @@ +{ + open Parser +} + +rule token = parse +| ' ' { token lexbuf } +| "-" | "->" { ARROW } +| "(" { PARENS_OPEN } +| ")" { PARENS_CLOSE } +| "," { COMMA } +| '_' { ANY } +| '*' { STAR } +| "'" (['a'-'z' 'A'-'Z' '0'-'9' '\'' '_']* as p) { POLY p } +| ['a'-'z' 'A'-'Z' '0'-'9' '\'' '_' '.']+ as w { WORD w } +| eof { EOF } diff --git a/query/parser.mly b/query/parser.mly new file mode 100644 index 0000000000..c59275fd97 --- /dev/null +++ b/query/parser.mly @@ -0,0 +1,50 @@ +%{ + open Query_ast +%} + +%token EOF +%token PARENS_OPEN PARENS_CLOSE +%token ARROW COMMA ANY STAR +%token WORD +%token POLY + +%start main +%type main + +%% + +main: + | t=typ EOF { t } + | EOF { Any } + ; + +typ: + | a=typ1 ARROW b=typ { Arrow (a, b) } + | a=typ1 ARROW EOF { Arrow (a, Any) } + | ARROW b=typ { Arrow (Any, b) } + | ARROW EOF { Arrow (Any, Any) } + | t=typ1 { t } + ; + +typ1: + | x=typ0 xs=tups { match xs with [] -> x | xs -> Tuple (x::xs) } + ; + +tups: + | STAR x=typ0 xs=tups { x::xs } + | STAR { [Any] } + | EOF { [] } + | { [] } + ; + +typ0: + | ANY { Any } + | w=POLY { Poly w } + | w=WORD { Constr (w, []) } + | t=typ0 w=WORD { Constr (w, [t]) } + | PARENS_OPEN ts=typ_list PARENS_CLOSE w=WORD { Constr (w, ts) } + | PARENS_OPEN t=typ PARENS_CLOSE { t } + | PARENS_OPEN t=typ EOF { t } + ; + +typ_list: ts=separated_list(COMMA, typ) { ts } ; diff --git a/query/query.ml b/query/query.ml new file mode 100644 index 0000000000..b0be72e13d --- /dev/null +++ b/query/query.ml @@ -0,0 +1,115 @@ +module Parser = Query_parser +module Succ = Succ +module Storage = Db.Storage +open Db.Types + +let inter_list = function + | [] -> Succ.all + | x :: xs -> List.fold_left Succ.inter x xs + +let merge a b = + Occ.merge + (fun _ ox oy -> + match ox, oy with + | Some x, Some y -> Some (Succ.union (Succ.of_set x) y) + | Some x, None -> Some (Succ.of_set x) + | None, opt -> opt) + a b + +let collapse_trie t _acc = + let open Db.Types.T in + match t with + | Leaf (_, outcome) -> outcome + | Node { summary = Some s; _ } -> s + | _ -> Occ.empty + +let collapse_trie t = + let r = collapse_trie t Occ.empty in + let r = Occ.map Succ.of_set r in + r + +let collapse_triechar t _acc = + let open Tchar in + match t with + | Leaf (_, outcome) -> outcome + | Node { summary = Some s; _ } -> s + | _ -> Elt_set.empty + +let collapse_triechar t = Succ.of_set (collapse_triechar t Elt_set.empty) + +let collapse_count ~count (t : Succ.t Occ.t) = + Occ.fold + (fun k x acc -> if k < count then acc else Succ.union x acc) + t Succ.empty + +let collapse_trie_with_poly name t = + match name with + | [ "POLY"; _ ] -> + let open T in + begin + match t with + | Leaf ([], s) | Node { leaf = Some s; _ } -> Occ.map Succ.of_set s + | _ -> Occ.empty + end + | _ -> collapse_trie t + +let sort x = x + +let find_inter ~shards names = + Lwt_list.fold_left_s + (fun acc shard -> + let db = shard.Storage.db in + let r = + sort @@ inter_list + @@ List.map + (fun (name, count) -> + collapse_count ~count + @@ collapse_trie_with_poly name + @@ T.find name db) + (regroup names) + in + let open Lwt.Syntax in + let+ () = Lwt.pause () in + Succ.union acc r) + Succ.empty shards + +let find_names ~shards names = + let names = List.map (fun n -> List.rev (Db.list_of_string n)) names in + Lwt_list.fold_left_s + (fun acc shard -> + let db_names = shard.Storage.db_names in + let open Lwt.Syntax in + let+ () = Lwt.pause () in + let candidates = + List.map + (fun name -> + let t = Tchar.find name db_names in + collapse_triechar t) + names + in + let candidates = inter_list candidates in + Succ.union acc candidates) + Succ.empty shards + +let pp h set = + Int_map.iter + (fun cost values -> + Elt_set.iter + (fun value -> Format.fprintf h "(%i) %s\n%!" cost value.str_type) + values) + set + +exception Abort of Elt.t list + +let to_list results = + let lst = + try + Int_map.fold + (fun _ v acc -> + let lst = List.rev_append (Elt_set.elements v) acc in + if List.length lst > 200 then raise (Abort lst) ; + lst) + results [] + with Abort lst -> lst + in + List.rev lst diff --git a/query/query_ast.ml b/query/query_ast.ml new file mode 100644 index 0000000000..29de7eeb21 --- /dev/null +++ b/query/query_ast.ml @@ -0,0 +1,53 @@ +type t = + | Arrow of t * t + | Constr of string * t list + | Tuple of t list + | Poly of string + | Any +[@@deriving show] + +let rec paths ~prefix ~sgn = function + | Poly _ -> [ "POLY" :: Db.Types.string_of_sgn sgn :: prefix ] + | Any -> [ prefix ] + | Arrow (a, b) -> + paths ~prefix ~sgn:(Db.Types.sgn_not sgn) a @ paths ~prefix ~sgn b + | Constr (name, args) -> + let prefix = name :: Db.Types.string_of_sgn sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + List.concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + paths ~prefix ~sgn arg) + args + end + | Tuple args -> + List.concat @@ List.map (fun arg -> paths ~prefix ~sgn arg) args + +let rec show = function + | Arrow (a, b) -> show_parens a ^ " -> " ^ show b + | Constr (t, []) -> t + | Constr (t, [ x ]) -> show_parens x ^ " " ^ t + | Constr (t, xs) -> "(" ^ show_list xs ^ ") " ^ t + | Tuple xs -> show_tuple xs + | Poly "" -> "'_" + | Poly name -> "'" ^ name + | Any -> "_" + +and show_parens t = + match t with + | Arrow _ | Tuple _ -> "(" ^ show t ^ ")" + | _ -> show t + +and show_list = function + | [] -> failwith "show_list: empty" + | [ x ] -> show x + | x :: xs -> show x ^ ", " ^ show_list xs + +and show_tuple = function + | [] -> failwith "show_tuple: empty" + | [ x ] -> show x + | x :: xs -> show_parens x ^ " * " ^ show_tuple xs diff --git a/query/query_parser.ml b/query/query_parser.ml new file mode 100644 index 0000000000..e8a06d07ea --- /dev/null +++ b/query/query_parser.ml @@ -0,0 +1,32 @@ +open Query_ast + +type t = string list + +let parse str = Parser.main Lexer.token (Lexing.from_string str) + +let alphanum = function + | 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '\'' -> true + | _ -> false + +let naive_of_string str = + List.filter (fun s -> String.length s > 0) (String.split_on_char ' ' str) + +let of_string str = + let ok, str_name, str_typ = + match String.split_on_char ':' str with + | [ a; b ] -> true, a, b + | _ -> false, str, "" + in + let pretty, ps = + match parse str_typ with + | Any -> "_", [] + | typ -> + ( Query_ast.show typ + , List.filter + (fun s -> List.length s > 0) + (paths ~prefix:[] ~sgn:Db.Types.Pos typ) ) + | exception _ -> "", [] + in + let keywords = naive_of_string str_name in + let keywords_pretty = String.concat " " keywords in + ok, keywords, ps, keywords_pretty ^ " : " ^ pretty diff --git a/query/succ.ml b/query/succ.ml new file mode 100644 index 0000000000..e6966521ba --- /dev/null +++ b/query/succ.ml @@ -0,0 +1,133 @@ +open Db.Types + +type s = + | All + | Empty + | Set of Elt_set.t + | Inter of s * s + | Union of s * s + +type t = + { cardinal : int + ; s : s + } + +let all = { cardinal = -1; s = All } +let empty = { cardinal = 0; s = Empty } + +let of_set s = + if Elt_set.is_empty s + then empty + else { cardinal = Elt_set.cardinal s; s = Set s } + +let inter a b = + match a.s, b.s with + | Empty, _ | _, Empty -> empty + | _, All -> a + | All, _ -> b + | x, y -> + let x, y = if a.cardinal < b.cardinal then x, y else y, x in + { cardinal = min a.cardinal b.cardinal; s = Inter (x, y) } + +let union a b = + match a.s, b.s with + | Empty, _ -> b + | _, Empty -> a + | All, _ | _, All -> all + | x, y -> { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } + +let succ_ge' elt set = Elt_set.find_first (fun e -> Elt.compare e elt >= 0) set +let succ_gt' elt set = Elt_set.find_first (fun e -> Elt.compare e elt > 0) set +let first' set = Elt_set.find_first (fun _ -> true) set + +exception Gt of Elt.t + +let rec succ_ge elt = function + | All -> elt + | Empty -> raise Not_found + | Set s -> + let out = succ_ge' elt s in + begin + match Elt.compare elt out with + | 0 -> elt + | _ -> raise (Gt out) + end + | Inter (a, b) -> + let _ = succ_ge elt a in + let y = succ_ge elt b in + y + | Union (a, b) -> begin + match succ_ge elt a with + | exception Not_found -> succ_ge elt b + | exception Gt x -> begin + match succ_ge elt b with + | exception Not_found -> raise (Gt x) + | exception Gt y -> + raise + (Gt + (match Elt.compare x y with + | c when c <= 0 -> x + | _ -> y)) + | v -> v + end + | v -> v + end + +let rec succ_gt elt = function + | All -> invalid_arg "Succ.succ_gt All" + | Empty -> raise Not_found + | Set s -> succ_gt' elt s + | Inter (a, _b) -> succ_gt elt a + | Union (a, b) -> begin + match succ_gt_opt elt a, succ_gt_opt elt b with + | None, None -> raise Not_found + | None, Some z | Some z, None -> z + | Some x, Some y -> begin + match Elt.compare x y with + | c when c <= 0 -> x + | _ -> y + end + end + +and succ_gt_opt elt t = try Some (succ_gt elt t) with Not_found -> None + +let rec first = function + | All -> invalid_arg "Succ.first All" + | Empty -> raise Not_found + | Set s -> first' s + | Inter (a, _b) -> first a + | Union (a, b) -> begin + match first_opt a, first_opt b with + | None, None -> raise Not_found + | None, Some z | Some z, None -> z + | Some x, Some y -> begin + match Elt.compare x y with + | 0 -> x + | c when c < 0 -> x + | _ -> y + end + end + +and first_opt t = try Some (first t) with Not_found -> None + +let first t = + let rec go n elt acc = + if n <= 0 + then Lwt.return (List.rev acc) + else + let open Lwt.Syntax in + let* () = Lwt.pause () in + match succ_ge elt t with + | elt' -> + assert (Elt.compare elt elt' = 0) ; + go_gt (n - 1) elt (elt :: acc) + | exception Gt elt -> go n elt acc + | exception Not_found -> Lwt.return (List.rev acc) + and go_gt n elt acc = + match succ_gt elt t with + | elt -> go n elt acc + | exception Not_found -> Lwt.return (List.rev acc) + in + Lwt.catch (fun () -> go 100 (first t) []) (fun (_ : exn) -> Lwt.return []) + +let to_list t = first t.s diff --git a/sherlodoc.opam b/sherlodoc.opam new file mode 100644 index 0000000000..1b9de2484b --- /dev/null +++ b/sherlodoc.opam @@ -0,0 +1,35 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "Fuzzy search in OCaml documentation" +maintainer: ["art.wendling@gmail.com"] +authors: ["Arthur Wendling"] +license: "MIT" +homepage: "https://github.com/art-w/sherlodoc" +bug-reports: "https://github.com/art-w/sherlodoc/issues" +depends: [ + "ocaml" {>= "4.14.0"} + "dune" {>= "2.9"} + "ancient" + "dream" + "fpath" + "odoc" {= "2.1.0"} + "opam-core" + "tyxml" +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "--promote-install-files=false" + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] + ["dune" "install" "-p" name "--create-install-files" name] +] +dev-repo: "git+https://github.com/art-w/sherlodoc.git" diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000000..db8c06df4e --- /dev/null +++ b/static/style.css @@ -0,0 +1,163 @@ +body { + margin: 0; + padding: 0; + margin-bottom: 1em; +} + +form { + display: flex; + margin: 0; + padding: 1rem; + background-color: #EABB60; + border-bottom: 2px solid #C78746; + position: fixed; + top: 0px; + width: 100%; + height: 2.5em; +} + +#results { + margin-top: 7.5em; +} + +input { + line-height: 1.5em; +} + +input[type="text"] { + width: 80%; + background-color: #FADFB1; + font-size: 1.5em; + border: none; + margin-right: -2px; + padding: 0 0.5em; + margin-left: 1.7em; + outline: 1px solid #553515; +} +input[type="submit"] { + padding: 0 1em; + font-size: 1.5em; + background-color: #C78746; + border: none; + color: #553515; + font-weight: bold; + outline: 1px solid #553515; +} + +a { + text-decoration: none; +} + +pre { + margin: 0.5em; + font-size: 1.1rem; + white-space: normal; +} +pre { + padding-left: 6em; + text-indent: -6em; +} + +pre em { + font-style: normal; + font-weight: bold; +} + +ul { + margin: 0; + padding: 0; +} + +.found li { + list-style: none; + margin: 0; + padding: 0; + margin-bottom: 1.5em; + margin-right: 5em; + margin-left: 0.95em; +} + +.found li em { + margin: 0 -3px; + padding: 3px; + color: black; +} + +.found li:hover em { + background: #FADFB1; +} + +.found li a:hover em { + background: #EABB60; + border-bottom: 2px solid #553515; +} + + +h1, ul.doc, p { + margin: 0; + padding: 0; + margin-left: 3.4rem; +} + +h1 { + margin-bottom: 1em; + font-size: 3em; +} + +p.doc { + margin-bottom: 1em; + font-size: 1.5em; +} + +ul.doc li { + margin-bottom: 0.5em; +} + +.doc code { + font-size: 1rem; + background: #eee; + padding: 0.1em 0.5em; +} + +.query { + background-color: #FADFB1; + border-top: 1px solid #C78746; + border-bottom: 2px solid #C78746; + position: fixed; + top: 4.5em; + width: 100%; + padding: 0.3em 4.2em; + font-style: italic; + color: #553515; +} +.query code { + margin-left: 1em; +} + +code { + font-size: 1rem; +} + +.pkg { + margin-left: 3em; + margin-bottom: -0.4em; +} + +.pkg a, .pkg a:visited { + margin: 0; + font-weight: bold; + font-size: 0.8em; + padding: 0 5px; + color: #1A3B60; +} + +.pkg .version { + font-weight: normal; + color: #8BA4C0; +} + +.pkg a:hover, .pkg a:hover .version { + background: #3D5570; + color: white !important; + text-decoration: none; +} diff --git a/www/dune b/www/dune new file mode 100644 index 0000000000..96fec40001 --- /dev/null +++ b/www/dune @@ -0,0 +1,3 @@ +(executable + (name www) + (libraries dream db query)) diff --git a/www/ui.ml b/www/ui.ml new file mode 100644 index 0000000000..e1127182a8 --- /dev/null +++ b/www/ui.ml @@ -0,0 +1,133 @@ +open Tyxml.Html + +let list_of_option = function + | None -> [] + | Some x -> [ x ] + +let render_result r = + let open Db.Types.Elt in + div + ~a:[ a_class [ "pkg" ] ] + [ a + ~a:[ a_href (pkg_link r) ] + [ txt (fst r.pkg) + ; txt " " + ; span ~a:[ a_class [ "version" ] ] [ txt (snd r.pkg) ] + ] + ] + :: pre + [ txt "val " + ; a ~a:[ a_href (link r) ] [ em [ txt r.name ] ] + ; txt " : " + ; txt r.str_type + ] + :: list_of_option r.doc + +let render ~pretty results = + match results with + | [] -> + div ~a:[ a_class [ "query" ] ] [ txt "No results! "; code [ txt pretty ] ] + | _ -> + div + [ div + ~a:[ a_class [ "query" ] ] + [ txt "Results for "; code [ txt pretty ] ] + ; ul ~a:[ a_class [ "found" ] ] + @@ List.map (fun r -> li (render_result r)) results + ] + +let ajax_reload = + {js| + var latest = 0; + var current = 0; + document.getElementById('q').addEventListener('input', function(e) { + var param = encodeURIComponent(e.target.value); + ++latest; + var self = latest; + var req = new XMLHttpRequest(); + req.onreadystatechange = function() { + if (this.readyState === 4 && current < self) { + current = self; + document.getElementById('results').innerHTML = this.response; + } + }; + req.open('GET', '/api?q=' + param, true); + req.send(); + var url = param === '' ? '/' : '/?q=' + param; + history.replaceState(null, 'Sherlodoc', url); + }); + |js} + +let search_form query = + div + ~a:[ a_class [ "header" ] ] + [ form + ~a:[ a_method `Get ] + [ input + ~a: + [ a_input_type `Text + ; a_id "q" + ; a_name "q" + ; a_value query + ; a_placeholder "Search..." + ; a_autofocus () + ; a_autocomplete false + ] + () + ; input ~a:[ a_input_type `Submit; a_value "Search!" ] () + ] + ; script (Unsafe.data ajax_reload) + ] + +let template query contents = + html + ~a:[ a_lang "en" ] + (head + (title (txt "Sherlodoc")) + [ meta ~a:[ a_charset "UTF-8" ] () + ; meta + ~a: + [ a_name "viewport" + ; a_content "width=device-width, initial-scale=1" + ] + () + ; link ~rel:[ `Stylesheet ] ~href:"/s.css" () + ]) + @@ body [ search_form query; div ~a:[ a_id "results" ] [ contents ] ] + +let link str = a ~a:[ a_href ("?q=" ^ Uri.pct_encode str) ] [ code [ txt str ] ] + +let explain = + div + ~a:[ a_class [ "doc" ] ] + [ h1 [ txt "Sherlodoc" ] + ; p + ~a:[ a_class [ "doc" ] ] + [ txt + "Fuzzy search in OCaml's documentation for almost all opam \ + packages." + ] + ; ul + ~a:[ a_class [ "doc" ] ] + [ li + [ txt "Search by name: " + ; link "concat map" + ; txt " and " + ; link "Lwt pool" + ] + ; li [ txt "Search by type with a colon: "; link ": list list -> list" ] + ; li + [ txt "Search on name and type with a colon separator: " + ; link "Yojson : t -> string" + ] + ; li [ txt "Search for constructors of a type: "; link ": Gg.color" ] + ; li + [ txt "Use _ to omit a subtype and search for consumers of a type: " + ; link ": Gg.color -> _" + ] + ; li + [ txt "Products and reordering of arguments: " + ; link ": 'a list -> ('a * int -> bool) -> 'a list" + ] + ] + ] diff --git a/www/www.ml b/www/www.ml new file mode 100644 index 0000000000..20e712221b --- /dev/null +++ b/www/www.ml @@ -0,0 +1,80 @@ +module Storage = Db.Storage +module Succ = Query.Succ + +let db_filename = Sys.argv.(1) + +let shards = + let h = Storage.db_open_in db_filename in + Array.to_list h.Storage.shards + +let search raw_query = + let has_typ, query_name, query_typ, pretty = + Query.Parser.of_string raw_query + in + let open Lwt.Syntax in + let* results_name = Query.find_names ~shards query_name in + let+ results = + if has_typ + then + let+ results_typ = Query.find_inter ~shards query_typ in + Succ.inter results_name results_typ + else Lwt.return results_name + in + results, pretty + +open Lwt.Syntax +module H = Tyxml.Html + +let api query = + let* results, pretty = search query in + let+ results = Succ.to_list results in + Ui.render ~pretty results + +let api query = + if String.trim query = "" then Lwt.return Ui.explain else api query + +open Lwt.Syntax + +let get_query params = Option.value ~default:"" (Dream.query params "q") + +let root ~query fn _params = + let* result = fn query in + Dream.html result + +let string_of_tyxml html = Format.asprintf "%a" (Tyxml.Html.pp ()) html +let string_of_tyxml' html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) html + +let root fn params = + let query = get_query params in + try root ~query fn params + with err -> + Format.printf "ERROR: %S@." (Printexc.to_string err) ; + Dream.html (string_of_tyxml @@ Ui.template query Ui.explain) + +let root fn params = + try root fn params + with _ -> Dream.html (string_of_tyxml @@ Ui.template "" Ui.explain) + +let cache : int -> Dream.middleware = + fun max_age f req -> + let+ response = f req in + Dream.add_header response "Cache-Control" + ("public, max-age=" ^ string_of_int max_age) ; + response + +let () = + Dream.run ~interface:"127.0.0.1" ~port:1234 + @@ Dream.logger @@ cache 3600 + @@ Dream.router + [ Dream.get "/" + (root (fun q -> + let+ result = api q in + string_of_tyxml @@ Ui.template q result)) + ; Dream.get "/api" + (root (fun q -> + let+ result = api q in + string_of_tyxml' result)) + ; Dream.get "/s.css" (Dream.from_filesystem "static" "style.css") + ; Dream.get "/robots.txt" (Dream.from_filesystem "static" "robots.txt") + ; Dream.get "/favicon.ico" (Dream.from_filesystem "static" "favicon.ico") + ] From e60602c8f17ee7ee5060d1ca51ea431c32bb7bb7 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 22 Oct 2022 19:00:43 +0200 Subject: [PATCH 002/285] fix references --- index/pretty.ml | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/index/pretty.ml b/index/pretty.ml index 5effaaf5ef..14353570b3 100644 --- a/index/pretty.ml +++ b/index/pretty.ml @@ -10,6 +10,32 @@ let fmt_to_string f = Format.fprintf to_b "%!" ; Buffer.contents b +let string_of_identifier = function + | `Class (_, n) -> Names.ClassName.to_string n + | `ClassType (_, n) -> Names.ClassTypeName.to_string n + | `Constructor (_, n) -> Names.ConstructorName.to_string n + | `Exception (_, n) -> Names.ExceptionName.to_string n + | `Extension (_, n) -> Names.ExtensionName.to_string n + | `Field (_, n) -> Names.FieldName.to_string n + | `InstanceVariable (_, n) -> Names.InstanceVariableName.to_string n + | `Label (_, n) -> Names.LabelName.to_string n + | `Method (_, n) -> Names.MethodName.to_string n + | `Module (_, n) -> ModuleName.to_string n + | `ModuleType (_, n) -> Names.ModuleTypeName.to_string n + | `Type (_, n) -> Names.TypeName.to_string n + | `Value (_, n) -> Names.ValueName.to_string n + | _ -> "" + +let string_of_resolved = function + | `Identifier v -> string_of_identifier v + | r -> string_of_identifier r + +let string_of_reference = function + | `Root (r, _) -> r + | `Dot (_, n) -> n + | `Resolved r -> string_of_resolved r + | r -> string_of_identifier r + let rec string_of_non_link = function | `Space -> H.txt " " | `Word w -> H.txt w @@ -19,7 +45,7 @@ let rec string_of_non_link = function and string_of_element = function | `Styled (_, lst) -> string_of_paragraph lst - | `Reference (_, r) -> string_of_link_content r + | `Reference (r, _) -> H.code [ H.txt (string_of_reference r) ] | `Link (_, r) -> string_of_link_content r | `Space -> H.txt " " | `Word w -> H.txt w From dd100931270a72f450d414e13528650256e48fb4 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 23 Oct 2022 14:40:01 +0200 Subject: [PATCH 003/285] guess type search --- query/query_parser.ml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/query/query_parser.ml b/query/query_parser.ml index e8a06d07ea..9dbd35ec3d 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -11,10 +11,16 @@ let alphanum = function let naive_of_string str = List.filter (fun s -> String.length s > 0) (String.split_on_char ' ' str) +let guess_type_search str = + String.length str >= 1 + && (str.[0] = '\'' || String.contains str '-' || String.contains str '(') + let of_string str = + let str = String.trim str in let ok, str_name, str_typ = match String.split_on_char ':' str with | [ a; b ] -> true, a, b + | _ when guess_type_search str -> true, "", str | _ -> false, str, "" in let pretty, ps = From e86646288edac5f038b57faafd72673ff58babc3 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 23 Oct 2022 14:52:49 +0200 Subject: [PATCH 004/285] add readme --- LICENSE | 21 +++++++++++++++++++++ README.md | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..674ecf6330 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Arthur Wendling, Tarides + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..3597c79504 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +**Try it online at [doc.sherlocode.com](https://doc.sherlocode.com) !** + +A rough prototype of a Hoogle-like search engine for OCaml documentation. It's full of bugs and todos, but works well enough for my purpose: Perhaps it will be useful to you too. +- The fuzzy type search is supported by a polarity search. As an example, the type `string -> int -> char` gets simplified to `{ -string, -int, +char }` which means that it consumes a `string` and an `int` and produces a `char` (irrespective of the order of the arguments). This yields good search results, but the sorting could be improved. +- The real magic is all the package documentation generated for [`ocaml.org/packages`](https://ocaml.org/packages), which I got my hands on thanks to insider trading (but don't have the bandwidth to share back... sorry!) + +``` +$ opam install --deps-only ./sherlodoc.opam + # Note: your odoc version must match your odocl files + +# To index all the odocl files in `/path/to/doc`: +$ dune exec -- ./index/index.exe /path/to/doc /path/to/result.db + # `/path/to/doc` should contain a hierarchy of subfolders `libname/1.2.3/**/*.odocl` + # `result.db` will be created or replaced + +# To run the website: +$ dune exec -- ./www/www.exe /path/to/result.db +22.10.22 17:17:33.102 Running at http://localhost:1234 +``` From e74a5179314e5f131c8efd5bc8460904bac249c0 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 23 Oct 2022 14:59:54 +0200 Subject: [PATCH 005/285] add link to repo --- static/style.css | 9 +++++++++ www/ui.ml | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/static/style.css b/static/style.css index db8c06df4e..e96039198e 100644 --- a/static/style.css +++ b/static/style.css @@ -161,3 +161,12 @@ code { color: white !important; text-decoration: none; } + +.ad { + padding-top: 3rem; + font-family: monospace; + font-style: italic; + font-size: 1rem; +} + +.ad svg { vertical-align: middle; margin-right: 0.5rem } diff --git a/www/ui.ml b/www/ui.ml index e1127182a8..4063bb37e1 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -95,6 +95,42 @@ let template query contents = ]) @@ body [ search_form query; div ~a:[ a_id "results" ] [ contents ] ] +let github_icon = + let open Tyxml.Svg in + Tyxml.Html.svg + ~a: + [ a_width (16., None) + ; a_height (16.0, None) + ; a_viewBox (0., 0., 16., 16.) + ] + [ path + ~a: + [ a_d + "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 \ + 7.59.4.07.55-.17.55-.38 \ + 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 \ + 1.08.58 1.23.82.72 1.21 1.87.87 \ + 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 \ + 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 \ + 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 \ + 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 \ + 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 \ + 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 \ + 8c0-4.42-3.58-8-8-8z" + ] + [] + ] + +let link_to_repo = + p + ~a:[ a_class [ "ad" ] ] + [ txt {|(* Read the source, fork and contribute to |} + ; a + ~a:[ a_href "https://github.com/art-w/sherlodoc" ] + [ github_icon; txt "art-w/sherlodoc" ] + ; txt " *)" + ] + let link str = a ~a:[ a_href ("?q=" ^ Uri.pct_encode str) ] [ code [ txt str ] ] let explain = @@ -130,4 +166,5 @@ let explain = ; link ": 'a list -> ('a * int -> bool) -> 'a list" ] ] + ; link_to_repo ] From b7ff9a8982a627c0ea83eaff01e633866ff15c26 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 27 Oct 2022 14:16:41 +0200 Subject: [PATCH 006/285] add gitignore --- .gitignore | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..a04b03726e --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +*.annot +*.cmo +*.cma +*.cmi +*.a +*.o +*.cmx +*.cmxs +*.cmxa + +.merlin +*.install +*.coverage +*.sw[lmnop] + +_build/ +_doc/ +_coverage/ +_opam/ From ebd5352c3c267a31ab2b5f18770086ffc008c0ab Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 27 Oct 2022 16:17:00 +0200 Subject: [PATCH 007/285] sort case insensitive names --- index/load_doc.ml | 1 + query/dune | 2 +- query/query.ml | 22 ++++++---------------- query/sort.ml | 45 +++++++++++++++++++++++++++++++++++++++++++++ www/www.ml | 16 +++++++++------- 5 files changed, 62 insertions(+), 24 deletions(-) create mode 100644 query/sort.ml diff --git a/index/load_doc.ml b/index/load_doc.ml index 2d69307e50..c7e59fe9fb 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -115,6 +115,7 @@ let save_item ~pkg ~path_list ~path name type_ doc = (Db.list_of_string (Odoc_model.Names.ValueName.to_string name)) ('.' :: path_list) in + let my_full_name = List.map Char.lowercase_ascii my_full_name in Db.store_name my_full_name str_type ; Db.store_all str_type (List.map (List.map Cache_name.memo) (type_paths ~prefix:[] ~sgn:Pos type_)) diff --git a/query/dune b/query/dune index e8569597d7..0b3ee71d72 100644 --- a/query/dune +++ b/query/dune @@ -1,6 +1,6 @@ (library (name query) - (libraries lwt db)) + (libraries lwt re db)) (menhir (modules parser) diff --git a/query/query.ml b/query/query.ml index b0be72e13d..caefcda31f 100644 --- a/query/query.ml +++ b/query/query.ml @@ -1,5 +1,6 @@ module Parser = Query_parser module Succ = Succ +module Sort = Sort module Storage = Db.Storage open Db.Types @@ -74,7 +75,11 @@ let find_inter ~shards names = Succ.empty shards let find_names ~shards names = - let names = List.map (fun n -> List.rev (Db.list_of_string n)) names in + let names = + List.map + (fun n -> List.rev (Db.list_of_string (String.lowercase_ascii n))) + names + in Lwt_list.fold_left_s (fun acc shard -> let db_names = shard.Storage.db_names in @@ -98,18 +103,3 @@ let pp h set = (fun value -> Format.fprintf h "(%i) %s\n%!" cost value.str_type) values) set - -exception Abort of Elt.t list - -let to_list results = - let lst = - try - Int_map.fold - (fun _ v acc -> - let lst = List.rev_append (Elt_set.elements v) acc in - if List.length lst > 200 then raise (Abort lst) ; - lst) - results [] - with Abort lst -> lst - in - List.rev lst diff --git a/query/sort.ml b/query/sort.ml new file mode 100644 index 0000000000..70bf40b86e --- /dev/null +++ b/query/sort.ml @@ -0,0 +1,45 @@ +module Elt = Db.Types.Elt + +let is_substring ~sub s = + let re = Re.(compile (seq [ rep any; str sub ])) in + Re.execp re s + +let score_name query_name name = + if String.starts_with ~prefix:query_name name + || String.ends_with ~suffix:query_name name + then 1 + else if is_substring ~sub:("(" ^ query_name) name + || is_substring ~sub:(query_name ^ ")") name + then 1 + else if is_substring ~sub:("." ^ query_name) name + || is_substring ~sub:(query_name ^ ".") name + then 2 + else if is_substring ~sub:("_" ^ query_name) name + || is_substring ~sub:(query_name ^ "_") name + then 3 + else 4 + +let score_name query_name name = + match score_name query_name name with + | 4 -> + let query_name_lower = String.lowercase_ascii query_name in + let name_lower = String.lowercase_ascii name in + 3 + + (if query_name = query_name_lower then 0 else 100) + + score_name query_name_lower name_lower + | c -> c + +let score_name query_name name = + List.fold_left + (fun acc query_name -> acc + score_name query_name name) + 0 query_name + +let by_name query_name results = + let results = + List.map + (fun a -> + let cost = a.Elt.cost + (2 * score_name query_name a.Elt.name) in + { a with cost }) + results + in + List.sort Elt.compare results diff --git a/www/www.ml b/www/www.ml index 20e712221b..c3cdb00e42 100644 --- a/www/www.ml +++ b/www/www.ml @@ -1,5 +1,6 @@ module Storage = Db.Storage module Succ = Query.Succ +module Sort = Query.Sort let db_filename = Sys.argv.(1) @@ -7,10 +8,7 @@ let shards = let h = Storage.db_open_in db_filename in Array.to_list h.Storage.shards -let search raw_query = - let has_typ, query_name, query_typ, pretty = - Query.Parser.of_string raw_query - in +let search (has_typ, query_name, query_typ) = let open Lwt.Syntax in let* results_name = Query.find_names ~shards query_name in let+ results = @@ -20,14 +18,18 @@ let search raw_query = Succ.inter results_name results_typ else Lwt.return results_name in - results, pretty + results open Lwt.Syntax module H = Tyxml.Html -let api query = - let* results, pretty = search query in +let api raw_query = + let has_typ, query_name, query_typ, pretty = + Query.Parser.of_string raw_query + in + let* results = search (has_typ, query_name, query_typ) in let+ results = Succ.to_list results in + let results = Sort.by_name query_name results in Ui.render ~pretty results let api query = From 8b9e648700edb3fbdc3b74bd8610dcae988d86cc Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 28 Oct 2022 12:43:53 +0200 Subject: [PATCH 008/285] sort by query type --- README.md | 2 +- db/types.ml | 1 + index/load_doc.ml | 59 +++++++++++++++++++--- query/query_ast.ml | 30 +++++++++++ query/query_parser.ml | 11 ++-- query/sort.ml | 113 +++++++++++++++++++++++++++++++++++++++++- www/www.ml | 4 +- 7 files changed, 204 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3597c79504..54c966b354 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ **Try it online at [doc.sherlocode.com](https://doc.sherlocode.com) !** A rough prototype of a Hoogle-like search engine for OCaml documentation. It's full of bugs and todos, but works well enough for my purpose: Perhaps it will be useful to you too. -- The fuzzy type search is supported by a polarity search. As an example, the type `string -> int -> char` gets simplified to `{ -string, -int, +char }` which means that it consumes a `string` and an `int` and produces a `char` (irrespective of the order of the arguments). This yields good search results, but the sorting could be improved. +- The fuzzy type search is supported by a polarity search. As an example, the type `string -> int -> char` gets simplified to `{ -string, -int, +char }` which means that it consumes a `string` and an `int` and produces a `char` (irrespective of the order of the arguments). This yields good candidates which are then sorted by similarity with the query. - The real magic is all the package documentation generated for [`ocaml.org/packages`](https://ocaml.org/packages), which I got my hands on thanks to insider trading (but don't have the bandwidth to share back... sorry!) ``` diff --git a/db/types.ml b/db/types.ml index 3c3fc4c259..8f98e0deda 100644 --- a/db/types.ml +++ b/db/types.ml @@ -3,6 +3,7 @@ module Elt = struct { cost : int ; name : string ; str_type : string + ; type_paths : string list list ; doc : Html_types.li_content_fun Tyxml.Html.elt option ; pkg : string * string } diff --git a/index/load_doc.ml b/index/load_doc.ml index c7e59fe9fb..e0c5c3f1c6 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -50,12 +50,52 @@ let rec tails = function | [] -> [] | _ :: xs as lst -> lst :: tails xs +let fullname t = + Pretty.fmt_to_string (fun h -> Pretty.show_type_name_verbose h t) + let all_type_names t = - let fullname = - Pretty.fmt_to_string (fun h -> Pretty.show_type_name_verbose h t) - in + let fullname = fullname t in tails (String.split_on_char '.' fullname) +let rec paths ~prefix ~sgn = function + | Odoc_model.Lang.TypeExpr.Var _ -> + let poly = Cache_name.memo "POLY" in + [ poly :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix ] + | Any -> + let poly = Cache_name.memo "POLY" in + [ poly :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix ] + | Arrow (_, a, b) -> + let prefix_left = Cache_name.memo "->0" :: prefix in + let prefix_right = Cache_name.memo "->1" :: prefix in + List.rev_append + (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) + (paths ~prefix:prefix_right ~sgn b) + | Constr (name, args) -> + let name = fullname name in + let prefix = + Cache_name.memo name + :: Cache_name.memo (Types.string_of_sgn sgn) + :: prefix + in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = Cache_name.memo (string_of_int i) :: prefix in + paths ~prefix ~sgn arg) + args + end + | Tuple args -> + rev_concat + @@ List.mapi (fun i arg -> + let prefix = Cache_name.memo (string_of_int i ^ "*") :: prefix in + paths ~prefix ~sgn arg) + @@ args + | _ -> [] + let rec type_paths ~prefix ~sgn = function | Odoc_model.Lang.TypeExpr.Var _ -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] @@ -107,8 +147,15 @@ let save_item ~pkg ~path_list ~path name type_ doc = | _ -> 0) + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 in + let paths = paths ~prefix:[] ~sgn:Pos type_ in let str_type = - { Db.Elt.name = full_name; cost; str_type = Cache.memo str_type; doc; pkg } + { Db.Elt.name = full_name + ; cost + ; type_paths = paths + ; str_type = Cache.memo str_type + ; doc + ; pkg + } in let my_full_name = List.rev_append @@ -117,8 +164,8 @@ let save_item ~pkg ~path_list ~path name type_ doc = in let my_full_name = List.map Char.lowercase_ascii my_full_name in Db.store_name my_full_name str_type ; - Db.store_all str_type - (List.map (List.map Cache_name.memo) (type_paths ~prefix:[] ~sgn:Pos type_)) + let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in + Db.store_all str_type (List.map (List.map Cache_name.memo) type_paths) let rec item ~pkg ~path_list ~path = let open Odoc_model.Lang in diff --git a/query/query_ast.ml b/query/query_ast.ml index 29de7eeb21..a53ca4deb0 100644 --- a/query/query_ast.ml +++ b/query/query_ast.ml @@ -6,6 +6,36 @@ type t = | Any [@@deriving show] +let rec paths_arrow ~prefix ~sgn = function + | Poly _ -> [ "POLY" :: Db.Types.string_of_sgn sgn :: prefix ] + | Any -> [ prefix ] + | Arrow (a, b) -> + let prefix_left = "->0" :: prefix in + let prefix_right = "->1" :: prefix in + List.rev_append + (paths_arrow ~prefix:prefix_left ~sgn:(Db.Types.sgn_not sgn) a) + (paths_arrow ~prefix:prefix_right ~sgn b) + | Constr (name, args) -> + let prefix = name :: Db.Types.string_of_sgn sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + List.concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + paths_arrow ~prefix ~sgn arg) + args + end + | Tuple args -> + List.concat + @@ List.mapi + (fun i arg -> + let prefix = (string_of_int i ^ "*") :: prefix in + paths_arrow ~prefix ~sgn arg) + args + let rec paths ~prefix ~sgn = function | Poly _ -> [ "POLY" :: Db.Types.string_of_sgn sgn :: prefix ] | Any -> [ prefix ] diff --git a/query/query_parser.ml b/query/query_parser.ml index 9dbd35ec3d..11becbe881 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -23,16 +23,17 @@ let of_string str = | _ when guess_type_search str -> true, "", str | _ -> false, str, "" in - let pretty, ps = + let pretty, ps, ps_arrow = match parse str_typ with - | Any -> "_", [] + | Any -> "_", [], [] | typ -> ( Query_ast.show typ , List.filter (fun s -> List.length s > 0) - (paths ~prefix:[] ~sgn:Db.Types.Pos typ) ) - | exception _ -> "", [] + (paths ~prefix:[] ~sgn:Db.Types.Pos typ) + , paths_arrow ~prefix:[] ~sgn:Db.Types.Pos typ ) + | exception _ -> "", [], [] in let keywords = naive_of_string str_name in let keywords_pretty = String.concat " " keywords in - ok, keywords, ps, keywords_pretty ^ " : " ^ pretty + ok, keywords, ps, ps_arrow, keywords_pretty ^ " : " ^ pretty diff --git a/query/sort.ml b/query/sort.ml index 70bf40b86e..2256d81d30 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -34,11 +34,120 @@ let score_name query_name name = (fun acc query_name -> acc + score_name query_name name) 0 query_name -let by_name query_name results = +let distance xs ys = + let len_xs = List.length xs in + let len_ys = List.length ys in + let cache = Array.make_matrix (1 + len_xs) (1 + len_ys) (-1) in + let rec memo i j xs ys = + let r = cache.(i).(j) in + if r >= 0 + then r + else begin + let r = go i j xs ys in + cache.(i).(j) <- r ; + r + end + and go i j xs ys = + match xs, ys with + | [], _ -> 0 + | [ "_" ], _ -> 0 + | _, [] -> List.length xs + | x :: xs, y :: ys when String.ends_with ~suffix:x y -> + memo (i + 1) (j + 1) xs ys + | _, "->1" :: ys -> memo i (j + 1) xs ys + | "->1" :: xs, _ -> 1 + memo (i + 1) j xs ys + | _ :: xs', _ :: ys' -> + 7 + + min + (memo (i + 1) (j + 1) xs' ys') + (min (memo (i + 1) j xs' ys) (memo i (j + 1) xs ys')) + in + go 0 0 xs ys + +let minimize = function + | [] -> 0 + | arr -> + let used = Array.make (List.length (List.hd arr)) false in + let arr = + Array.map (fun lst -> + let lst = (1, None) :: List.mapi (fun i x -> x, Some i) lst in + List.sort Stdlib.compare lst) + @@ Array.of_list arr + in + Array.sort (fun xs ys -> Stdlib.compare xs ys) arr ; + let heuristics = Array.make (Array.length arr + 1) 0 in + for i = Array.length heuristics - 2 downto 0 do + let best = fst (List.hd arr.(i)) in + heuristics.(i) <- heuristics.(i + 1) + best + done ; + let best = ref 1000 in + let limit = ref 0 in + let rec go rem acc i = + incr limit ; + if !limit > 10_000 + then false + else if rem <= 0 + then begin + let score = acc + (1 * (Array.length arr - i)) in + best := min score !best ; + true + end + else if i >= Array.length arr + then begin + best := min !best (acc + (100 * rem)) ; + true + end + else if acc + heuristics.(i) >= !best + then true + else + let rec find = function + | [] -> true + | (cost, j) :: rest -> + let ok = + match j with + | None -> + go rem + (acc + cost + + if rem > Array.length arr - i then 100 else 0) + (i + 1) + | Some j -> + if used.(j) + then true + else begin + used.(j) <- true ; + let ok = go (rem - 1) (acc + cost) (i + 1) in + used.(j) <- false ; + ok + end + in + if ok then find rest else false + in + find arr.(i) + in + let _ = go (Array.length used) 0 0 in + !best + +let score_type query_type paths = + match paths, query_type with + | _, [] | [], _ -> 0 + | _ -> + let arr = + List.map + (fun p -> + let p = List.rev p in + List.map (fun q -> distance (List.rev q) p) query_type) + paths + in + minimize arr + +let list query_name query_type results = let results = List.map (fun a -> - let cost = a.Elt.cost + (2 * score_name query_name a.Elt.name) in + let open Elt in + let name_cost = score_name query_name a.name in + let type_cost = score_type query_type a.type_paths in + let cost = a.Elt.cost + (2 * name_cost) + (800 * type_cost) in { a with cost }) results in diff --git a/www/www.ml b/www/www.ml index c3cdb00e42..37972a8902 100644 --- a/www/www.ml +++ b/www/www.ml @@ -24,12 +24,12 @@ open Lwt.Syntax module H = Tyxml.Html let api raw_query = - let has_typ, query_name, query_typ, pretty = + let has_typ, query_name, query_typ, query_typ_arrow, pretty = Query.Parser.of_string raw_query in let* results = search (has_typ, query_name, query_typ) in let+ results = Succ.to_list results in - let results = Sort.by_name query_name results in + let results = Sort.list query_name query_typ_arrow results in Ui.render ~pretty results let api query = From 95ed0f4474187c08bd331b99d3472feaa610d325 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 30 Oct 2022 17:12:19 +0100 Subject: [PATCH 009/285] package categories (first draft) --- static/packages.csv | 4013 +++++++++++++++++++++++++++++++++++++++++++ static/style.css | 37 +- www/packages.ml | 162 ++ www/ui.ml | 1 + 4 files changed, 4212 insertions(+), 1 deletion(-) create mode 100644 static/packages.csv create mode 100644 www/packages.ml diff --git a/static/packages.csv b/static/packages.csv new file mode 100644 index 0000000000..8c91066bd1 --- /dev/null +++ b/static/packages.csv @@ -0,0 +1,4013 @@ +ai aifad "AIFAD - Automated Induction of Functions over Algebraic Datatypes" +ai caisar "Implements a caching service for storing arbitrary strings that can be located by string keys" +ai caisar-nnet "NNet parser for CAISAR" +ai caisar-onnx "ONNX parser for CAISAR" +ai caisar-ovo "OVO parser for CAISAR" +ai dsfo "Download (anyhow) and interact (ocaml, utop) with common machine learning datasets." +ai libsvm "LIBSVM bindings for OCaml" +ai libtensorflow "TensorFlow library package" +ai libtorch "LibTorch library package" +ai linwrap "Wrapper on top of liblinear-tools" +ai odnnr "Regressor using a Deep Neural Network" +ai openai-gym "OCaml binding for openai Gym toolkit" +ai tensorflow "TensorFlow bindings for OCaml" +ai torch "PyTorch bindings for OCaml" +app 0install-gtk "Decentralised installation system - GTK UI" +app 0install "The antidote to app-stores" +app advi "Active DVI Dune package!" +app apalogretrieve +app aperf "OCaml tools for loop perforation" +app asak "Partitioning OCaml codes" +app ask "Create/Answer questionnaires" +app ask-integrator "Link questionnaires to an uuid of 'a type" +app benchpress-server "Server and web UI for benchpress" +app benchpress "Tool to run one or more logic programs, on a set of files, and collect the results" +app bibtex2html "BibTeX to HTML translator" +app bigbro "Management tool for hypertext (HTML) documents" +app bnfgen +app bracetax "Simple and deterministic text processing syntax" +app bytepdf "Tool to create PDFs that are also OCaml bytecodes" +app camels "A game about camels" +app caml2html "Produce ready-to-go HTML files" +app certify "CLI utilities for simple X509 certificate manipulation" +app chamo "Chamo is a source code editor, even if it can be used to edit any text file" +app coccinelle "Coccinelle is a C source code matching and transformation engine" +app comby "A tool for structural code search and replace that supports ~every language" +app comby-kernel "A match engine for structural code search and replace that supports ~every language" +app comby-semantic "A match engine for structural code search and replace that supports ~every language" +app conex "Establish trust in community repositories" +app conex-mirage-crypto "Establishing trust in community repositories: crypto provided via mirage-crypto" +app conex-nocrypto "Establishing trust in community repositories: crypto provided via nocrypto" +app csvtool "Command line tool for handling CSV files" +app ctoxml "Parses a C program into Cabs AST and dumps as an XML document" +app diskuvbox "Cross-platform basic set of script commands" +app diy "Tool suite for testing shared memory models" +app doculib "A GUI for tagging and managing document metadata for books, textbooks, or articles" +app dog "A loyal and faithful synchronisation tool that you can rely on." +app doi2bib "Small CLI to get a bibtex entry from a DOI, an arXiv ID or a PubMed ID" +app DrawGrammar "Draw railroad diagrams of EBNF grammars" +app elasticsearch-cli "Command-line client for Elasticsearch" +app elf2json "Converts an ELF binary to a JSON representation" +app freetennis "Free Tennis, a free tennis simulation." +app fury-puyo "Fury Puyo is a free clone of the Puyo Puyo game." +app gadelac "Preprocessor for the Game Description Language." +app gappa "Tool intended for formally proving properties on numerical programs dealing with floating-point or fixed-point arithmetic" +app hxd "Hexdump in OCaml" +app lab "GitLab cli" +app learn-ocaml-client "The learn-ocaml client" +app learn-ocaml "The learn-ocaml online platform (engine)" +app ledit "Line editor, a la rlwrap" +app merge-fmt "Git mergetool leveraging code formatters" +app mpp "MPP is both a preprocessor and a meta preprocessor" +app nebula "DCPU-16 emulator" +app ocal "An improved Unix `cal` utility" +app ocaml-probes "USDT probes for OCaml: command line tool" +app oclaunch "Command-line program allowing you to launch program on a human basis. Don't let a clock plan things!" +app opass "A simple command line tool for storing, retreiving," +app opomodoro "A simple Pomodoro timer" +app orpie "Curses-based RPN calculator" +app otetris "Tetris game implemented in OCaml language." +app owork "A productivity timer for focusing on work" +app pardi "Parallel execution of command lines, pardi!" +app passmakercmd "Command line utility for generating memorable passphrases" +app planets "A simple interactive program for playing with simulations of planetary systems" +app tcalc "Minimal desktop calculator for timestamps" +app telltime "Cli tool for interacting with Daypack-lib components" +app tldr "An ocaml tldr client" +app tryocaml "Easiest way to learn how to code in OCaml language" +app valentine "Validate HTML from command line" +app vimebac "Vimebac is graphical metronome and instructions display that interfaces with JACK-midi applications" +app wyrd "Text-based front-end to Remind, a sophisticated calendar and alarm program" +ascii ascii85 +ascii base32 "Base32 encoding for OCaml" +ascii base58 "Base58 encoding and decoding" +ascii base64 "Base64 encoding for OCaml" +ascii hex_encode "Hexadecimal encoding library" +ascii hex "Library providing hexadecimal converters" +ascii hexstring "A library to encode to and decode from hexadecimal strings" +ascii pp-binary-ints "Pretty Printing Binary Integers" +audio aacplus +audio alsa +audio ao +audio bjack +audio cue_sheet_maker "A library to create cue sheet" +audio dssi "Bindings for the DSSI API which provides audio synthesizers" +audio faad "Bindings for the faad library which provides functions for decoding AAC audio files" +audio fdkaac "Fraunhofer FDK AAC Codec Library" +audio flac "Bindings to libflac" +audio ladspa "Bindings for the LADSPA API which provides audio effects" +audio lame "MP3 encoding library" +audio lastfm "The lastfm library is an implementation of the API used by the last.fm to keep count of played songs" +audio lilv "Bindings to lilv library for using LV2 audio plugins" +audio mad "Mad decoding library" +audio misuja "A library to drive the MIDI system of the Jack Audio Connection Kit." +audio mkaudio "CLI program for generating audio files" +audio ml2mxml "Generate musicxml files from OCaml" +audio mpg123 "MP3 decoding library" +audio ogg "Bindings to libogg" +audio opus "Bindings to libopus" +audio osc-lwt "OpenSoundControl Lwt library" +audio osc "OpenSoundControl core library" +audio osc-unix "OpenSoundControl Unix library" +audio portaudio +audio portaudio_c_bindings "Bindings to the C PortAudio library" +audio portmidi "Bindings to libportmidi" +audio pulseaudio "Bindings to Pulseaudio client library" +audio samplerate "Samplerate audio conversion library" +audio sdl-liquidsoap "Virtual package installing liquidsoap's sdl dependencies" +audio shine "Fixed-point MP3 encoder" +audio soundtouch +audio speex "Bindings to libspeex" +audio vecosek "" +audio vecosek-engine "" +audio vecosek-scene "" +audio voaacenc "Bindings for the voaacenc library to encode audio files in AAC format" +audio vorbis "Bindings to libvorbis" +audio xmlplaylist "Library to parse various file playlists in XML format" +bap bap-abi "BAP ABI integration subsystem" +bap bap-analyze "Implements the analyze command" +bap bap-api "A pass that adds parameters to subroutines based on known API" +bap bap-arm "BAP ARM lifter and disassembler" +bap bap-beagle "BAP obfuscated string solver" +bap bap-beagle-strings "Finds strings of characters using microexecution" +bap bap-bil "Controls the BIL transformation pipeline" +bap bap "Binary Analysis Platform" +bap bap-build "BAP build automation tools" +bap bap-bundle "BAP bundler" +bap bap-byteweight "BAP facility for indentifying code entry points" +bap bap-byteweight-frontend "BAP Toolkit for training and controlling Byteweight algorithm" +bap bap-cache "BAP caching service" +bap bap-c "A C language support library for BAP" +bap bap-callgraph-collator "Collates programs based on their callgraphs" +bap bap-callsites "Inject data definition terms at callsites" +bap bap-constant-tracker "Constant Tracking Analysis based on Primus" +bap bap-core "Binary Analysis Platform" +bap bap-core-theory "BAP Semantics Representation" +bap bap-cxxfilt "A demangler that relies on a c++filt utility" +bap bap-dead-code-elimination "A BAP plugin that removes dead IR code" +bap bap-demangle "Provides names service and demangling facilities" +bap bap-dependencies "Analyzes program dependencies" +bap bap-disassemble "Implements the disassemble command" +bap bap-dump-symbols "BAP plugin that dumps symbols information from a binary" +bap bap-dwarf "BAP DWARF parsing library" +bap bap-elementary "BAP floating point approximations of elementary functions" +bap bap-elf "BAP ELF parser and loader written in native OCaml" +bap bap-emacs-dot +bap bap-emacs-goodies "A collection of useful Emacs tools for BAP" +bap bap-emacs-mode "Emacs major mode for reading and analyzing programs in BAP's IR" +bap bap-extra "Binary Analysis Platform" +bap bap-flatten "A BAP plugin, that translates a program into the flatten form" +bap bap-frames "A data format for storing execution traces" +bap bap-frontc "A C language frontend for based on FrontC library" +bap bap-frontend "BAP frontend" +bap bap-fsi-benchmark "BAP function start identification benchmark game" +bap bap-future "A library for asynchronous values" +bap bap-ghidra "BAP Ghidra backend" +bap bap-glibc-runtime "Detects the presence of glibc runtime" +bap bap-ida "An IDA Pro integration library" +bap bap-ida-plugin "Plugins for IDA and BAP integration" +bap bap-ida-python "A BAP - IDA Pro integration library" +bap bap-knowledge "Knowledge Representation Library" +bap bap-llvm "BAP LLVM backend" +bap bap-main "Build BAP Main Framework Configuration Library" +bap bap-mc "BAP machine instruction playground" +bap bap-microx "A micro execution framework" +bap bap-mips "BAP MIPS lifter" +bap bap-objdump "Extract symbols from binary, using binutils objdump" +bap bap-optimization "A BAP plugin that removes dead IR code" +bap bap-patterns "Applies semantic actions to the matching byte patterns" +bap bap-phoenix "BAP plugin that dumps information in a phoenix decompiler format" +bap bap-piqi "BAP plugin for serialization based on piqi library" +bap bap-plugins "BAP plugins support library" +bap bap-powerpc "BAP PowerPC lifter" +bap bap-primus-dictionary "BAP Primus Lisp library that provides dictionaries" +bap bap-primus-exploring-scheduler "Evaluates all machines, prioritizing the least visited" +bap bap-primus-greedy-scheduler "Evaluates all machines in the DFS order" +bap bap-primus-limit "Ensures termination by limiting Primus machines" +bap bap-primus-lisp "BAP Primus Lisp Runtime" +bap bap-primus-loader "Generic program loader for Primus" +bap bap-primus-mark-visited "Registers the bap:mark-visited component" +bap bap-primus-powerpc "Performs the PowerPC target specific setup" +bap bap-primus-print "Prints Primus states and observations" +bap bap-primus-promiscuous "Enables the promiscuous mode of execution" +bap bap-primus-propagate-taint "A compatibility layer between different taint analysis frameworks" +bap bap-primus-random "Provides components for Primus state randomization" +bap bap-primus-region +bap bap-primus-round-robin-scheduler "Evaluates all machines in the BFS order" +bap bap-primus-support "Provides supporting components for Primus" +bap bap-primus-symbolic-executor "Primus Symbolic Executor" +bap bap-primus-systems "Loads Primus systems and registers them in the system repository" +bap bap-primus-taint "A taint analysis control interface" +bap bap-primus-test "BAP Primus Testing and Program Verification module" +bap bap-primus "The BAP Microexecution Framework" +bap bap-primus-track-visited "Tracks basic blocks visited by Primus" +bap bap-primus-wandering-scheduler "Evaluates all machines while" +bap bap-primus-x86 "The x86 CPU support package for BAP Primus CPU emulator" +bap bap-print "Print plugin - print project in various formats" +bap bap-radare2 "Extract symbols from binary using radare2" +bap bap-raw "Provides a loader for raw binaries" +bap bap-recipe-command "Provides commands to manipulate the recipe subsystem" +bap bap-recipe "Stores command line parameters and resources in a single file" +bap bap-relation "A set of relations (bimap)" +bap bap-relocatable "Extracts symbolic information from the program relocations" +bap bap-report "A BAP plugin that reports program status" +bap bap-riscv "BAP RISCV lifter and disassembler" +bap bap-run "A BAP plugin that executes a binary" +bap bap-saluki +bap bap-server "BAP RPC server" +bap bap-signatures "A data package with binary signatures for BAP" +bap bap-specification "Implements the specification command" +bap bap-ssa "A BAP plugin, that translates a program into the SSA form" +bap bap-std "The Binary Analysis Platform Standard Library" +bap bap-strings "Text utilities useful in Binary Analysis and Reverse Engineering" +bap bap-stub-resolver "Identifies and manages stub functions in a binary" +bap bap-symbol-reader "BAP plugin that reads symbol information from files" +bap bap-systemz "A target support package for the Systemz (Z9) ISA" +bap bap-taint "BAP Taint Analysis Framework" +bap bap-taint-propagator "BAP Taint propagation engine using based on microexecution" +bap bap-term-mapper "A BAP DSL for mapping program terms" +bap bap-thumb "A target support package for the Thumb instruction set" +bap bap-toplevel "BAP toplevel, baptop" +bap bap-trace "A plugin to load and run program execution traces" +bap bap-traces "BAP Library for loading and parsing execution traces" +bap bap-trivial-condition-form "Eliminates complex conditionals in branches" +bap bap-veri "BAP verification tool" +bap bap-warn-unused +bap bap-x86 "BAP x86 lifter" +bap bare "BAP Rule Engine Library" +bap cbat-explicit-edge "VSA-based CFG edge reconstruction made in bap ecosystem" +bap cbat-tools "Program analysis tools developed at Draper on the CBAT project" +bap cbat-vsa "Value set analysis made in bap ecosystem" +bap cwe_checker "BAP plugin collection to detect common bug classes" +bap unisim_archisec "UNISIM-VP DBA decoder" +bench bechamel-js "HTML generator for bechamel's output" +bench bechamel-notty "CLI generator for bechamel's output" +bench bechamel-perf "Linux perf's metrics for bechamel" +bench bechamel "Yet Another Benchmark in OCaml" +bench bench "A benchmarking tool for statistically valid benchmarks" +bench benchmark "Benchmark running times of code" +bench core_bench "Benchmarking library" +bench core_profiler "Profiling library" +bench operf-macro "Macro benchmarking tool" +bench operf-micro "Simple tool for benchmarking the OCaml compiler" +bench orun "Run benchmarks and measure performance" +bench pa_bench "Syntax extension for inline benchmarks" +bench rungen "Generates dune files to run benchmarks from centralised config" +bindings fontforge-of-ocaml "OCaml binding of FontForge" +bindings fzf "A library for running the fzf command line tool" +bindings gemini "OCaml bindings for Gemini Trading Exchange API" +bindings geoip "Bindings to GeoIP database library." +bindings github-data "GitHub APIv3 data library" +bindings github "GitHub APIv3 OCaml library" +bindings github-hooks "GitHub API web hook listener library" +bindings github-hooks-unix "GitHub API web hook listener library using unix functions" +bindings github-jsoo "GitHub APIv3 JavaScript library" +bindings github-unix "GitHub APIv3 Unix library" +bindings gitlab "GitLab APIv4 OCaml library" +bindings gitlab-jsoo "Gitlab APIv4 OCaml library" +bindings gitlab_pipeline_notifier +bindings gitlab-unix "GitLab APIv4 OCaml library" +bindings hockmd "A library to access hackmd's api" +bindings mmdb "Binding to the MaxMind DB library for GeoIP lookups" +bindings moss "A client for the MOSS plagiarism detection service." +bindings otoggl "Bindings for Toggl API in OCaml" +bindings reddit_api_async "Async connection and utility functions for Reddit's API" +bindings reddit_api_kernel "OCaml types for Reddit's API" +bindings slack-backup "Small tool to backup IM and channels from slack." +bindings slacko "Access the Slack API" +bindings socialpeek "OCaml library to extract social information such as Twitter cards or OpenGraph data from webpages and HTML." +bindings sociaml-facebook-api "Facebook Graph API Client Library for OCaml" +bindings sociaml-oauth-client "OAuth Client Library for Ocaml" +bindings sociaml-tumblr-api "Tumblr API Client Library for OCaml" +bindings sociaml-vcard "vCard library for OCaml" +bindings spotify-cli "CLI program for controlling the Spotify client on Linux and OSX" +bindings spotify-web-api "OCaml bindings to the Spotify web API" +bindings sturgeon "A toolkit for communicating with Emacs" +bindings telegraml "Telegram Bot API for OCaml" +bindings themoviedb "API for TheMovieDb.org website" +bindings wcs-api "SDK for Watson Conversation Service" +bindings wcs "Command line interface for Watson Conversation Service" +bindings wcs-lib "SDK for Watson Conversation Service" +bio biocaml "The OCaml Bioinformatics Library" +bio bio_io +bio biotk "Bioinformatics toolkit" +bio bistro-bio "Bistro workflows for computational biology" +build base-ocamlbuild +build bsdowl "This collection of BSD Make directives aims at providing a highly" +build conjury "Conjury library for OMake" +build dune-action-plugin "[experimental] API for writing dynamic Dune actions" +build dune-build-info "Embed build informations inside executable" +build dune-configurator "Helper library for gathering system configuration" +build dune-deps "Show dependency graph of a multi-component dune project" +build dune-expand "Tool to view ppx-expanded OCaml source files" +build dune "Fast, portable, and opinionated build system" +build dune-glob "Glob string matching language supported by dune" +build dune-private-libs "Private libraries of Dune" +build dune-release "Release dune packages in opam" +build dune-rpc "Communicate with dune using rpc" +build dune-rpc-lwt "Communicate with dune using rpc and Lwt" +build dune-site "Embed locations informations inside executable and libraries" +build dune_watch +build jbuilder +build jenga "Industrial strength, full-featured build system" +build js-build-tools "Collection of tools to help building Jane Street Packages" +build jst-config "Compile-time configuration for Jane Street libraries" +build mybuild "Collection of ocamlbuild plugins (extprot, atdgen, ragel, etc) and utility to generate version from VCS" +build obi "interface to OCaml Build Infrastructure" +build ocamlbuild +build ocamlbuild-atdgen "Atdgen plugin for OCamlbuild" +build ocamlbuild-pkg "An ocamlbuild plugin that helps packaging softwares." +build ocamlbuild-protoc "ocaml-protoc plugin for Ocamlbuild" +build ocaml-makefile "Generic Makefile for building OCaml projects" +build ocb-stubblr "OCamlbuild plugin for C stubs" +build omake "Build system designed for scalability and portability." +build pds "A tool to build Makefiles for Ocaml projects" +build rmlbuild "rmlbuild is a fork of ocamlbuild that handles ReactiveML projets" +build solvuu_build "DEPRECATED. Please use solvuu-build." +build solvuu-build "Solvuu's build system." +chemistry acpc "Chemoinformatics tool for ligand-based virtual screening" +cloud aws "Amazon Web Services SDK" +cloud aws-async "Amazon Web Services SDK bindings for async" +cloud aws-autoscaling "Amazon Web Services SDK bindings to Auto Scaling" +cloud aws-cloudformation "Amazon Web Services SDK bindings to AWS CloudFormation" +cloud aws-cloudtrail "Amazon Web Services SDK bindings to AWS CloudTrail" +cloud aws-cloudwatch "Amazon Web Services SDK bindings to Amazon CloudWatch" +cloud aws-config "Read AWS configuration in OCaml" +cloud aws-ec2 "Amazon Web Services SDK bindings to Amazon Elastic Compute Cloud" +cloud aws-elasticache "Amazon Web Services SDK bindings to Amazon ElastiCache" +cloud aws-elasticloadbalancing "Amazon Web Services SDK bindings to Elastic Load Balancing" +cloud aws-lwt "Amazon Web Services SDK bindings for lwt" +cloud aws-rds "Amazon Web Services SDK bindings to Amazon Relational Database Service" +cloud aws-route53 "Amazon Web Services SDK bindings to Amazon Route 53" +cloud aws-s3-async "Ocaml library for accessing Amazon S3 - Async version" +cloud aws-s3-lwt "Ocaml library for accessing Amazon S3 - Lwt version" +cloud aws-s3 "Ocaml library for accessing Amazon S3" +cloud aws-sdb "Amazon Web Services SDK bindings to Amazon SimpleDB" +cloud aws-sqs "Amazon Web Services SDK bindings to Amazon Simple Queue Service" +cloud aws-ssm "Amazon Web Services SDK bindings to Amazon Simple Systems Management Service" +cloud aws-sts "Amazon Web Services SDK bindings to AWS Security Token Service" +cloud azblob-async "A trivial Azure Blob Storage interface for OCaml" +cloud azblocloud "A trivial Azure Blob Storage interface for OCaml" +cloud azure-cosmos-db "Azure cosmos db interface" +cloud cloudi "OCaml CloudI API" +cloud coclobas "Coclobas is a scheduler for HPC-like jobs accessible through HTTP" +cloud distributed "Library to provide Erlang style distributed computations. This library is inspired by Cloud Haskell" +cloud distributed-lwt "A library to probide a lwt based implementation of Distributed" +cloud distributed-uwt "A library to probide a uwt based implementation of Distributed" +cloud equinoxe "An OCaml wrapper for the Equinix API" +cloud equinoxe-cohttp "Equinoxe with the cohttp-lwt-unix request handler" +cloud equinoxe-hlc "Equinoxe with the http-lwt-client request handler" +cloud gapi-ocaml "A simple OCaml client for Google Services" +cloud google-drive-ocamlfuse "A FUSE filesystem over Google Drive" +cloud libres3 "Amazon S3 compatible server" +cloud vercel "A custom runtime for Vercel.com (Now v2) written in OCaml" +cloud vrt "A setup command line tools to help with development on remote AWS desktops" +color color-brewery "Offer colors palettes and functions to brew colors" +color color "Converts between different color formats" +color spectrum "Library for colour and formatting in the terminal" +compression brotli "Bindings to Google's Brotli compresion algorithm" +compression brozip +compression camlbz2 "Bindings for bzip2" +compression camlzip "Accessing compressed files in ZIP, GZIP and JAR format" +compression clz "Compression support for cohttp-lwt client using decompress" +compression decompress "Implementation of Zlib and GZip in OCaml" +compression ezgzip "Simple gzip (de)compression library" +compression js-lz4 "Barebones bindings for the LZ4 C api" +compression lz4 "Bindings to the LZ4 compression algorithm" +compression lz4_chans "LZ4-compressed binary channels" +compression lzo "Bindings to LZO - a portable lossless data compression library" +compression rfc1951 "Implementation of RFC1951 in OCaml" +compression snappy "Bindings to snappy - fast compression/decompression library" +compression tar "Decode and encode tar format files in pure OCaml" +compression tar-format "Decode and encode tar files" +compression tar-mirage "Read and write tar format files via MirageOS interfaces" +compression tar-unix "Decode and encode tar format files from Unix" +compression zlib "Bindings to the zlib compression library" +compression zstandard "OCaml bindings to Zstandard" +compression zstd "Bindings to zstd compression library" +conf conf-aclocal "Virtual package relying on aclocal" +conf conf-adwaita-icon-theme "Virtual package relying on adwaita-icon-theme" +conf conf-alsa "Virtual package relying on alsa" +conf conf-ao "Virtual package relying on libao" +conf conf-asciidoc "Virtual package relying on asciidoc" +conf conf-autoconf "Virtual package relying on autoconf installation" +conf conf-automake "Virtual package relying on GNU automake" +conf conf-bap-llvm "Virtual package relying on llvm library installation for BAP" +conf conf-binutils "Checks that binutils are installed" +conf conf-bison "Virtual package relying on GNU bison" +conf conf-blas "Virtual package for BLAS configuration" +conf conf-bluetooth "Virtual package for Bluetooth library" +conf conf-bmake "Virtual package relying on a BSD Make compatible program" +conf conf-boost "Virtual package relying on boost" +conf conf-brotli "Virtual package relying on a brotli system installation" +conf conf-cairo "Virtual package relying on a Cairo system installation" +conf conf-capnproto "Virtual package relying on captnproto installation" +conf conf-clang "Virtual package relying on clang" +conf conf-cmake "Virtual package relying on cmake" +conf conf-cosmopolitan "Virtual package relying on APE/Cosmopolitan" +conf conf-cpio "Virtual package relying on cpio" +conf conf-csdp "Virtual package relying on a CSDP binary system installation" +conf conf-c++ "Virtual package relying on the c++ compiler" +conf conf-dbm "Virtual package relying on gdbm" +conf conf-diffutils "Virtual package relying on diffutils" +conf conf-dkml-cross-toolchain "Add findlib toolchains for all installed DKML cross-compilers" +conf conf-dpkg "Virtual package relying on dpkg" +conf conf-dssi "Virtual package relying on dssi" +conf conf-efl "Virtual package relying on the EFL system installation" +conf conf-emacs "Virtual package to install the Emacs editor" +conf conf-env-travis "Detect Travis CI and lift its environment to opam" +conf conf-expat "Virtual package relying on an expat system installation" +conf conf-faad "Virtual package relying on libfaad" +conf conf-ffmpeg "Virtual package relying on FFmpeg" +conf conf-fftw3 "Virtual package relying on a FFTW3 lib system installation" +conf conf-findutils "Virtual package relying on findutils" +conf conf-flex "Virtual package relying on GNU flex" +conf conf-freetype "Virtual package relying on a freetype lib system installation" +conf conf-frei0r "Virtual package relying on frei0r" +conf conf-fswatch "Virtual package relying on libfswatch installation" +conf conf-ftgl "Virtual package relying on an ftgl system installation" +conf conf-fts "Virtual package relying on the fts.h header" +conf conf-gcc "Virtual package relying on the gcc compiler (for C)" +conf conf-gd "Virtual package relying on a libgd system installation" +conf conf-gfortran "Virtual package relying on a gfortran system installation" +conf conf-ghostscript "Virtual package relying on ghostscript" +conf conf-git "Virtual package relying on git" +conf conf-glade "Virtual package relying on a libglade system installation" +conf conf-gles2 "Virtual package relying on a OpenGL ES 2 system installation" +conf conf-glew "Virtual package relying on a GLEW system installation" +conf conf-glfw3 "Virtual package relying on a GLFW3 system installation" +conf conf-glib-2 "Virtual package relying on a system GLib 2 installation" +conf conf-glpk "Virtual package for GLPK (GNU Linear Programming Kit)" +conf conf-gmp-powm-sec +conf conf-gmp "Virtual package relying on a GMP lib system installation" +conf conf-gnomecanvas "Virtual package relying on a Gnomecanvas system installation" +conf conf-gnome-icon-theme3 "Virtual package relying on gnome-icon-theme" +conf conf-gnuplot "Virtual package relying on gnuplot installation" +conf conf-gnutls "Virtual package relying on a gnutls system installation" +conf conf-gobject-introspection "Virtual package relying on a system gobject-introspection installation" +conf conf-goocanvas2 "Virtual package relying on a Goocanvas-2 system installation" +conf conf-gpiod "C libgpiod library for GPIO on recent (>4.8) Linux kernels" +conf conf-graphviz "Virtual package relying on graphviz installation" +conf conf-gsl "Virtual package relying on a GSL lib system installation" +conf conf-gssapi "Virtual package relying on a krb5-gssapi system installation" +conf conf-gstreamer "Virtual package relying on libgstreamer" +conf conf-gtk2 "Virtual package relying on gtk2" +conf conf-gtk3 "Virtual package relying on GTK+ 3" +conf conf-gtksourceview3 "Virtual package relying on a GtkSourceView-3 system installation" +conf conf-gtksourceview "Virtual package relying on a GtkSourceView system installation" +conf conf-guile "Virtual package relying on an GNU Guile system installation" +conf conf-g++ "Virtual package relying on the g++ compiler (for C++)" +conf conf-haveged "Check if havaged is installed on the system" +conf conf-hidapi "Virtual package relying on a hidapi system installation" +conf conf-ida "Checks that IDA Pro is installed" +conf config-file "Small library to define, load and save options files." +conf configuration "Analyse configuration files" +conf configurator "Helper library for gathering system configuration" +conf conf-jack "Virtual package relying on jack" +conf conf-jq "Virtual package relying on jq" +conf conf-ladspa "Virtual package relying on ladspa" +conf conf-lame "Virtual package relying on lame" +conf conf-lapack "Virtual package for LAPACK configuration" +conf conf-leveldb "Virtual package relying on a LevelDB lib system installation" +conf conf-libargon2 "Virtual package relying on libargon2" +conf conf-libbz2 "Virtual package relying on libbz2" +conf conf-libclang "Virtual package relying on the installation of llvm and clang libraries (<= 15.0.x)" +conf conf-libcurl "Virtual package relying on a libcurl system installation" +conf conf-libdw "Virtual package relying on libdw" +conf conf-libevent "Virtual package relying on libevent" +conf conf-libev "High-performance event loop/event model with lots of features" +conf conf-libffi "Virtual package relying on libffi system installation" +conf conf-libflac "Virtual package relying on libFLAC" +conf conf-libfontconfig "Virtual package relying on fontconfig" +conf conf-libfuse "Virtual package relying on FUSE" +conf conf-libgif "Virtual package relying on a libgif system installation" +conf conf-libgsasl "Virtual package relying on a GSASL lib system installation" +conf conf-libjpeg "Virtual package relying on a libjpeg system installation" +conf conf-liblinear-tools "Virtual package relying on liblinear-{train|predict} installation" +conf conf-liblo "Virtual package relying on liblo" +conf conf-liblz4 "Virtual package relying on liblz4 system installation" +conf conf-liblzma "Virtual package relying on liblzma" +conf conf-libMagickCore "Virtual package relying on an ImageMagick system installation" +conf conf-libmagic "Virtual package relying on a libmagic system installation" +conf conf-libmaxminddb "Virtual package relying on a libmaxminddb system installation" +conf conf-libmosquitto "Virtual package relying on a libmosquitto system installation" +conf conf-libmpg123 "Virtual package relying on libmpg123" +conf conf-libnl3 "Virtual package relying on a libnl system installation" +conf conf-libogg "Virtual package relying on libogg" +conf conf-libopus "Virtual package relying on libopus" +conf conf-libpcre2-8 "Virtual package relying on a libpcre2 system installation" +conf conf-libpcre "Virtual package relying on a libpcre system installation" +conf conf-libpng "Virtual package relying on a libpng system installation" +conf conf-libportmidi "Virtual package relying on libportmidi" +conf conf-librsvg2 "Virtual package relying on Librsvg2 system installation" +conf conf-libsamplerate "Virtual package relying on libsamplerate" +conf conf-libseccomp "Virtual package relying on a libseccomp system installation" +conf conf-libsodium "Virtual package relying on a libsodium system installation" +conf conf-libspeex "Virtual package relying on libspeex" +conf conf-libssl "Virtual package relying on an OpenSSL library system installation" +conf conf-libsvm-tools "Virtual package relying on libsvm-tools installation" +conf conf-libsvm "Virtual package relying on libsvm library installation" +conf conf-libtheora "Virtual package relying on libtheora" +conf conf-libtool "Virtual package relying on libtool installation" +conf conf-libudev "Virtual package relying on a libudev system installation" +conf conf-libuv "Virtual package relying on a libuv system installation" +conf conf-libvorbis "Virtual package relying on libvorbis" +conf conf-libwayland "Virtual package relying on libwayland" +conf conf-libX11 "Virtual package relying on an Xlib system installation" +conf conf-libxcb-image "Virtual package relying on xcb-image" +conf conf-libxcb-keysyms "Virtual package relying on xcb-shm" +conf conf-libxcb-shm "Virtual package relying on xcb-shm" +conf conf-libxcb "Virtual package relying on xcb" +conf conf-libxcb-xkb "Virtual package relying on xcb-xkb" +conf conf-libxcursor "Virtual package relying on an libXcursor system installation" +conf conf-libxinerama "Virtual package relying on an libXinerama system installation" +conf conf-libxi "Virtual package relying on an libXi system installation" +conf conf-libxrandr "Virtual package relying on an libXRandR system installation" +conf conf-lilv "Virtual package relying on lilv" +conf conf-linux-libc-dev +conf conf-lldb +conf conf-llvm "Virtual package relying on llvm library installation" +conf conf-lua "Virtual package relying on a Lua system installation" +conf conf-lz4 "Virtual package requiring the lz4 command to be available" +conf conf-m4 "Virtual package relying on m4" +conf conf-mad "Virtual package relying on mad" +conf conf-mariadb +conf conf-mbedtls "Virtual package relying on an mbedtls system installation" +conf conf-mecab "Virtual package relying on MeCab library installation" +conf conf-mesa "Virtual package relying on an mesa system installation" +conf conf-mpfr "Virtual package relying on library MPFR installation" +conf conf-mpi "Virtual package relying on a mpi system installation" +conf conf-mysql "Virtual package relying on a libmysqlclient system installation" +conf conf-nanomsg "Virtual package relying on a nanomsg system installation" +conf conf-nauty "Virtual package relying on nauty" +conf conf-ncurses "Virtual package relying on ncurses" +conf conf-neko "Virtual package relying on a Neko system installation" +conf conf-netsnmp "Package relying on net-snmp libs" +conf conf-nlopt "Virtual package relying on nlopt" +conf conf-nmap "Virtual package relying on nmap installation" +conf conf-npm "Virtual package relying on npm installation" +conf conf-numa "Package relying on libnuma" +conf conf-ode "Virtual package relying on a ODE system installation" +conf conf-oniguruma "Virtual package relying on an Oniguruma system installation" +conf conf-openbabel "Virtual package relying on openbabel library installation" +conf conf-openblas "Virtual package to install OpenBLAS and LAPACKE" +conf conf-opencc0 "Virtual package relying on opencc v0 (libopencc.so.1) installation" +conf conf-opencc1_1 "Virtual package relying on opencc v1.1 (libopencc.so.1.1) installation" +conf conf-opencc1 "Virtual package relying on opencc v1 (libopencc.so.2) installation" +conf conf-openimageio "Virtual package relying on OpenImageIO development package installation" +conf conf-openjdk "Virtual package relying on OpenJDK / Javac" +conf conf-openssl "Virtual package relying on an OpenSSL binary system installation" +conf conformist +conf conf-pam "Virtual package relying on a system installation of PAM" +conf conf-pandoc "Virtual package relying on pandoc installation" +conf conf-pango "Virtual package relying on a Pango system installation" +conf conf-perl-ipc-system-simple "Virtual package relying on perl's IPC::System::Simple" +conf conf-perl-string-shellquote "Virtual package relying on perl's String::ShellQuote" +conf conf-perl "Virtual package relying on perl" +conf conf-pic-switch +conf conf-pixz "Virtual package relying on pixz" +conf conf-pkg-config "Check if pkg-config is installed and create an opam switch local pkgconfig folder" +conf conf-plplot "Virtual package relying on plplot" +conf conf-portaudio "Virtual package relying on portaudio" +conf conf-postgresql "Virtual package relying on a PostgreSQL system installation" +conf conf-ppl +conf conf-protoc "Virtual package to install protoc compiler" +conf conf-pulseaudio "Virtual package relying on pulseaudio" +conf conf-python-2-7-dev +conf conf-python-2-7 "Virtual package relying on Python-2.7 installation" +conf conf-python-3-7 "Virtual package relying on Python >=3.7 installation" +conf conf-python-3-dev "Virtual package relying on Python 3 development package installation" +conf conf-python-3 "Virtual package relying on Python-3 installation" +conf conf-python3-yaml "Virtual package relying on PyYAML" +conf conf-qt "Installation of Qt5 using APT packages or from source" +conf conf-radare2 "Checks that radare2 is installed" +conf conf-rdkit "Virtual package relying on rdkit library installation" +conf conf-r-mathlib +conf conf-rocksdb "Virtual package relying on a system installation of RocksDB" +conf conf-ruby "Virtual package relying on Ruby" +conf conf-rust-2018 "Virtual package relying on cargo (rust build system)" +conf conf-rust-2021 "Virtual package relying on cargo (rust build system)" +conf conf-rust "Virtual package relying on cargo (rust build system)" +conf conf-r "Virtual package relying on the R interpreter" +conf conf-samplerate "Virtual package relying on samplerate" +conf conf-sdl2-image "Virtual package relying on a sdl2-image system installation" +conf conf-sdl2-mixer "Virtual package relying on a sdl2-mixer system installation" +conf conf-sdl2-net "Virtual package relying on a sdl2-net system installation" +conf conf-sdl2-ttf "Virtual package relying on a sdl2-ttf system installation" +conf conf-sdl2 "Virtual package relying on a SDL2 system installation" +conf conf-sdl-gfx "Virtual package relying on a sdl-gfx system installation" +conf conf-sdl-image "Virtual package relying on a sdl-image system installation" +conf conf-sdl-mixer "Virtual package relying on a sdl-mixer system installation" +conf conf-sdl-net "Virtual package relying on a sdl-net system installation" +conf conf-sdl-ttf "Virtual package relying on a sdl-ttf system installation" +conf conf-sdpa "Virtual package relying on a SDPA binary system installation" +conf conf-secp256k1 "Virtual package relying on a secp256k1 lib system installation" +conf conf-sfml2 "Virtual package relying on a SFML2 system installation" +conf conf-shine "Virtual package relying on libshine" +conf conf-snappy "Virtual package relying on snappy" +conf conf-soundtouch "Virtual package relying on soundtouch" +conf conf-sqlite3 "Virtual package relying on an SQLite3 system installation" +conf conf-srt-gnutls "Virtual package relying on srt build with gnutls" +conf conf-srt-openssl "Virtual package relying on srt compiled with openssl" +conf conf-srt "Virtual package relying on srt" +conf conf-sundials "Virtual package relying on sundials" +conf conf-swi-prolog "Virtual package to install the swi-prolog interpreter" +conf conf-taglib "Virtual package relying on taglib" +conf conf-tcl "Virtual package relying on tcl" +conf conf-texlive "Virtual package relying on texlive / pdflatex" +conf conf-tidy "Virtual package relying on libtidy installation" +conf conf-timeout "Virtual package relying on the \"timeout\" command" +conf conf-time "Virtual package relying on the \"time\" command" +conf conf-tk "Virtual package relying on tk" +conf conf-tree-sitter "Check if tree-sitter is installed" +conf conf-trexio "Virtual package relying on trexio library installation" +conf conf-tzdata "Virtual package relying on tzdata" +conf conf-vim "Virtual package to install the Vim editor" +conf conf-wayland-protocols "Virtual package relying on wayland-protocols" +conf conf-wget "Virtual package relying on wget" +conf conf-which "Virtual package relying on which" +conf conf-wxwidgets +conf conf-xen +conf conf-xkbcommon "Virtual package relying on xkbcommon" +conf conf-xxhash "Virtual package relying on a xxhash system installation" +conf conf-zig "Virtual package relying on zig" +conf conf-zlib "Virtual package relying on zlib" +conf conf-zmq "Virtual package relying on zmq library installation" +conf conf-zstd "Virtual package relying on zstd" +cordova cordova "Binding OCaml to cordova Javascript object." +cordova cordova-plugin-activity-indicator +cordova cordova-plugin-background-mode "Binding to cordova-plugin-background-mode using gen_js_api." +cordova cordova-plugin-barcode-scanner "Binding OCaml to cordova-plugin-barcode-scanner using gen_js_api." +cordova cordova-plugin-battery-status "Binding OCaml to cordova-plugin-battery-status using gen_js_api." +cordova cordova-plugin-camera "Binding OCaml to cordova-plugin-camera using gen_js_api." +cordova cordova-plugin-clipboard "Binding OCaml to cordova-plugin-clipboard using gen_js_api." +cordova cordova-plugin-datepicker "Binding OCaml to cordova-plugin-datepicker using gen_js_api." +cordova cordova-plugin-device "Binding OCaml to cordova-plugin-device using gen_js_api." +cordova cordova-plugin-device-motion "Binding OCaml to cordova-plugin-device-motion using gen_js_api." +cordova cordova-plugin-device-orientation +cordova cordova-plugin-dialogs "Binding OCaml to cordova-plugin-dialogs using gen_js_api." +cordova cordova-plugin-email-composer "Binding OCaml to cordova-plugin-email-composer using gen_js_api." +cordova cordova-plugin-fcm "Binding OCaml to cordova-plugin-fcm using gen_js_api." +cordova cordova-plugin-file "Binding OCaml to cordova-plugin-file using gen_js_api." +cordova cordova-plugin-file-opener "Binding OCaml to cordova-plugin-file-opener using gen_js_api." +cordova cordova-plugin-file-transfer "Binding OCaml to cordova-plugin-file-transfer using gen_js_api." +cordova cordova-plugin-geolocation "Binding OCaml to cordova-plugin-geolocation using gen_js_api." +cordova cordova-plugin-globalization "Binding OCaml to cordova-plugin-globalization using gen_js_api." +cordova cordova-plugin-image-picker "Binding OCaml to cordova-plugin-image-picker using gen_js_api." +cordova cordova-plugin-inappbrowser "Binding OCaml to cordova-plugin-inappbrowser using gen_js_api." +cordova cordova-plugin-insomnia "Binding OCaml to cordova-plugin-insomnia using gen_js_api." +cordova cordova-plugin-keyboard "Binding OCaml to cordova-plugin-keyboard using gen_js_api." +cordova cordova-plugin-loading-spinner "Binding OCaml to cordova-plugin-loading-spinner using gen_js_api." +cordova cordova-plugin-local-notifications "Binding to cordova-plugin-local-notifications using gen_js_api." +cordova cordova-plugin-media "Binding OCaml to cordova-plugin-media using gen_js_api." +cordova cordova-plugin-media-capture "Binding OCaml to cordova-plugin-media-capture using gen_js_api." +cordova cordova-plugin-network-information +cordova cordova-plugin-progress "Binding OCaml to cordova-plugin-progress using gen_js_api." +cordova cordova-plugin-push-notifications "Binding OCaml to phonegap-plugin-push using gen_js_api." +cordova cordova-plugin-qrscanner "Binding OCaml to cordova-plugin-qrscanner using gen_js_api." +cordova cordova-plugin-screen-orientation +cordova cordova-plugin-sim-card "Binding OCaml to cordova-plugin-sim-card using gen_js_api." +cordova cordova-plugin-sms "Binding OCaml to cordova-plugin-sms using gen_js_api." +cordova cordova-plugin-social-sharing "Binding OCaml to cordova-plugin-x-socialsharing using gen_js_api." +cordova cordova-plugin-statusbar "Binding OCaml to cordova-plugin-statusbar using gen_js_api." +cordova cordova-plugin-toast "Binding OCaml to cordova-plugin-toast using gen_js_api." +cordova cordova-plugin-touch-id "Binding OCaml to cordova-plugin-touch-id using gen_js_api." +cordova cordova-plugin-vibration "Binding OCaml to cordova-plugin-vibration using gen_js_api." +cordova cordova-plugin-videoplayer "Binding OCaml to cordova-plugin-videoplayer using gen_js_api." +crypto eqaf "Constant-time equal function on string" +crypto ez_hash "Ez hash & crypto utilities" +crypto farmhash "Bindings for Google's farmhash library" +crypto fiat-p256 "Primitives for Elliptic Curve Cryptography taken from Fiat" +crypto gmp-ecm "GMP-ECM library for the Elliptic Curve Method (ECM) for integer factorization" +crypto gsasl "Bindings ot the GNU SASL library using Ctypes" +crypto hacl-star "OCaml API for EverCrypt/HACL*" +crypto hacl-star-raw "Auto-generated low-level OCaml bindings for EverCrypt/HACL*" +crypto hacl "Tezos binding for Hacl*" +crypto hacl_x25519 +crypto hkdf "HMAC-based Extract-and-Expand Key Derivation Function (RFC 5869)" +crypto ibx "OCaml implementation of the Interactive Brokers TWS API" +crypto jwt "Implementation of JWT in OCaml." +crypto jwto "JWT encoding, decoding and verification" +crypto key-parsers "Parsers for multiple key formats" +crypto ledgerwallet "Ledger wallet library for OCaml" +crypto ledgerwallet-tezos "Ledger wallet library for OCaml: Tezos app" +crypto letsencrypt "ACME implementation in OCaml" +crypto letsencrypt-app "ACME implementation in OCaml" +crypto letsencrypt-dns "DNS solver for ACME implementation in OCaml" +crypto lt-code "OCaml implementation of a Luby Transform code" +crypto mec "Mec - Mini Elliptic Curve library" +crypto monocypher "OCaml bindings to the Monocypher cryptographic library" +crypto murmur3 "bindings for murmur3 hash implementation" +crypto nocoiner "A Commitment Scheme library for Coin Flipping/Tossing algorithms and sort" +crypto nocrypto "Simpler crypto" +crypto noise "The Noise Protocol Framework" +crypto otr "Off the record implementation purely in OCaml" +crypto passmaker "Library for generating memorable passphrases" +crypto pbkdf "Password based key derivation functions (PBKDF) from PKCS#5" +crypto pkcs11-cli "Cmdliner arguments to initialize a PKCS#11 session" +crypto pkcs11-driver "Bindings to the PKCS#11 cryptographic API" +crypto pkcs11 "PKCS#11 OCaml types" +crypto pkcs11-rev "Reverse bindings to pkcs11" +crypto proverifdoc "Documentation for ProVerif, a cryptographic protocol verifier in the symbolic model" +crypto proverif "ProVerif: Cryptographic protocol verifier in the symbolic model" +crypto randoml "Generating cryptographically-secure random numbers" +crypto rfc6287 "OCRA (OATH Challenge-Response Algorithm) implementation in OCaml" +crypto rfc7748 "Edwards Curves X25519 and X448 from RFC 7748" +crypto safepass "Facilities for the safe storage of user passwords" +crypto salsa20-core "The Salsa20 core functions, in OCaml" +crypto salsa20 "Salsa20 family of encryption functions, in pure OCaml" +crypto scrypt +crypto scrypt-kdf "The scrypt Password-Based Key Derivation Function" +crypto secp256k1 "Elliptic curve library secp256k1 wrapper for Ocaml" +crypto secp256k1-internal +crypto sha "Binding to the SHA cryptographic functions" +crypto sid "Handle security identfiers" +crypto sodium "Binding to libsodium UNAUDITED" +crypto sodium-fmt "Fmt formatters for Sodium" +crypto spoke "SPAKE+EE implementation in OCaml" +crypto statverif "StatVerif: automated verifier for cryptographic protocols with state, based on ProVerif" +crypto ttweetnacl "Thin bindings to TweetNaCl cryptography for OCaml" +crypto twostep "HOTP and TOTP algorithms for 2-step verification (for OCaml)" +crypto u2f "Universal Second Factor (U2F) implementation in OCaml" +crypto uecc "Bindings for ECDH and ECDSA for 8-bit, 32-bit, and 64-bit processors" +crypto webauthn "WebAuthn - authenticating users to services using public key cryptography" +crypto x509 "Public Key Infrastructure (RFC 5280, PKCS) purely in OCaml" +crypto xoshiro "Xoshiro PRNGs as drop-in replacements for Stdlib.Random" +crypto xxhash "Bindings for xxHash, an extremely fast hash algorithm" +crypto zxcvbn "Bindings for the zxcvbn password strength estimation library" +data aches "Caches (bounded-size stores) for in-memory values and for resources" +data aches-lwt "Caches (bounded-size stores) for Lwt promises" +data agrep "String searching with errors" +data agrid "Adjustable grid (two dimensional array) library" +data aliases "In memory indexes" +data anthill "Word search library and utility" +data anycache-async "Scan-resistant LRU/2Q cache" +data anycache-lwt "Scan-resistant LRU/2Q cache" +data anycache "Scan-resistant LRU/2Q cache" +data art "Adaptive Radix Tree" +data asetmap "Alternative, compatible, OCaml standard library Sets and Maps" +data astring """Alternative String module for OCaml""" +data bag "Bags (aka multisets)" +data balancer "A collection of load balancing algorithms implemented in pure Ocaml" +databases ahrocksdb "A binding to RocksDB" +databases ancient "Use data structures larger than available memory" +databases arakoon +databases baardskeerder "Baardskeerder is an append-only B-ish tree." +databases cache "Implements a caching service for storing arbitrary strings that can be located by string keys" +databases camltc "OCaml bindings for tokyo cabinet" +databases caqti-async "Async support for Caqti" +databases caqti-driver-mariadb "MariaDB driver for Caqti using C bindings" +databases caqti-driver-postgresql "PostgreSQL driver for Caqti based on C bindings" +databases caqti-driver-sqlite3 "Sqlite3 driver for Caqti using C bindings" +databases caqti-dynload "Dynamic linking of Caqti drivers using findlib.dynload" +databases caqti-lwt "Lwt support for Caqti" +databases caqti-type-calendar "Date and time field types using the calendar library" +databases caqti "Unified interface to relational database libraries" +databases dbforge "A tool to describe database schemas and generate OCaml code to access these databases." +databases dbm "Binding to the NDBM/GDBM Unix \"databases\"" +databases dokeysto_camltc "The dumb OCaml key-value store w/ tokyocabinet backend" +databases dokeysto_lz4 "The dumb OCaml key-value store w/ LZ4 compression" +databases dokeysto "The dumb OCaml key-value store" +databases esgg "Elasticsearch guided (code) generator" +databases ez_pgocaml "A simple library to work with pgocaml" +databases ezsqlite "Simplified SQLite3 bindings for OCaml" +databases freetds "Binding to the FreeTDS library" +databases gensqlite "A ppx preprocessor to generate SQLite3 prepared statements and query functions." +databases git "Git format and protocol in pure OCaml" +databases git-http "Client implementation of the \"Smart\" HTTP Git protocol in pure OCaml" +databases graphql-async "Build GraphQL schemas with Async support" +databases graphql "Build GraphQL schemas and execute queries against them" +databases graphql-cohttp "Run GraphQL servers with `cohttp`" +databases graphql-lwt "Build GraphQL schemas with Lwt support" +databases graphql_parser "Library for parsing GraphQL queries" +databases graphql_ppx "GraphQL PPX rewriter for ReScript/ReasonML" +databases gremlin "Gremlin Client Library" +databases hg_lib "A library that wraps the Mercurial command line interface" +databases hiredis "Redis tools based on the Hiredis C library" +databases hiredis-value "Hiredis Value type" +databases influxdb-async "InfluxDB client library using async for concurrency" +databases influxdb "InfluxDB client library" +databases influxdb-lwt "InfluxDB client library using lwt for concurrency" +databases kafka_async "OCaml bindings for Kafka, Async bindings" +databases kafka_lwt "OCaml bindings for Kafka, Lwt bindings" +databases kafka "OCaml bindings for Kafka" +databases kyotocabinet "OCaml bindings for Kyoto Cabinet DBM" +databases lemonade-sqlite "A monadic interface to sqlite" +databases leveldb "OCaml bindings for Google's LevelDB library" +databases lmdb "Bindings for LMDB, a fast in-file database with ACID transactions" +databases macaque "DSL for SQL Queries in Caml" +databases macaque_lwt "Utils for MaCaQue with Lwt" +databases mariadb "OCaml bindings for MariaDB" +databases metadb "A database for storing and managing file metadata in JSON format" +databases mongo "OCaml driver for MongoDB" +databases mssql "Async SQL Server client using FreeTDS" +databases mysql +databases mysql8 "OCaml interface for mysql-connector-c" +databases mysql_protocol +databases obigstore "Client/server + embeddable semi-structured database." +databases ocamldbi "Database independent layer patterned upon Perl DBI" +databases ocaml_db_model "An Ocaml library and utility for creating modules out of thin air that describe database tables and types, with functions for running queries and commands. Aka database modelling" +databases ocaml_pgsql_model +databases ocp-search "The ocp-search tool to index/search source packages" +databases ocsipersist-dbm "Persistent key/value storage (for Ocsigen) using DBM" +databases ocsipersist-lib "Persistent key/value storage (for Ocsigen) - support library" +databases ocsipersist "Persistent key/value storage (for Ocsigen) using multiple backends" +databases ocsipersist-pgsql "Persistent key/value storage (for Ocsigen) using PostgreSQL" +databases ocsipersist-sqlite "Persistent key/value storage (for Ocsigen) using SQLite" +databases odbc "Interface to various ODBC drivers" +databases ogre "Open Generic REpresentation NoSQL Database" +databases omigrate "Database migrations for Reason and OCaml" +databases orewa "Async-friendly Redis client" +databases orm "The ORM library provides a storage backend to persist ML values." +databases orocksdb "ctypes based bindings for rocksdb" +databases pa_sqlexpr +databases pgocaml "Native OCaml interface to PostgreSQL databases" +databases pgocaml_ppx "PPX extension for PGOCaml" +databases pg_query "Bindings to libpg_query for parsing PostgreSQL" +databases pgx_async "Pgx using Async for IO" +databases pgx_lwt_mirage "Pgx using Lwt on Mirage for IO" +databases pgx_lwt "Pgx using Lwt for IO" +databases pgx_lwt_unix "Pgx using Lwt and Unix libraries for IO" +databases pgx "Pure-OCaml PostgreSQL client library" +databases pgx_unix "PGX using the standard library's Unix module for IO (synchronous)" +databases pgx_value_core "Pgx_value converters for Core types like Date and Time" +databases pgx_value_ptime "Pgx_value converters for Ptime types" +databases phashtbl "Persistent hash table library using dbm under the carpet." +databases plebeia "Functional storage using Merkle Patricia tree" +databases postgres_async "OCaml/async implementation of the postgres protocol (i.e., does not use C-bindings to libpq)" +databases postgresql "Bindings to the PostgreSQL library" +databases prob-cache "Polymorphic probability cache API, including a distributed riak backed cache." +databases rdf_lwt "Sparql HTTP with Lwt" +databases rdf_mysql "Mysql backend for rdf" +databases rdf "Native OCaml implementation of RDF Graphs and Sparql 1.1 Query." +databases rdf_postgresql "Postgresql backend for rdf" +databases rdf_ppx "Syntax extension for rdf" +databases redis-async "Redis client for Async applications" +databases redis-lwt "Redis client (lwt interface)" +databases redis "Redis client" +databases redis-sync "Redis client (blocking)" +databases resp-client """ +databases resp-mirage """ +databases resp "Redis serialization protocol library" +databases resp-server """ +databases resp-unix """ +databases riak "A Riak OCaml client" +databases riakc_ppx "An OCaml riak client with ppx extensions" +databases riakc "Protobuf based Riak client" +databases riak-pb "Riak OCaml Protobuffs library" +databases sanddb "A simple immutable database for the masses" +databases sequoia "Type-safe query builder for OCaml" +databases sqlexpr "Type-safe, convenient SQLite database access." +databases sqlgg "SQL Guided (code) Generator" +databases sqlite3EZ "Thin wrapper for sqlite3-ocaml with a simplified interface" +databases sqlite3 "SQLite3 bindings for OCaml" +databases sqlite3_utils "High-level wrapper around ocaml-sqlite3" +databases traildb "OCaml bindings for TrailDB." +databases trakeva "Transactions, Keys, and Values; with Postgresql and/or Sqlite." +data batch_jaro_winkler "Fast batch jaro winkler distance implementation in C99" +data bentov "1D histogram sketching" +data bheap "Priority queues" +data bimap "An OCaml library implementing bi-directional maps and multi-maps" +data binning "A datastructure to accumulate values in bins" +data bitmasks "BitMasks over int and int64 exposed as sets" +data bitv "A bit vector library for OCaml" +data bitvec "Fixed-size bitvectors and modular arithmetic, based on Zarith" +data bitvec-order "Base style comparators and orders for Bitvec" +data bloomf "Efficient Bloom filters for OCaml" +data bst "Bisector tree implementation in OCaml" +data buffer-pool "A pool of buffers which automatically increases in size as required" +data bwd "Backward lists" +data cactus "A B-Tree based index implementation" +data Camldiets "A highly efficient OCaml set implementation for fat sets, i.e. densely populated sets over a discrete linear order." +data carray "Contiguous arrays in OCaml" +data combinat "Fast combinatorics for OCaml" +data cpm "The Classification and Regression Performance Metrics library" +data crdt-ml "CRDTs - Conflict-Free Replicated Data Types for OCaml" +data DAGaml "DAGaml : Abstract DAG manipulation in OCaml" +data dataframe "A simple and type-safe dataframe api in pure ocaml" +data datalog "An in-memory datalog implementation for OCaml" +data diet "Discrete Interval Encoding Trees" +data dlist "A purely functional list-like data structure supporting O(1) concatenation" +data dmap "A library that implements dependent (heterogeneous) maps" +data enumerators "Finite lazy enumerators" +data fix "Algorithmic building blocks for memoization, recursion, and more" +data flex-array "Flexible arrays" +data fm-simplex-plugin +data fsml "A library for describing and describing synchronous finite state machines" +data fstreams "Functional, lazy, infinite streams." +data funfields "Functional bit field library" +data glicko2 "Implementation of the Glicko2 algorithm" +data gmap "Heterogenous maps over a GADT" +data graphlib "Generic Graph library" +data grenier "A collection of various algorithms in OCaml" +data GuaCaml "GuaCaml : Generic Unspecific Algorithmic in OCaml" +data hamt "Hash Array Mapped Tries" +data hashcons "OCaml hash-consing library" +data hashset "Sets as hash tables" +data hc "Hashconsing library" +data hdr_histogram "OCaml bindings to Hdr Histogram" +data hmap "Heterogeneous value maps for OCaml" +data huffman "An OCaml library to manipulate Huffman trees" +data hweak "An hastable with weak pointer enabling the GC to collect things that are in the hashtable" +data idd "Identity-suppressed decision diagrams (IDDs)" +data idds "Identity-suppressed decision diagrams (IDDs)" +data immutable "Pure Reason implementation of persistent immutable data structures." +data indexmap "Generic indexed data for OCaml" +data interval-map "An immutable interval map data structure" +data ke "Queue implementation" +data knights_tour "Solves the 'Knights Tour' and various 'Poyomino' puzzles" +data lacc "fat-free list accumulators" +data lascar "A library for manipulating Labeled Transition Systems in OCaml" +data lazy-trie "Implementation of lazy prefix trees" +data lockfree "Lock-free data structures for multicore OCaml" +data lru-cache "A simple implementation of a LRU cache." +data lru "Scalable LRU caches" +data memcpy "Safe and efficient copying between blocks of memory." +data memo "Memoïzation library" +data minivpt "Minimalist vantage point tree implementation in OCaml." +data m_tree "An implementation of M-trees" +data mula "ML's Universal Levenshtein Automata library" +data mvar "Threadsafe mutable variables for Unix threads" +data non_empty_list "A non empty list library for OCaml" +data nullable-array +data ocamlgraph "A generic graph library for OCaml" +data ocamlgraph_gtk "Displaying graphs using OCamlGraph and GTK" +data ocplib-simplex +data odds "Dice roller" +data olinq "LINQ inspired queries on in-memory data" +data ordering "Element ordering" +data oseq "Simple list of suspensions, as a composable lazy iterator that behaves like a value" +data partition_map "Partition maps" +data pomap "Partially Ordered Maps for OCaml" +data prbnmcn-dagger-gsl "Probabilistic programming library: GSL-based samplers" +data prbnmcn-dagger "Probabilistic programming library" +data prbnmcn-dagger-stats "Probabilistic programming library: prbnmcn-stats-based samplers" +data prbnmcn-dagger-test "Probabilistic programming library: tests" +data prbnmcn-mcts "Monte-Carlo tree search based on UCB1 bandits" +data prbnmcn-ucb1 "UCB1 algorithm for multi-armed bandits" +data psq "Functional Priority Search Queues" +data ptmap "Maps of integers implemented as Patricia trees" +data ptset "Sets of integers implemented as Patricia trees" +data radis "Radix tree implementation" +data range "Fold on integer range" +data ranger "A consecutive range slice library for strings, arrays, etc." +data reed-solomon-erasure "OCaml implementation of Reed-Solomon erasure coding" +data reedsolomon "Reed-Solomon Error Correction CODEC" +data res "RES - Library for resizable, contiguous datastructures" +data rfsm "A toolset for describing and simulating StateChart-like state diagrams" +data rhythm "Data Structures and Algorithms implemented in Reason" +data ringo "Bounded-length collections" +data ringo-lwt "Lwt-wrappers for Ringo caches" +data roman "Manipulate roman numerals (ocaml.org dune/opam tutorial)" +data rope "Ropes (\"heavyweight strings\")" +data safa "Symbolic Algorithms for Finite Automata" +data sd_logic "Functionality for time-based finite state machine" +data searchTree "A module to easily implement search trees" +data sek "An efficient implementation of ephemeral and persistent sequences" +data sequence "Simple and lightweight sequence abstract data type." +data setr "Abstract domain library for sets" +data Snowflake "Snowflake : A Generic Symbolic Dynamic Programming framework" +data sortedseq_intersect "A divide-and-conquer algorithm to intersect sorted sequences" +data spatial_index "Implementation of several spatial indexes (R-tree, etc.)" +data splay_tree "A splay tree implementation" +data splittable_random "PRNG that can be split into independent streams" +data streaming "Fast, safe and composable streaming abstractions" +data string_dict "Efficient static string dictionaries" +data symkat "Symbolic Algorithms for Kleene algebra with Tests (KAT)" +data tdigest "OCaml implementation of the T-Digest algorithm" +data tdk "The Decision Kit is a collection of data structures that are useful for representing functions, relations, and other combinatorial objects" +data topological_sort "Topological sort algorithm" +data topology "A library for working with network topologies." +data tree_layout "Algorithms to layout trees in a pretty manner" +data treeprint "Printing combinator library with automatic parenthese" +data trie "Strict impure trie tree" +data tsort "Easy to use and user-friendly topological sort" +data unionFind "Implementations of the union-find data structure" +data varint +data varray "Resizable arrays with fast insertion/deletion" +data vec "Fast, safe mutable dynamic arrays" +data vector "Resizable Arrays" +data vocal "VOCaL -- The Verified OCaml Library" +data vpt "Vantage point tree implementation in OCaml" +data zlist "Lazy lists for OCaml" +dns dns "An opinionated Domain Name System (DNS) library" +dns dns-async "DNS implementation using the Async concurrency framework" +dns dns-certify "MirageOS let's encrypt certificate retrieval" +dns dns-client "DNS resolver API" +dns dns-cli "Unix command line utilities using uDNS" +dns dns-forward "Library and tools for creating forwarding DNS servers" +dns dns-forward-lwt-unix "Lwt implementation for the `dns-forward` library" +dns dns-lwt "DNS implementation in portable Lwt" +dns dns-lwt-unix "DNS implementation for Unix and Windows using Lwt_unix" +dns dns-mirage "An opinionated Domain Name System (DNS) library" +dns dns-resolver "DNS resolver business logic" +dns dnssec "DNSSec support for OCaml-DNS" +dns dns-server "DNS server, primary and secondary" +dns dns-stub "DNS stub resolver" +dns dns-tsig "TSIG support for DNS" +dns domain-name "RFC 1035 Internet domain names" +documentation argot "An enhanced HTML generator for the ocamldoc tool of the OCaml language" +documentation doc-ock "Extract documentation from OCaml files" +documentation doc-ock-html "From doc-ock to HTML" +documentation doc-ock-xml "XML printer and parser for Doc-Ock" +documentation md2mld "Little cli tool to convert md files into mld files" +documentation mdx "Executable code blocks inside markdown files" +documentation ocamlbrowser "OCamlBrowser Library Explorer" +documentation ocaml-manual "The OCaml system manual" +documentation ocamlspot "OCamlSpotter - OCaml source browsing" +documentation ocamlweb "A literate programming tool for OCaml" +documentation ocp-browser "Console browser for the documentation of installed OCaml libraries" +documentation ocp-index +documentation ocp-index-top "Documentation in the OCaml toplevel" +documentation odig "Lookup documentation of installed OCaml packages" +documentation odoc "OCaml documentation generator" +documentation odoc-parser "Parser for ocaml documentation comments" +documentation qocamlbrowser "OCamlBrowser clone written with OCaml and QtQuick 2" +documentation sphinxcontrib-ocaml "Sphinx extension to document OCaml libraries" +documentation swagger "Swagger 2.0 code generator for OCaml" +documentation swdogen "SWagger DOcumentation GENerator" +document blahcaml "Blahcaml provides basic OCaml bindings to the Blahtex library." +document camlpdf "Read, write and modify PDF files" +document caradoc "Parser and validator of PDF files" +document cmarker "Bindings for a local installation of CMark" +document cmark "OCaml bindings for the CMark Common Markdown parsing and rendering library." +document cpdf "High-level PDF tools based on CamlPDF" +document hevea "A quite complete and fast LATEX to HTML translator" +document htmlfromtexbooks "From TeX To Human-Readable HTML" +document jekyll-format "Jekyll post parsing library" +document kdl "An implementation of the KDL document laguage" +document lambdasoup "Easy functional HTML scraping and manipulation with CSS selectors" +document markdown "Markdown processor for Ocsigen" +document markup "Error-recovering functional HTML5 and XML parsers and writers" +document markup-lwt "Adapter between Markup.ml and Lwt" +document melt "Program LaTeX documents using OCaml" +document ocaml-markdown "This is a transition package, ocaml-markdown is now named markdown." +document octavius "Ocamldoc comment syntax parser" +document omd "A Markdown frontend in pure OCaml" +document polyglot "Filters to convert XHTML into polyglot HTML5" +document stog +document stog_all "Virtual package to install all Stog libraries, tools and plugins" +document stog_asy "Stog plugin to include Asymptote results in documents" +document stog_dot "Stog plugin to generate and include graphviz graphs in documents" +document stog_extern "Stog plugin to pipe documents in external commands" +document stog_markdown "Stog plugin to use markdown syntax" +document tidy "Bindings for libtidy5 -- HTML/XML syntax checker and reformatter" +document wikitext "Wikitext parser" +email colombe "SMTP protocol in OCaml" +email dkim "Implementation of DKIM in OCaml" +email dkim-mirage "Implementation of DKIM in OCaml for MirageOS" +email email_message "E-mail message parser" +email emile "Parser of email address according RFC822" +email facteur "Tool to send an email" +email imaplet-lwt "IMAP server prototype, supports IMAPv4rev1" +email imap "Non-blocking client library for the IMAP4rev1 protocol" +email letters "Client library for sending emails over SMTP" +email maildir "This is a preliminary release of an OCaml library to access directories in the Maildir format." +email milter "OCaml libmilter bindings" +email received "Received field according RFC5321" +email receive-mail "A simple SMTP server for OCaml" +email sendmail "Implementation of the sendmail command" +email sendmail-lwt "Implementation of the sendmail command over LWT" +email smtp "SMTP library with Unix and Lwt backends" +email spf "OCaml bindings for libspf2" +email srs "OCaml bindings for libsrs2" +email tidy_email "An OCaml library that simplifies connecting to email services" +email tidy_email_mailgun "An OCaml library that simplifies connecting to Mailgun's REST API" +email tidy_email_sendgrid +email tidy_email_smtp "An OCaml library that simplifies connecting to SMTP servers" +email uspf "SPF implementation in OCaml" +format amf "Parser/serializer for Adobe's Action Message Format" +format asn1-combinators "Embed typed ASN.1 grammars in OCaml" +format assimp "OCaml bindings to Assimp, Open Asset Import Library" +format atd2cconv +format atdgen +format atdgen-codec-runtime "Runtime for atdgen generated bucklescript converters" +format atdgen-runtime "Runtime library for code generated by atdgen" +format atdj "Java code generation for ATD" +format atd "Parser for the ATD data format description language" +format atdpy "Python/mypy code generation for ATD APIs" +format atds "ATD Code generator for Scala" +format atdts "TypeScript code generation for ATD APIs" +format augeas "Bindings to the Augeas configuration editing tool" +format avro-compiler "Schema compiler for Avro" +format avroc "Read and write Apache Avro files" +format avro "Runtime library for encoding/decoding Avro" +format bare_encoding "BARE encoding, see https://baremessages.org/" +format bech32 "Bech32 addresses for OCaml" +format bencode "Bencode (`.torrent` file format) reader/writer in OCaml" +format binaryen_dsl "Writing Webassembly text format in DSL" +format binaryen "OCaml bindings for Binaryen" +format binbin "Convenient and human-readable bitmap manipulation" +format biniou +format bin_prot "A binary protocol generator" +format bip32 "Hierarchical Deterministic Wallets" +format bitlib "A library for writing binary files" +format bitpack_serializer "This library provides functions for encoding efficiently simple OCaml data" +format bitvec-binprot "Janestreet's Binprot serialization for Bitvec" +format bitvec-sexp "Sexp serializers for Bitvec" +format bookaml "Library for retrieving information about published books" +format bson2 "Bson format encoding/decoding for Ocaml" +format bson "A bson data structure, including encoding/decoding" +format bulletml "Library to manipulate shmup patterns" +format carton-git "Implementation of PACK file in OCaml" +format carton "Implementation of PACKv2 file in OCaml" +format carton-lwt "Implementation of PACK file in OCaml" +format cbor "CBOR encoder/decoder (RFC 7049) - native OCaml implementation" +format cborl "CBOR library" +format cconv "Combinators for Type Conversion in OCaml" +format cconv-ppx "Combinators for Type Conversion in OCaml" +format conan-cli "Identify type of your file (such as the MIME type)" +format conan-database "A database of decision trees to recognize MIME type" +format conan "Identify type of your file (such as the MIME type)" +format conan-lwt "Identify type of your file (such as the MIME type)" +format conan-unix "Identify type of your file (such as the MIME type)" +format cosovo "An OCaml library parsing CSV files" +format csv "A pure OCaml library to read and write CSV files" +format csvfields "Runtime support for ppx_xml_conv and ppx_csv_conv" +format csv-lwt "A pure OCaml library to read and write CSV files, LWT version" +format csvprovider "CSV Type Provider for OCaml" +format cudf "CUDF library (part of the Mancoosi tools)" +format cuid "CUID generator for OCaml" +format data-encoding "Library of JSON and binary encoding combinators" +format dbf "DBF format parsing" +format debian-formats "Parse debian files" +format decoders-bencode "Bencode backend for decoders" +format decoders-cbor "CBOR backend for decoders" +format decoders "Elm-inspired decoders for Ocaml" +format decoders-msgpck "Msgpck backend for decoders" +format depyt "Yet-an-other type combinator library" +format distwit "Distribute/marshal exceptions and extensible variants" +format dose3 "Dose library (part of Mancoosi tools)" +format dose3-extra "Dose-extra libraries and tools (part of Mancoosi tools)" +format dose "Dose library (part of Mancoosi tools)" +format easy_xlsx "A library to easily read XLSX files into a simpler format" +format encore "Library to generate encoder/decoder which ensure isomorphism" +format eris "Encoding for Robust Immutable Storage (ERIS)" +format eris-lwt "Lwt bindings to eris" +format erm_xmpp "XMPP protocol implementation" +format erssical "Converting RSS event feeds to ical" +format extprot "Extensible binary protocols for cross-language communication and long-term serialization" +format faraday "A library for writing fast and memory-efficient serializers" +format faraday-async "Async support for Faraday" +format faraday-lwt "Lwt support for Faraday" +format faraday-lwt-unix "Lwt_unix support for Faraday" +format farfadet "A printf-like for Faraday library" +format fit "A parser for Garmin FIT data files" +format gedcom "GEDCOM parsing." +format gpx "Conversions between XML and GPX (1.1) types." +format gxl-light "Gxl parser and in-place destructive update library" +format hashids "Generate short, unique, non-sequential ids from numbers, that you can also decode" +format hdf5 "Manages HDF5 files used for storing large amounts of data" +format hdf "Bindings for the HDF4 library" +format hdfs "Bindings to libhdfs" +format iso639 "Language Codes for OCaml" +format libbinaryen "Libbinaryen packaged for OCaml" +format lilac "Get the value of any field in a YAML file as a string" +format magic "Bindings for libmagic (to determine the type of files)" +format magic-mime "Map filenames to common MIME types" +format mastodon-archive-viewer "View your Mastodon archive offline" +format mbr-format "A simple library for manipulating Master Boot Records" +format meta_conv "Meta conv, type_conv for various tree data formats" +format mlt_parser "Parsing of top-expect files" +format mrmime "Mr. MIME" +format mrt-format "MRT parsing library and CLI" +format msgpack "Msgpack library for OCaml" +format msgpck "Fast MessagePack (http://msgpack.org) library" +format msgpck-repr "Fast MessagePack (http://msgpack.org) library -- ocplib-json-typed interface" +format multibase "Self-describing base encodings" +format multicodec "Canonical codec of values and types used by various multiformats" +format multicont "Multi-shot continuations in OCaml" +format multihash-digestif "Self-describing Hash Functions using Digestif" +format multihash "Self-describing Hash Functions" +format multipart-form-data "Parser for multipart/form-data (RFC2388)" +format multipart_form-lwt "Multipart-form: RFC2183, RFC2388 & RFC7578" +format multipart_form "Multipart-form: RFC2183, RFC2388 & RFC7578" +format nanoid "Nano ID implementation for OCaml" +format nanomsg "Ctypes based bindings to nanomsg" +format nmea "Nmea parser" +format obeam "A utility library for parsing BEAM format" +format ocaml-data-notation "Store data using OCaml notation (deprecated)" +format ocaml-inifiles "An ini file parser" +format ocaml-protoc-plugin "Plugin for protoc protobuf compiler to generate ocaml definitions from a .proto file" +format ocaml-protoc "Protobuf compiler for OCaml" +format ocamlrss "Library providing functions to parse and print RSS 2.0 files" +format ocf "OCaml library to read and write configuration files in JSON syntax" +format ocf_ppx "Preprocessor for Ocf library" +format ockt "OCaml library for parsing ckt files into hashtables" +format ocplib-config "A simple library to manage configuration files" +format ofx "OCaml parser for OFX files" +format opazl "Library to parse ZNC logs" +format openflow "Serialization and protocol implementation for OpenFlow 1.{0,3}" +format open_packaging "A library for parsing Microsoft's Open Packaging Specification (most commonly used for Microsoft" +format orsetto "A library of assorted structured data interchange languages" +format osm_xml "Library for parsing OpenStreetMap XML dumps." +format otoml "TOML parsing, manipulation, and pretty-printing library (1.0.0-compliant)" +format pa_bin_prot "A binary protocol generator" +format packet "A serialization library for several common packet formats" +format packstream "Packstream parses and serializes Packstream binary format" +format pa_fields_conv +format pcap-format "Decode and encode PCAP (packet capture) files" +format pecu "Encoder/Decoder of Quoted-Printable (RFC2045 & RFC2047)" +format piqilib "The Piqi library -- runtime support for multi-format Protobuf/JSON/XML/Piq data serialization and conversion" +format piqi "Protocol Buffers, JSON and XML serialization system for OCaml" +format plotkicadsch "Utilities to print and compare version of Kicad schematics" +format prettym "An memory-bounded encoder according to RFC 822" +format radare2 "OCaml interface to r2" +format rlp "RLP: Recursive Length Prefix Encoding" +format rss "Library to read and write RSS files" +format scfg "OCaml library and executable to work with the scfg configuration file format" +format semver2 "Semantic version handling for OCaml" +format semver "Semantic versioning module" +format serial "Serial communication module" +format sgf "Parser and pretty printer for SGF files." +format shapefile "A small library to read ESRI shapefiles" +format spdx_licenses "A library providing a strict SPDX License Expression parser" +format spreadsheet "Functor for parsing and building spreadsheets." +format spreadsheetml "A library to parsing SpreadsheetML (used in Microsoft Excel files)" +format stog_multi_doc "Stog plugin to define various documents in one file" +format stog_nocaml "Stog plugin to block commands executing ocaml code" +format stog_noexec "Stog plugin to prevent running command with " +format stog_plugins "Virtual package to install all Stog plugins" +format stog-rdf +format stog-rdf "Plugin for Stog. Define and query RDF graphs in rewrite rules." +format stog_rdf "Stog plugin to generate rdf triples and execute sparql queries" +format stog_rel_href "Stog plugin to generate relative urls" +format stog_server_multi "Stog multi server library" +format stog_server "Stog server library" +format stog_sitemap "Stog plugin to generate a sitemap file" +format stog_writing "Stog plugin to generate table of contents and bibliographies" +format swhid_compute +format swhid_core "OCaml library to work with swhids" +format swhid "OCaml library to work with Software Heritage identifiers" +format swhid_types +format syguslib-utils "SyGuS Lib parser and utils" +format syndic "RSS1, RSS2, Atom and OPML1 parsing" +format syslog-message "Syslog message parser" +format syslog-rfc5424 "Syslog Protocol (RFC5424) parser and pretty-printer" +format SZXX "Streaming ZIP XML XLSX parser" +format taglib "Bindings for the taglib library" +format tcx "OCaml library for parsing and formatting Training Center XML files." +format tip-parser "Parser for https://tip-org.github.io/format.html" +format toml-cconv "Interface between cconv and toml" +format toml_cconv "Interface between cconv and toml" +format toml "Library for TOML with a parser, a serializer and a printer" +format tptp "Library for reading and writing FOF and CNF formulas in TPTP format" +format tracing "Tracing library" +format typebeat "Agnostic parser of the `Content-Type` in OCaml" +format type-beat "A parser for the Content-Type value" +format ulid "ULIDs for OCaml" +format validator "Create a record validator via composable sub-validators" +format vcardgen "Simple OCaml library for generating VCards per RFC-6350" +format vlq "A simple library for encoding variable-length quantities" +format webidl "Web IDL parser" +format yaml "Parse and generate YAML 1.1/1.2 files" +format yaml-sexp "Parse and generate YAML 1.1 files" +format zbar "Binding to ZBar (QR-code scanning library)" +frp cumulus "Differential FRP based on the React library" +frp current_ansi "ANSI escape sequence parser" +frp current_docker "OCurrent Docker plugin" +frp current_examples "Example pipelines for OCurrent" +frp current_git "Git plugin for OCurrent" +frp current_github "GitHub plugin for OCurrent" +frp current_gitlab "GitLab plugin for OCurrent" +frp current_incr "Self-adjusting computations" +frp current_ocluster "OCurrent plugin for OCluster builds" +frp current "Pipeline language for keeping things up-to-date" +frp current_rpc "Cap'n Proto RPC plugin for OCurrent" +frp current_slack "Slack plugin for OCurrent" +frp current_web "Test web UI for OCurrent" +frp froc "Jake Donham's Froc library for functional reactive programming in OCaml." +frp incremental_kernel +frp incremental "Library for incremental computations" +frp incr_map "Helpers for incremental operations on map like data structures." +frp incr_select "Handling of large set of incremental outputs from a single input" +frp note "Declarative events and signals for OCaml" +frp prbnmcn-cgrph "Incremental computation" +frp react "Declarative events and signals for OCaml" +frp reactiveData "Declarative events and signals for OCaml" +frp rml "ReactiveML: a programming language for implementing interactive systems" +frp rtime "Module implementing timelines for React" +graphics2d archimedes "Extensible 2D plotting library" +graphics2d async_graphics "Async wrapper for the OCaml Graphics library" +graphics2d bimage """ +graphics2d bimage-display """ +graphics2d bimage-gtk """ +graphics2d bimage-io """ +graphics2d bimage-lwt """ +graphics2d bimage-sdl """ +graphics2d bimage-unix """ +graphics2d cairo2 "Binding to Cairo, a 2D Vector Graphics Library" +graphics2d cairo2-gtk "Rendering Cairo on Gtk canvas" +graphics2d cairo2-pango "Interface between Cairo and Pango" +graphics2d cairo "Binding to Cairo, a 2D Vector Graphics Library" +graphics2d camlimages "Image processing library" +graphics2d gd "OCaml interface to the GD graphics library." +graphics2d gnuplot "Simple interface to Gnuplot +graphics2d graphicspdf "Version of OCaml's Graphics library which outputs PDFs." +graphics2d graphics "The OCaml graphics library" +graphics2d graphv_core "Functor for creating a new Graphv library based on a font render and backend renderer" +graphics2d graphv_core_lib "Primitives for the Graphv vector graphics library" +graphics2d graphv_font "Functor for generating the Graphv font library" +graphics2d graphv_font_stb_truetype "STB truetype implementation of the font interface for Graphv" +graphics2d graphv_gles2 "Functor for creating a Graphv renderer based on GLES2" +graphics2d graphv_gles2_native "Full version of the Graphv library based on native GLES2" +graphics2d graphv_gles2_native_impl +graphics2d graphv "Top_level graphv package, includes all dependencies" +graphics2d gr "OCaml bindings to the GR plotting library" +graphics2d lilis "Library to Interpret Lindenmayer Systems" +graphics2d matplotlib "Plotting using Matplotlib through python" +graphics2d mlpost-lablgtk "Library for adding mlpost graphics in lablgtk" +graphics2d mlpost "OCaml library on top of Metapost" +graphics2d ocamldot "Parsing and printing graphviz files in OCaml" +graphics2d ocamlsdl2 "Interface to the SDL2 library" +graphics2d ocamlsdl2-ttf "Interface to the SDL2_ttf library" +graphics2d ocamlsdl "Interface between OCaml and SDL" +graphics2d ocb "SVG badge generator" +graphics2d ocsfml "Binding to the C++ SFML gaming library." +graphics2d oplot "Mathematical plotter library for ocaml" +graphics2d osh "OCaml web API to generate SVG shields" +graphics2d otfm "OpenType font decoder for OCaml" +graphics2d patoline "Patoline typesetting system and libraries" +graphics2d pcf-format "parse PCF format X11 bitmap font files" +graphics2d picasso "Abstract elements drawing library" +graphics2d plplot "Bindings for the PLplot library" +graphics2d prbnmcn-gnuplot "Declarative generation of gnuplot scripts" +graphics2d qrc "QR code encoder for OCaml" +graphics2d qrencode "Binding to libqrencode (QR-code encoding library)" +graphics2d raylib "OCaml bindings for raylib" +graphics2d tsdl-image "SDL2_Image bindings to go with Tsdl" +graphics2d tsdl-mixer "SDL2_Mixer bindings to go with Tsdl" +graphics2d tsdl "Thin bindings to SDL for OCaml" +graphics2d tsdl-ttf "SDL2_Ttf bindings to go with Tsdl" +graphics2d vg """Declarative 2D vector graphics for OCaml""" +graphics2d wall "Realtime Vector Graphics with OpenGL" +graphics3d gles3 "OCaml GLES 3.0 bindings" +graphics3d glfw-ocaml "A GLFW binding for OCaml" +graphics3d glMLite "OpenGL bindings for OCaml" +graphics3d glsurf "GlSurf, implicit curves and surfaces drawing and discretization" +graphics3d irrlicht "An OCaml binding for the Irrlicht Engine" +graphics3d lablgl "Interface to OpenGL" +graphics3d mesh-display "Triangular mesh representation using the graphics module" +graphics3d mesh-easymesh "Triangular mesh generation with EasyMesh" +graphics3d mesh-graphics "Triangular mesh representation using the graphics module" +graphics3d mesh-triangle "Binding to the triangle mesh generator" +graphics3d mesh "Triangular mesh generation and manipulation" +graphics3d minilight "Minimal global illumination renderer." +graphics3d OSCADml "OCaml DSL for 3D solid modelling in OpenSCAD" +graphics3d sarek "GPGPU kernel DSL for OCaml" +graphics3d scad_ml "OCaml DSL for 3D solid modelling in OpenSCAD" +graphics3d spoc "High-level GPGPU programming library for OCaml" +graphics3d spoc_ppx "PPX to declare external GPGPU kernels written in CUDA or OpenCL" +graphics3d tgls "Thin bindings to OpenGL {3,4} and OpenGL ES {2,3} for OCaml" +gui bogue "GUI library for ocaml, with animations, based on SDL2" +gui bonsai "A library for building dynamic webapps, using Js_of_ocaml" +gui gtk-light "Light wrapper around lablgtk2" +gui gtktop "A small library to ease the creation of graphical toplevels." +gui lablgtk3-extras +gui lablgtk3-goocanvas2 "OCaml interface to GTK+ GooCanvas library" +gui lablgtk3-gtkspell3 "OCaml interface to GTK+3" +gui lablgtk3 "OCaml interface to GTK+3" +gui lablgtk3-sourceview3 "OCaml interface to GTK+ gtksourceview library" +gui lablgtk-extras +gui lablgtk "OCaml interface to GTK+" +gui lablgtkosx "Lablgtkosx binds gOSX_application on top of lablgtk" +gui lablqml +gui lablqt "Tool for interfacing QtQuick with OCaml" +gui labltk "OCaml interface to Tcl/Tk" +gui lwd "Lightweight reactive documents" +gui raygui "OCaml bindings for raygui" +gui wxOCaml "OCaml bindings to the wxWidgets graphical library" +hardcaml hardcaml-affirm "Verification tools for HardCaml" +hardcaml hardcaml-bloop "Boolean logic tools for HardCaml" +hardcaml hardcaml_c "Hardcaml C Simulation Backend" +hardcaml hardcaml_circuits "Hardcaml Circuits" +hardcaml hardcaml-examples "HardCaml examples designs build using hardcaml-framework" +hardcaml hardcaml_fixed_point "Hardcaml fixed point arithmetic" +hardcaml hardcaml-framework "Framework for generating and simulating HardCaml cores" +hardcaml hardcaml-llvmsim "HardCaml simulation backend using LLVM" +hardcaml hardcaml_of_verilog "Convert Verilog to a Hardcaml design" +hardcaml hardcaml-reedsolomon "HardCaml implementation of Reed-Solomon error correction coding" +hardcaml hardcaml "RTL Hardware Design in OCaml" +hardcaml hardcaml_step_testbench "Hardcaml Testbench Monad" +hardcaml hardcaml_verify "Hardcaml Verification Tools" +hardcaml hardcaml_verilator "Hardcaml Verilator Simulation Backend" +hardcaml hardcaml-vpi "HardCaml Icarus Verilog cosimulation module" +hardcaml hardcaml_waveterm "A terminal based digital waveform viewer for Hardcaml" +hardcaml hardcaml-waveterm "Terminal based digital waveform viewer" +hardcaml hardcaml_xilinx_components "Hardcaml Xilinx component definitions" +hardcaml hardcaml_xilinx "Hardcaml wrappers for Xilinx memory primitives" +hardcaml hardcaml-yosys "Import Verilog designs into HardCaml" +http cohttp "An OCaml library for HTTP clients and servers" +http cohttp-async "CoHTTP implementation for the Async concurrency library" +http cohttp_async_websocket "Websocket library for use with cohttp and async" +http cohttp-lwt "CoHTTP implementation using the Lwt concurrency library" +http cohttp-lwt-jsoo "CoHTTP implementation for the Js_of_ocaml JavaScript compiler" +http cohttp-lwt-unix "CoHTTP implementation for Unix and Windows using Lwt" +http cohttp-lwt-unix-nossl "CoHTTP implementation for Unix and Windows using Lwt" +http cohttp-lwt-unix-ssl "CoHTTP implementation for Unix and Windows using Lwt" +http cohttp-mirage "CoHTTP implementation for the MirageOS unikernel" +http cohttp_static_handler "A library for easily creating a cohttp handler for static files" +http cohttp-top "CoHTTP toplevel pretty printers for HTTP types" +http curly "Curly is a brain dead wrapper around the curl command line utility" +http ezcurl "Friendly wrapper around OCurl" +http ezcurl-lwt "Friendly wrapper around OCurl, Lwt version" +http ezresto "A minimal OCaml library for type-safe HTTP/JSON RPCs" +http ezresto-directory "A minimal OCaml library for type-safe HTTP/JSON RPCs" +http h1_parser "Parser for HTTP 1.1" +http h2 "A high-performance, memory-efficient, and scalable HTTP/2 library for OCaml" +http h2-async "Async support for h2" +http h2-lwt "Lwt support for h2" +http h2-lwt-unix "Lwt + UNIX support for h2" +http h2-mirage "Mirage support for h2" +http hpack "An HPACK (Header Compression for HTTP/2) implementation in OCaml" +http http2https "HTTP to HTTPS redirector daemon" +http httpaf +http httpaf-async "Async support for http/af" +http httpaf_caged "A higher-level httpaf-async server interface" +http httpaf-lwt-unix "Lwt support for http/af" +http http_async "Async library for HTTP/1.1 servers" +http http-cookie "HTTP cookie library for OCaml" +http httph "Minimal OCaml to the httpserver.h http server toolkit" +http http-lwt-client "A simple HTTP client using http/af, h2, and lwt" +http http-multipart-formdata "Http multipart/formdata parser" +http http_router "Simple http router for cohttp and async." +http hyper "Web client with HTTP/1, HTTP/2, TLS, and WebSocket support" +http ocaml-http "Library freely inspired from Perl's HTTP::Daemon module" +http ocurl "Bindings to libcurl" +http openapi "Openapi documentation generation for Opium" +http paf-cohttp "A CoHTTP client with its HTTP/AF implementation" +http paf-le "A CoHTTP client with its HTTP/AF implementation" +http piaf "An HTTP library with HTTP/2 support written entirely in OCaml" +http quests "HTTP/1.1 client library like Python requests" +http session "A session manager for your everyday needs" +http session-cohttp "A session manager for your everyday needs - Cohttp-specific support" +http session-cohttp-async "A session manager for your everyday needs - Cohttp-specific support for Async" +http session-cohttp-lwt "A session manager for your everyday needs - Cohttp-specific support for Lwt" +http session-cookie-async "Session handling for OCaml and ReasonML" +http session-cookie-lwt "Session handling for OCaml and ReasonML" +http session-cookie "Session handling for OCaml and ReasonML" +http session-postgresql "A session manager for your everyday needs - Postgresql-specific support" +http session-postgresql-async "A session manager for your everyday needs - Postgresql-specific support for Async" +http session-postgresql-lwt "A session manager for your everyday needs - Postgresql-specific support" +http session-redis-lwt "A session manager for your everyday needs - Redis-specific support for Lwt" +http sessions +http session-webmachine "A session manager for your everyday needs - Webmachine-specific support" +http terminus "A generic client to interact with Rest API" +http terminus-cohttp "Terminus with the cohttp-lwt-unix request handler" +http terminus-hlc "Terminus with the http-lwt-client request handler" +http uri "An RFC3986 URI/URL parsing library" +http uri-re "An RFC3986 URI/URL parsing library" +http uri-sexp "An RFC3986 URI/URL parsing library" +http uritemplate "OCaml implementation of URI templates (RFC6570)" +http websocketaf +http websocket-async "Websocket library (Async)" +http websocket-lwt-unix "Websocket library (Lwt)" +http websocket-lwt "Websocket library (Lwt)" +http websocketml "A simple websocket library for OCaml with no dependency" +http websocket "Websocket library" +http wget "Basic wget-like client, based on the Citrix' HTTP library." +http ws "Generic websocket implementation for OCaml" +http ws-server "WebSocket server" +ide annot "annotation parser for external editors and IDEs" +ide caml-mode "Caml mode for GNU Emacs" +ide dot-merlin-reader "Reads config files for merlin" +ide gopcaml-mode +ide gopcaml-mode-merlin +ide merlin +ide merlin-acme "Merlin interface for acme." +ide merlin-extend "A protocol to provide custom frontend to Merlin" +ide merlin-lib +ide merlin-of-pds "Simple script that turns a pds.conf into a .merlin file" +ide ocamleditor "OCamlEditor is a GTK+ source code editor and build tool for OCaml" +ide ocaml-lsp-server "LSP Server for OCaml" +ide otags "Tag file generation of OCaml sources (for vi and emacs)" +ide tuareg "OCaml mode for GNU Emacs" +images gavl "Bindings for the gavl library which provides functions for converting images formats, colorspaces, etc." +images imagelib "Library implementing parsing of image formats such as PNG, BMP, PPM" +images imagemagick "Bindings for ImageMagick" +images ocamlsdl2-image "Interface to the SDL2_image library" +images qcow-format "Read and write images in Qcow2 format" +images qcow "Support for Qcow2 images" +images qcow-tool "A command-line tool for manipulating qcow2-formatted data" +images stb_image "OCaml bindings to stb_image, a public domain image loader" +images stb_image_write "OCaml bindings to stb_image_write, a public domain image writer" +images stb_truetype "OCaml bindings to stb_truetype, a public domain font rasterizer" +interoperability alberto "OCaml interface to Erlang ports" +interoperability cppffigen "A C++ foreign-function-interface generator for Ocaml based on C++ STL Containers" +interoperability cstruct "Access C-like structures directly from OCaml" +interoperability cstruct-async "Access C-like structures directly from OCaml" +interoperability cstruct-lwt "Access C-like structures directly from OCaml" +interoperability cstruct-sexp "S-expression serialisers for C-like structures" +interoperability cstruct-unix "Access C-like structures directly from OCaml" +interoperability ctypes-build "Support for building Ctypes bindings." +interoperability ctypes "Combinators for binding to C libraries without writing any C" +interoperability ctypes-foreign "Virtual package for enabling the ctypes.foreign subpackage" +interoperability ctypes_stubs_js "Js_of_ocaml Javascript stubs for the OCaml ctypes library" +interoperability gobject-introspection "OCaml bindings for the GObject-Introspection library (https://gi.readthedocs.io/en/latest/)" +interoperability gperftools "Bindings to gperftools" +interoperability guile "Bindings to GNU Guile Scheme for OCaml" +interoperability jemalloc "Bindings to jemalloc mallctl api" +interoperability lymp "Use Python functions and objects from OCaml" +interoperability mstruct "A mutable interface to Cstruct buffers" +interoperability ocaml-in-python "Effortless Python bindings for OCaml modules" +interoperability ocaml-lua "Lua bindings" +interoperability ocaml-r "Objective Caml bindings for the R interpreter" +interoperability py "Ctypes bindings to Python 3.5 or greater" +interoperability pyml_bindgen "Generate pyml bindings from OCaml value specifications" +interoperability pyml "OCaml bindings for Python" +interoperability pythonlib "A library to help writing wrappers around ocaml code for python" +interoperability randomconv "Convert from random byte vectors (Cstruct.t) to random native numbers" +interoperability swipl "Bindings to SWI-Prolog for OCaml" +interoperability thrift "OCaml bindings for the Apache Thrift RPC system" +io async_core "Monadic concurrency library" +io async_extended "Additional utilities for async" +io async_extra "Monadic concurrency library" +io async_find "Directory traversal with Async" +io async_inotify "Async wrapper for inotify" +io async_kernel "Monadic concurrency library" +io async "Monadic concurrency library" +io async-mvar "Async-mvar is a port of Lwt's Lwt_mvar" +io async_parallel "Distributed computing library" +io async_sendfile "Thin wrapper around [Linux_ext.sendfile] to send full files" +io builder "Scheduling and executing shell jobs" +io builder-web "Web interface for builder" +io command_rpc "Utilities for Versioned RPC communication with a child process over stdin and stdout" +io core-lwt "Lwt library wrapper in the Janestreet core style" +io core_unix "Unix-specific portions of Core" +io datakit-bridge-github "A bidirectional bridge between the GitHub API and Datakit" +io datakit-bridge-local-git "DataKit Local-Git bridge" +io datakit-ci "Continuous Integration service using DataKit" +io datakit-client-9p "A library for Datakit clients over 9P" +io datakit-client "A library to construct Datakit clients" +io datakit-client-git "A library for connecting Datakit client using Git" +io datakit-github "Abstraction of the GitHub API, suitable for DataKit clients" +io datakit "Orchestrate applications using a Git-like dataflow" +io datakit-server-9p "Build Datakit servers using the 9P filesystem protocol" +io datakit-server "A library to write Datakit servers" +io eio "Effect-based direct-style IO API for OCaml" +io eio_linux "Eio implementation for Linux using io-uring" +io eio_luv "Eio implementation using luv (libuv)" +io eio_main "Effect-based direct-style IO mainloop for OCaml" +io eio-ssl "OpenSSL binding to EIO" +io fiber "Structured concurrency library" +io future "Abstraction over Stdlib, Lwt, Async, and more." +io gen_server "An Erlang-like gen_server framework written for Async." +io io-page "Support for efficient handling of I/O memory pages" +io io-page-unix "Support for efficient handling of I/O memory pages on Unix" +io io-page-xen "Support for efficient handling of I/O memory pages on Xen" +io io "Simple, secure and composable abstraction for efficient component" +io lambda_streams_async "Async helpers for lambda_streams" +io lambda_streams "Lambda-based streaming library" +io lambda_streams_lwt "Lwt helpers for lambda_streams" +io lwt-binio "Asynchronous random access IO for numbers" +io lwt_camlp4 "Camlp4 syntax extension for Lwt (deprecated)" +io lwt-canceler "Cancellation synchronization object" +io lwt-dllist "Mutable doubly-linked list with Lwt iterators" +io lwt_domain "Helpers for using Domainslib with Lwt" +io lwt_eio "Run Lwt code within Eio" +io lwt-exit "An opinionated clean-exit and signal-handling library for Lwt programs" +io lwt_glib "GLib integration for Lwt" +io lwt_log "Lwt logging library (deprecated)" +io lwt_named_threads +io lwt-parallel "Lwt-enabled multiprocessing library" +io lwt-pipe "An alternative to `Lwt_stream` with interfaces for producers and consumers and a bounded internal buffer" +io lwt-pipeline "Pipeline library for Lwt" +io lwt_ppx_let "Dummy package context for ppx_let tests" +io lwt_ppx "PPX syntax for Lwt, providing something similar to async/await from JavaScript" +io lwt "Promises and event-driven I/O" +io lwt_react "Helpers for using React with Lwt" +io lwt_ssl "OpenSSL binding with concurrent I/O" +io lwt-watcher "One-to-many broadcast in Lwt" +io lwt-zmq "Lwt-friendly interface to ZeroMQ" +io ocplib-concur "Concurrent wrapper on top of Lwt and Async" +io pipebang "Part of Jane Street’s Core library" +io poll "Portable OCaml interface to macOS/Linux/Windows native IO event notification mechanisms" +io polly "Bindings for the Linux epoll system call" +io release "Release is a multi-process Lwt-enabled daemon framework for OCaml." +io resource_cache "General resource cache" +io resource-pooling "Library for pooling resources like connections, threads, or similar" +io sequencer_table "A table of [Async.Sequencer]'s, indexed by key" +io shared-block-ring "A single-consumer single-producer queue on a block device" +io shuttle_http "HTTP codec for shuttle" +io shuttle "Reasonably performant non-blocking channels for async" +io shuttle_ssl "Async_ssl support for shuttle" +io socket-daemon "Create daemons listening to a socket for stop, restart, ..., orders" +io tube "Typesafe abstraction on top of Lwt_io channels" +io uwt "libuv bindings" +irc calculon "Library for writing IRC bots in OCaml and a collection of plugins" +irc calculon-redis "A redis plugin for Calculon" +irc calculon-redis-lib "A library to interact with Calculon via Redis" +irc calculon-web "A collection of web plugins for Calculon" +irc irc-client "IRC client library - core functionality" +irc irc-client-lwt "IRC client library - Lwt implementation" +irc irc-client-lwt-ssl "IRC client library - Lwt SSL implementation" +irc irc-client-tls "IRC client library - TLS implementation" +irc irc-client-unix "IRC client library - Unix implementation" +irmin ezirmin "An easy interface on top of the Irmin library." +irmin index "A platform-agnostic multi-level index for OCaml" +irmin irmin """ +irmin irmin-chunk "Irmin backend which allow to store values into chunks" +irmin irmin-cli "CLI for Irmin" +irmin irmin-containers "Mergeable Irmin data structures" +irmin irmin-fs "Generic file-system backend for Irmin" +irmin irmin-git "Git backend for Irmin" +irmin irmin-graphql "GraphQL server for Irmin" +irmin irmin-http "HTTP client and server for Irmin" +irmin irmin-indexeddb "Irmin backend using the web-browser's IndexedDB store" +irmin irmin-layers "Combine different Irmin stores into a single, layered store" +irmin irmin-mem "Generic in-memory Irmin stores" +irmin irmin-mirage-git "MirageOS-compatible Irmin stores" +irmin irmin-mirage-graphql "MirageOS-compatible Irmin stores" +irmin irmin-mirage "MirageOS-compatible Irmin stores" +irmin irmin-pack "Irmin backend which stores values in a pack file" +irmin irmin-test "Irmin test suite" +irmin irmin-tezos "Irmin implementation of the Tezos context hash specification" +irmin irmin-tezos-utils "Utils for Irmin tezos" +irmin irmin-unix "Unix backends for Irmin" +irmin irmin-watcher "Portable Irmin watch backends using FSevents or Inotify" +irmin libirmin "C bindings for irmin" +irmin mergeable-vector "Mergeable vector based on operational transformation" +irmin merge-queues "Mergeable queues" +irmin merge-ropes "Mergeable ropes" +js async_js +js atable "Basic spreadsheet tool with HTML tables" +js brr "Browser programming toolkit for OCaml" +js brr-lwd "Make reactive webpages in Js_of_ocaml using Brr and Lwd" +js c3 "OCaml bindings for the Javascript c3 charting library." +js chartjs-annotation "OCaml bindigns for Chart.js annotation plugin" +js chartjs-colorschemes "OCaml bindigns for Chart.js colorschemes plugin" +js chartjs-datalabels "OCaml bindigns for Chart.js datalabels plugin" +js chartjs "OCaml bindings for Chart.js" +js chartjs-streaming "OCaml bindings for Chart.js streaming plugin" +js commonjs_of_ocaml "Import and export CommonJS modules in js_of_ocaml" +js cookie-js "Simple library for setting/getting cookies in js_of_ocaml" +js d3 "OCaml bindings for D3.js" +js dispatch-js "Path-based dispatch: js_of_ocaml-specific support" +js ezjs_ace "Bindings for the Ace editor" +js ezjs_blockies "Bindings for Blockies" +js ezjs_cleave "Bindings for Cleave" +js ezjs_crypto "Bindings for SubtleCrypto" +js ezjs_cytoscape "Bindings for Cytoscape" +js ezjs_d3pie "Bindings for d3pie" +js ezjs_extension "Binding for Chrome and Firefox extension API" +js ezjs_fetch "Bindings for Fetch" +js ezjs_idb "Bindings for IndexedDB" +js ezjs_jquery "Bindings for JQuery" +js ezjs_min "A bunch of js_of_ocaml shortcuts" +js ezjs_odometer "Bindings for odometer" +js ezjsonm-lwt "Simple Lwt-based interface to the Jsonm JSON library" +js ezjsonm "Simple interface on top of the Jsonm JSON library" +js ezjs_push "Bindings for Push Notification" +js ezjs_qrcode "Bindings for QRCode.js" +js ezjs_recaptcha "Bindings for reCAPTCHA" +js ezjs_timeline "Bindings for TimelineJS" +js fmlib_js "Library for easy compilation from ocaml to javascript" +js gamepad "Bindings for the JS Gamepad API" +js gen-bs "generate bucklescript code from Javascript type specifications" +js gen_js_api "Easy OCaml bindings for JavaScript libraries" +js graphv_font_js "Javascript implementation of the font interface for Graphv" +js graphv_webgl "Full version of the Graphv library based on WebGL" +js graphv_webgl_impl +js incr_dom "A library for building dynamic webapps, using Js_of_ocaml." +js incr_dom_interactive "A monad for composing chains of interactive UI elements" +js incr_dom_keyboard "A library for Incr_dom keybinding and keyboard shortcut helpers" +js incr_dom_partial_render "A library for simplifying rendering of large amounts of data" +js incr_dom_sexp_form "A library for building forms that allow the user to edit complicated types" +js incr_dom_widgets "Utilities for Incr_dom" +js integers_stubs_js "Javascript stubs for the integers library in js_of_ocaml" +js javascriptcore "OCaml bindings to JavaScriptCore" +js jose "JOSE implementation for OCaml and ReasonML" +js JsOfOCairo "Library to reuse Cairo-based drawing code in web browsers" +js js_of_ocaml-camlp4 "Compiler from OCaml bytecode to Javascript" +js js_of_ocaml-compiler "Compiler from OCaml bytecode to JavaScript" +js js_of_ocaml "Compiler from OCaml bytecode to JavaScript" +js js_of_ocaml-lwt "Compiler from OCaml bytecode to JavaScript" +js js_of_ocaml-ocamlbuild "Compiler from OCaml bytecode to Javascript" +js js_of_ocaml-ppx "Compiler from OCaml bytecode to JavaScript" +js js_of_ocaml-ppx_deriving_json "Compiler from OCaml bytecode to JavaScript" +js js_of_ocaml-toplevel "Compiler from OCaml bytecode to JavaScript" +js js_of_ocaml-tyxml "Compiler from OCaml bytecode to JavaScript" +js js_of_ocaml-webgpu "Js_of_ocaml bindings for webgpu" +js js_of_ocaml-webidl "Generate js_of_ocaml bindings from webidl definitions" +js jsonoo "JSON library for Js_of_ocaml" +js jsoo_broadcastchannel "A wrapper in Js_of_ocaml to deal with BroadcastChannel" +js jsoo_router +js jsoo_storage "A wrapper in Js_of_ocaml for the WebStorage API" +js leaflet "Bindings for the Leaflet JavaScript library" +js melange-compiler-libs +js melange "Toolchain to produce JS from Reason/OCaml" +js monaco_jsoo "JSOO interface for Monaco-editor" +js obrowser "OCaml virtual machine written in Javascript" +js ocaml-js-stdlib "Binding OCaml to JavaScript standard library" +js ocaml-vdom "DOM and VDOM for OCaml" +js ocaml-webworker +js ocp_reveal "OCaml bindings for Reveal.js, an HTML presentation framework" +js odash "Odash: Lodash for Ocaml" +js ojquery "JQuery binding for OCaml" +js ojs-base +js ojs_base +js ojs_base_all "Virtual package to install all ojs_base packages" +js ojs_base_ppx "PPx extension for the Ojs_base library" +js ojs_ed "Using file editor in ojs_base applications, common part" +js ojs_filetree "Using filetrees in ojs_base applications, common part" +js ojs_list "Using lists in ojs_base applications, common part" +js ojs "Runtime Library for gen_js_api generated libraries" +js ojwidgets "Browser widgets in OCaml with js_of_ocaml." +json decoders-ezjsonm "Ezjsonm backend for decoders" +json decoders-jsonaf "Jsonaf backend for decoders" +json decoders-jsonm "Jsonm backend for decoders" +json decoders-yojson "Yojson backend for decoders" +json jsonaf "A library for parsing, manipulating, and serializing data structured as JSON" +json json-data-encoding-browser "Type-safe encoding to and decoding from JSON (browser support)" +json json-data-encoding-bson "Type-safe encoding to and decoding from JSON (bson support)" +json json-data-encoding "Type-safe encoding to and decoding from JSON" +json json-derivers "Common Derivers for Jsonm/Yjson" +json jsondiff "JSON sensitive diffing" +json jsonm "Non-blocking streaming JSON codec for OCaml" +json json_of_jsonm +json json-pointer "JSON pointer" +json json-predicate "JSON predicate" +json json-rpc "JSON RPC" +json jsonrpc "Jsonrpc protocol implemenation" +json json-static "JSON camlp4 syntax extension using json-wheel" +json json-wheel_jane_street_overlay "Jane Street overlay of the json-wheel library" +json json-wheel "JSON parser and writer, with optional C-style comments" +json jsonxt "Jsonxt - JSON parsers for files, strings and more" +json ocaml-protoc-yojson +json ocplib-json-typed-browser "Json_repr interface over JavaScript's objects" +json ocplib-json-typed-bson "A Json_repr compatible implementation of the JSON compatible subset of BSON" +json ocplib-json-typed "Type-aware JSON and JSON schema utilities" +json tiny_json "A small Json library from OCAMLTTER" +json tiny_json_conv "Meta conv for Tiny Json" +json yajl "Bindings to the YAJL streaming JSON library" +json yajl-extra +json yojson +json yojson-bench "Run Yojson benchmarks" +js promise_jsoo "Js_of_ocaml bindings to JS Promises with supplemental functions" +js promise "Native implementation of a JS promise binding" +js relit_helper "A helper library for those wishing to write TLMs using Relit" +js relit-reason "Hygienic typed literal macros (TLMs) for Reason" +js spotlib_js "Useful functions for OCaml programming used by @camlspotter" +js subscriptions-transport-ws +js user-agent-parser "OCaml implementation of the user agent parse rules of uap-core" +js virtual_dom "OCaml bindings for the virtual-dom library" +js vue-jsoo "Binding of Vue_js" +language alba "Alba compiler" +language archetype "Archetype language compiler" +language asli "Interpreter for Arm's Architecture Specification Language (ASL)" +language baguette_sharp "The Baguette# Interpreter REPL" +language bamboo "A compiler targeting Ethereum Virtual Machine" +language batsh "A (C-like syntax) programming language that compiles to Bash and Windows Batch." +language beluga "Implementation of contextual modal logic for reasoning with higher-order abstract syntax" +language boomerang "The Boomerang Language" +language catala "Compiler and library for the literate programming language for tax code specification" +language cduce "Modern XML-oriented functional language with innovative features" +language cduce_ws "Library fo Web Services creation" +language clarity-lang "Clarity smart contract parser and AST" +language dedukti "An implementation of The Lambda-Pi Modulo Theory" +language elpi "ELPI - Embeddable λProlog Interpreter" +language elpi-option-legacy-parser "ELPI - option for legacy parser" +language frenetic "The Frenetic Programming Language and Runtime System" +language fstar "Verification system for effectful programs" +language gobba "A simple, didactical, purely functional programming language" +language gufo "A fonctionnal shell" +language haxe "Multi-target universal programming language" +language heptagon "Compiler for the Heptagon/BZR synchronous programming language" +language jasmin "Compiler for High-Assurance and High-Speed Cryptography" +language kappa-agents "Backends for an interactive use of the Kappa tool suite" +language kappa-binaries "Command line interfaces of the Kappa tool suite" +language kappa-library "Public internals of the Kappa tool suite" +language kappa-server "HTTP server delivering the Kappa tool suite capabilities" +language KaSim "Software suite for the Kappa language" +language kremlin "A compiler from Low*, a low-level subset of F*, to C" +language labrys "A toy language based on LLVM that implements the System Fω type-system" +language lem "Lem is a tool for lightweight executable mathematics" +language links-mysql "MySQL database driver for the Links Programming Language" +language links-postgresql "Postgresql database driver for the Links Programming Language" +language links-sqlite3 "SQLite database driver for the Links Programming Language" +language links "The Links Programming Language" +language lua-ml "An embeddable Lua 2.5 interpreter implemented in OCaml" +language lua_parser "A Lua 5.2 Parser" +language lua_pattern "Implementation of Lua patterns" +language lustre-v6 "The Lustre V6 Verimag compiler" +language lutils "Tools and libs shared by Verimag/synchronous tools (lustre, lutin, rdbg)" +language mezzo +language minicaml "A simple, didactical, purely functional programming language" +language minimal "Minima.l, a minimal Lisp" +language ocs "OCS: OCaml Scheme interpreter" +language opa-base "Extended standard library developped along the OPA language" +language optal "A new language for optimization" +language ordinal "A language interpreter based on the Forth language" +language oxylc "The compiler for the Oxyl language" +language p4pp "P4PP: Preprocessor for P4 Language" +language p5scm "Scheme via camlp5" +language portia "Literate Programming Preprocessor" +language psyche "A WASM-friendly lightweight programming language implemented in OCaml" +language reason-parser "Reason Parser: Meta Language Toolchain" +language reason "Reason: Syntax & Toolchain for OCaml" +language reason-standard "A portable standard library enhancement for Reason and OCaml." +language sail "Sail is a language for describing the instruction semantics of processors" +language scaml "SCaml, Smart Contract Abstract Machine Language" +language schoca "Implementation of the Scheme language in OCaml" +language sifun "Interpreter for SiFun (Simple Functional) Language with three different type systems (supports Higher Rank Polymorphism)" +language solidity-alcotest "The ocaml-solidity project" +language solidity-common "The ocaml-solidity project" +language solidity-parser "The ocaml-solidity project" +language solidity-test "The ocaml-solidity project" +language solidity-typechecker "The ocaml-solidity project" +language ucaml "Translate OCaml code into C code" +language universo "A tool for Dedukti to play with universes" +language zelus "A synchronous language with ODEs" +language zelus-gtk "Zelus GTK library" +linux aio "Linux kernel AIO access library for ocaml" +linux camldm "Bindings for Linux libdevicemapper" +linux cdrom "Query the state and contents of CDROM devices under Linux" +linux cgroups "An OCaml interface for the Linux control groups" +linux cpuid "Detect CPU features" +linux cpu "Pin current process to given core number" +linux crontab "Interacting with cron from OCaml" +linux dlm "Libdlm bindings" +linux efl "An OCaml interface to the Enlightenment Foundation Libraries (EFL) and Elementary." +linux flock "Ctypes bindings to flock for OCaml" +linux gpiod "A wrapper around the C libgpiod library for GPIO on recent (>4.8) Linux kernels" +linux i2c "i2c" +linux i3ipc "A pure OCaml implementation of the i3 IPC protocol" +linux inotify "Inotify bindings for OCaml" +linux mperf "Bindings to Linux perf's metrics" +linux numalib "Interface to Linux NUMA API" +linux ocaml-systemd "OCaml module for native access to the systemd facilities" +linux pam "OCaml bindings for the Linux-PAM library" +linux socketcan "socketcan" +linux ubpf "OCaml bindings for userspace eBPF VM" +linux uring "OCaml bindings for Linux io_uring" +linux wayland "Pure OCaml Wayland protocol library" +linux waylaunch "Waylaunch is a program launcher for Wayland" +log bolt "Bolt is an OCaml Logging Tool" +log docout "Functor to create (text) output functions" +log dolog "The dumb OCaml logging library" +log easy_logging "Module to log messages. Aimed at being both powerful and easy to use" +log easy_logging_yojson "Configuration loader for easy_logging with yojson backend" +log fluent-logger "Structured logger for Fluentd (OCaml)" +log joolog "Logger for js_of_ocaml" +log little_logger "A tiny, little logger <3" +log loga "Logging library for OCaml" +log logger-p5 "Camlp5 syntax extension for logging" +log logs-async "Jane Street Async logging with Logs" +log logs-async-reporter "Logs reporter compatible with Async's threads" +log logs """Logging infrastructure for OCaml""" +log logs-ppx "PPX to cut down on boilerplate when using Logs" +log logs-syslog "Logs reporter to syslog (UDP/TCP/TLS)" +log lucid "Super simple logging library for OCaml" +log ocamlog "Simple Logger for OCaml" +log taglog "Logging library using levels and tags to determine what to log." +log volt "Volt is a variant of Bolt OCaml Logging Tool" +macos asl "Bindings for the Apple System Log API" +macos cf-lwt "Lwt interface to macOS CoreFoundation" +macos cf "OCaml bindings to macOS CoreFoundation" +macos dnssd "DNS Service Discovery for macOS" +macos fsevents-lwt "Lwt interface to macOS FSEvents" +macos fsevents "OCaml bindings to macOS FSEvents" +macos launchd "Bindings for the launchd socket activation API" +macos osx-acl "OS X POSIX.1e file system access control list (ACL) bindings" +macos osx-attr "OS X generic file system attribute system call bindings" +macos osx-cf "OS X CoreFoundation bindings" +macos osx-fsevents "OS X FSevents bindings" +macos osx-membership "OS X membership.h bindings for user, group, and UUID translation" +macos osx-mount "Bindings to OS X mount system calls" +macos osx-plutil "OS X plutil plist manipulation" +macos osx-secure-transport "macos/ios SecureTransport TLS OSX implementation API for OCaml" +macos osx-xattr "OS X extended attribute system call bindings" +macos plist "Native OCaml Plist manipulation" +macos plist-xml +macos plist-xml-lwt "Reading of plist files in the XML format with Lwt" +macos tallgeese "Enhanced SSH on OS X" +macos vmnet "MacOS X `vmnet` NAT networking" +macos vpnkit "VPN-friendly networking devices for HyperKit" +maths abstract_algebra "A small library describing abstract algebra concepts" +maths antic "Stub of the C library Antic. Algebraic number" +maths apron "APRON numerical abstract domain library" +maths apronext "Apron extension" +maths arb "Stub of the C library Arb. Ball approximation" +maths base-num "Num library distributed with the OCaml compiler" +maths bigdecimal "Arbitrary-precision decimal based on Zarith" +maths bignum +maths calcium "Stub of the C library Antic. For exact computation with real and complex numbers, presently in early development" +maths camlgpc "Interface to Alan Murta's General Polygon Clipper" +maths camlprime "Primality testing with lazy lists of prime numbers" +maths chase "Model finder for geometric theories using the chase" +maths clp_operations "A Clp domain" +maths colibrilib "A library of domains and propagators proved in Why3" +maths crlibm "Binding to CRlibm, a correctly rounded math lib" +maths ctypes-zarith "Ctypes wrapper for zarith" +maths cviode "Contact variational integrators - native ocaml version" +maths decimal "Arbitrary-precision floating-point decimal library" +maths dual "Dual numbers library" +maths eigen "Owl's OCaml interface to Eigen3 C++ library" +maths elina "ETH LIBRARY FOR NUMERICAL ANALYSIS" +maths fadbadml "FADBAD++ for OCaml" +maths farith "Floating point numbers library extracted from the Flocq Coq Library" +maths ff-bench "Benchmark library for finite fields over the package ff-sig" +maths ff "OCaml implementation of Finite Field operations" +maths ff-pbt "Property based testing library for finite fields over the package ff-sig" +maths ff-sig "Minimal finite field signatures" +maths fftw3 "Binding to the famous Fast Fourier Transform library FFTW" +maths flint "Stub of the C library Flint2" +maths genspir "Generate almost uniformly points on a sphere" +maths geoml "Geoml: 2D Geometry library for OCaml" +maths gg "Basic types for computer graphics in OCaml" +maths glpk "Bindings for glpk" +maths gmp-freestanding "The GNU Multiple Precision Arithmetic Library" +maths gmp "The GNU Multiple Precision Arithmetic Library" +maths gmp-xen "The GNU Multiple Precision Arithmetic Library" +maths gpr "GPR - Library and Application for Gaussian Process Regression" +maths gsl "GSL - Bindings to the GNU Scientific Library" +maths integers "Various signed and unsigned integer types for OCaml" +maths integration1d "Integration of functions of one variable" +maths interval "An interval arithmetic library for OCaml (meta package)" +maths interval_base "An interval library for OCaml (base package)" +maths interval_crlibm "An interval library for OCaml (crlibm version)" +maths interval_intel "An interval library for OCaml" +maths int_repr "Integers of various widths" +maths itv-tree "float intervals tree library" +maths lacaml "OCaml-bindings to BLAS and LAPACK" +maths lbfgs "Bound-constrainted optimization in many variables" +maths lp-glpk-js "LP and MIP modeling in OCaml (glpk.js interface)" +maths lp-glpk "LP and MIP modeling in OCaml (GLPK interface)" +maths lp-gurobi "LP and MIP modeling in OCaml (Gurobi interface)" +maths lpi "A REPL and library for a small dependently-typed language." +maths lp "LP and MIP modeling in OCaml" +maths mlgmpidl "OCaml interface to the GMP library" +maths mlgmp "Interface of GNU MP and MPFR" +maths mlmpfr "OCaml C bindings for MPFR-4.1.0" +maths modular-arithmetic +maths nlopt "OCaml bindings to the NLOpt optimization library" +maths num +maths numerix "Big integer library, written by Michel Quercia. Compares well to GMP." +maths ocephes "Bindings to special math functions from the Cephes library." +maths odepack "Binding to ODEPACK" +maths oml "Math Library" +maths omlr "Multiple Linear Regression model" +maths oplsr "OCaml wrapper for the R 'pls' package" +maths opti "DSL to generate fast incremental C code from declarative specifications" +maths optimization1d "Find extrema of 1D functions" +maths optiml-transport +maths owl-base "OCaml Scientific and Engineering Computing - Base" +maths owl-jupyter "Owl - Jupyter Wrappter" +maths owl "OCaml Scientific and Engineering Computing" +maths owl-ode-base "Owl's ODE solvers" +maths owl-ode-odepack "Owl's ODE solvers, interface with ODEPACK" +maths owl-ode "Owl's ODE solvers" +maths owl-ode-sundials "Owl's ODE solvers, interface with SundialsML" +maths owl-opt-lbfgs "Owl's Lbfgs Optimisation Module" +maths owl-opt "Owl's Optimisation Module" +maths owl-plplot "OCaml Scientific and Engineering Computing" +maths owl-symbolic "Owl's Symbolic Library" +maths owl-top "OCaml Scientific and Engineering Computing - Top" +maths owl-zoo "OCaml Scientific and Engineering Computing - Zoo" +maths pareto "GSL powered OCaml statistics library." +maths phantom-algebra "A strongly-typed tensor library à la GLSL" +maths pilat "Polynomial invariant generator" +maths polka "Polka: convex polyhedron library by Bertrand Jeannet (now part of apron)" +maths polynomial "Polynomials over finite fields" +maths prbnmcn-linalg "Functional vector and matrix manipulation" +maths prc "Utilities for precision-recall curves" +maths primes "A small library for dealing with primes." +maths root1d "Find roots of 1D functions" +maths slap "A linear algebra library with static size checking for matrix operations" +maths smol-helpers "Test helpers for smol" +maths smol "Small Math Ocaml Library" +maths tofn "Typed ordered fuzzy numbers" +maths tplib "TPLib: Tropical Polyhedra Library" +maths vector3 "Module for 3D vectors (implemented as records of x, y and z floats)" +maths zarith +maths zarith-freestanding +maths zarith-ppx "Literals for Zarith's arbitrary-precision integers and rationals" +maths zarith_stubs_js "Javascripts stubs for the Zarith library" +maths zarith-xen +mirage albatross "Albatross - orchestrate and manage MirageOS unikernels with Solo5" +mirage arp-mirage "Address Resolution Protocol for MirageOS" +mirage chamelon "Subset of littlefs filesystem fulfilling MirageOS KV" +mirage chamelon-unix "Command-line Unix utilities for chamelon filesystems" +mirage channel "MirageOS channels" +mirage docteur "A simple read-only Key/Value from Git to MirageOS" +mirage docteur-solo5 "A simple read-only Key/Value from Git to MirageOS" +mirage docteur-unix "A simple read-only Key/Value from Git to MirageOS" +mirage dyntype "syntax extension which makes OCaml types and values easier to manipulate programmatically" +mirage ethernet "OCaml Ethernet (IEEE 802.3) layer, used in MirageOS" +mirage fat-filesystem "FAT filesystem implementation" +mirage functoria "A DSL to organize functor applications" +mirage functoria-runtime "Runtime support library for functoria-generated code" +mirage git-cohttp "A package to use HTTP-based ocaml-git with Unix backend" +mirage git-cohttp-mirage "A package to use HTTP-based ocaml-git with MirageOS backend" +mirage git-cohttp-unix "A package to use HTTP-based ocaml-git with Unix backend" +mirage git-mirage "A package to use ocaml-git with MirageOS backend" +mirage git-paf "A package to use HTTP-based ocaml-git with MirageOS backend" +mirage git-unix "Virtual package to install and configure ocaml-git's Unix backend" +mirage iso-filesystem "ISO9660 filesystem library" +mirage jitsu +mirage jitsu-libvirt "Virtual package for installing Jitsu with a libvirt backend." +mirage jitsu-libxl +mirage jitsu-xapi +mirage mirage-block "Block signatures and implementations for MirageOS" +mirage mirage-block-ccm "AES-CCM encrypted Mirage Mirage_types.BLOCK storage" +mirage mirage-block-combinators "Block signatures and implementations for MirageOS using Lwt" +mirage mirage-block-lwt "Block signatures and implementations for MirageOS using Lwt" +mirage mirage-block-partition "Mirage block device partitioning" +mirage mirage-block-ramdisk "In-memory BLOCK device for MirageOS" +mirage mirage-block-solo5 "Solo5 implementation of MirageOS block interface" +mirage mirage-block-unix "MirageOS disk block driver for Unix" +mirage mirage-block-xen "MirageOS block driver for Xen that implements the blkfront/back protocol" +mirage mirage-bootvar-solo5 "Solo5 implementation of MirageOS Bootvar interface" +mirage mirage-bootvar-unix "Unix implementation of MirageOS Bootvar interface" +mirage mirage-bootvar-xen "Handle boot-time arguments for Xen platform" +mirage mirage-btrees +mirage mirage-channel "Buffered channels for MirageOS FLOW types" +mirage mirage-channel-lwt "Buffered Lwt channels for MirageOS FLOW types" +mirage mirage-clock-freestanding "Paravirtual implementation of the MirageOS Clock interface" +mirage mirage-clock "Libraries and module types for portable clocks" +mirage mirage-clock-lwt "Lwt-based implementation of the MirageOS Clock interface" +mirage mirage-clock-solo5 "Paravirtual implementation of the MirageOS Clock interface" +mirage mirage-clock-unix "Unix-based implementation for the MirageOS Clock interface" +mirage mirage-clock-xen "A Mirage-compatible Clock library for Xen" +mirage mirage-conduit "MirageOS interface to network connections" +mirage mirage-console "Implementations of Mirage console devices" +mirage mirage-console-lwt "Implementation of Mirage consoles using Lwt" +mirage mirage-console-solo5 "Solo5 implementation of MirageOS console interface" +mirage mirage-console-unix "Implementation of Mirage consoles for Unix" +mirage mirage-console-xen-backend "Implementation of Mirage console backend for Xen" +mirage mirage-console-xen-cli +mirage mirage-console-xen "Implementation of Mirage console for Xen" +mirage mirage-console-xen-proto "Implementation of Mirage console protocol for Xen" +mirage mirage-crypto-ec "Elliptic Curve Cryptography with primitives taken from Fiat" +mirage mirage-crypto-entropy "Entropy source for MirageOS unikernels" +mirage mirage-crypto-pk "Simple public-key cryptography for the modern age" +mirage mirage-crypto-rng "A cryptographically secure PRNG" +mirage mirage-crypto-rng-async "Feed the entropy source in an Async-friendly way" +mirage mirage-crypto-rng-eio "Feed the entropy source in an eio-friendly way" +mirage mirage-crypto-rng-mirage "Entropy collection for a cryptographically secure PRNG" +mirage mirage-crypto "Simple symmetric cryptography for the modern age" +mirage mirage-device "Abstract devices for MirageOS" +mirage mirage-dns "DNS implementation for the MirageOS unikernel framework" +mirage mirage-entropy "Entropy source for MirageOS unikernels" +mirage mirage-entropy-unix "MirageOS entropy device" +mirage mirage-entropy-xen "MirageOS entropy device" +mirage mirage-flow-combinators "Flow implementations and combinators for MirageOS specialized to lwt" +mirage mirage-flow "Flow implementations and combinators for MirageOS" +mirage mirage-flow-lwt "Flow implementations and combinators for MirageOS specialized to lwt" +mirage mirage-flow-rawlink "Expose rawlink interfaces as MirageOS flows" +mirage mirage-flow-unix "Flow implementations and combinators for MirageOS on Unix" +mirage mirage-fs-lwt "MirageOS signatures for filesystem devices using Lwt" +mirage mirage-fs-mem "In-memory file system for for MirageOS" +mirage mirage-fs "MirageOS signatures for filesystem devices" +mirage mirage-fs-unix "Passthrough filesystem for MirageOS on Unix" +mirage mirage-git "Virtual package to install the `git.mirage` libary" +mirage mirage-http "MirageOS-compatible implementation of the Cohttp interfaces" +mirage mirage-http-unix "MirageOS HTTP client and server driver for Unix" +mirage mirage-http-xen "MirageOS HTTP client and server driver for Xen" +mirage mirage-irmin "Virtual package to install Irmin with mirage support" +mirage mirage-kv-lwt "MirageOS signatures for key/value devices" +mirage mirage-kv-mem "In-memory key value store for MirageOS" +mirage mirage-kv "MirageOS signatures for key/value devices" +mirage mirage-kv-unix "Key-value store for MirageOS backed by Unix filesystem" +mirage mirage-logs "A reporter for the Logs library that writes log messages to stderr, using a Mirage `CLOCK` to add timestamps" +mirage mirage-monitoring "Monitoring of MirageOS unikernels" +mirage mirage-nat "Mirage-nat is a library for network address translation to be used with MirageOS" +mirage mirage-net-direct "TCP/IP networking stack in pure OCaml" +mirage mirage-net-fd "MirageOS network interfaces using raw sockets" +mirage mirage-net-flow "Build MirageOS network interfaces on top of MirageOS flows" +mirage mirage-net-lwt "Network signatures for MirageOS" +mirage mirage-net-macosx "MacOS implementation of the Mirage_net_lwt interface" +mirage mirage-net "Network signatures for MirageOS" +mirage mirage-net-socket "Socket-based networking stack compatible with Mirage" +mirage mirage-net-solo5 "Solo5 implementation of MirageOS network interface" +mirage mirage-net-unix "Unix implementation of the Mirage_net_lwt interface" +mirage mirage-net-xen "Network device for reading and writing Ethernet frames via then Xen netfront/netback protocol" +mirage mirage-no-solo5 "Virtual package conflicting with mirage-solo5" +mirage mirage-no-xen "Virtual package conflicting with mirage-xen" +mirage mirage-os-shim "Portable shim for MirageOS OS API" +mirage mirage-profile "Collect runtime profiling information in CTF format" +mirage mirage-profile-unix "Collect runtime profiling information in CTF format" +mirage mirage-profile-xen "Collect runtime profiling information in CTF format" +mirage mirage-protocols-lwt "MirageOS signatures for network protocols" +mirage mirage-protocols "MirageOS signatures for network protocols" +mirage mirage-qubes "Implementations of various Qubes protocols for MirageOS" +mirage mirage-qubes-ipv4 "Implementations of IPv4 stack which reads configuration from QubesDB for MirageOS" +mirage mirage-random "Random-related devices for MirageOS" +mirage mirage-random-stdlib "Random device implementation using the OCaml stdlib" +mirage mirage-random-test "Stub random device implementation for testing" +mirage mirage-runtime "The base MirageOS runtime library, part of every MirageOS unikernel" +mirage mirage-seal "Serve static files over HTTPS, using Mirage+ocaml-TLS." +mirage mirage-solo5 "Solo5 core platform libraries for MirageOS" +mirage mirage-stack-lwt "MirageOS signatures for network stacks" +mirage mirage-stack "MirageOS signatures for network stacks" +mirage mirage-tc "MirageOS type-classes" +mirage mirage-tcpip-unix "Userlevel TCP/IP stack" +mirage mirage-tcpip-xen "Userlevel TCP/IP stack" +mirage mirage "The MirageOS library operating system" +mirage mirage-time-lwt "Time operations for MirageOS with Lwt" +mirage mirage-time "Time operations for MirageOS" +mirage mirage-time-unix "Time operations for MirageOS on Unix" +mirage mirage-types-lwt "Lwt module type definitions for MirageOS applications" +mirage mirage-types "Module type definitions for MirageOS applications" +mirage mirage-unix "Unix core platform libraries for MirageOS" +mirage mirage-vnetif-stack "Vnetif implementation of mirage-stack for Mirage TCP/IP" +mirage mirage-vnetif "Virtual network interface and software switch for Mirage" +mirage mirage-www "MirageOS website (written with MirageOS)" +mirage mirage-xen-minios "Xen MiniOS guest operating system library" +mirage mirage-xen-ocaml "OCaml runtime compiled for the MirageOS Xen backend" +mirage mirage-xen-posix "MirageOS library for posix headers" +mirage mirage-xen "Xen core platform libraries for MirageOS" +mirage mirari "MirageOS application builder" +mirage oneffs "One-file filesystem is a filesystem for storing a single unnamed file" +mirage paf "HTTP/AF and MirageOS" +mirage solo5-bindings-genode "Solo5 sandboxed execution environment (genode target)" +mirage solo5-bindings-hvt "Solo5 sandboxed execution environment (hvt target)" +mirage solo5-bindings-muen "Solo5 sandboxed execution environment (muen target)" +mirage solo5-bindings-spt "Solo5 sandboxed execution environment (spt target)" +mirage solo5-bindings-virtio "Solo5 sandboxed execution environment (virtio target)" +mirage solo5-bindings-xen "Solo5 sandboxed execution environment (xen target)" +mirage solo5-cross-aarch64 "Solo5 sandboxed execution environment" +mirage solo5-elftool "OCaml Solo5 elftool for querying solo5 manifests" +mirage solo5-kernel-muen "Solo5 sandboxed execution environment (muen target)" +mirage solo5-kernel-ukvm "Solo5 sandboxed execution environment (ukvm target)" +mirage solo5-kernel-virtio "Solo5 sandboxed execution environment (virtio target)" +mirage solo5 "Solo5 sandboxed execution environment" +mirage tcpip "OCaml TCP/IP networking stack, used in MirageOS" +mirage tftp "A TFTP library and Mirage unikernel" +monads algaeff "Reusable Effects-Based Components" +monads alg_structs "Interfaces and module combinators for algebraic structures" +monads bastet "An OCaml library for category theory and abstract algebra" +monads bastet_async "Async implementations for bastet" +monads bastet_lwt "Lwt implementations for bastet" +monads choice "Choice monad, for easy backtracking" +monads duppy "Library providing monadic threads" +monads interface-prime "Interfaces for common design patterns" +monads interface-prime-lwt "Interfaces for common design patterns (LWT implementation)" +monads lemonade "A monad library with bubbles" +monads mnd "A small monads library" +monads monadlib "A starter library for monads, with transformers and applicatives." +monads monads "A missing monad library" +monads mtl "A Monad Transformers Library for OCaml" +monads olmi "Olmi provide functor to generate monadic combinators with a minimal interface" +monads omonad "Monad programming using ppx preprocessor" +monads profunctor "A library providing a signature for simple profunctors and traversal of a record" +monads pvem "Polymorphic-Variants-based Error Monad" +monads rea "Effectful OCaml with Objects and Variants" +monads sugar "Monadic library for error aware expressions" +monads traverse "Traversable data structures with applicative functors" +monads travesty "Traversable containers, monad extensions, and more" +monitor catapult-client "Network client for catapult, to be paired with catapult-daemon" +monitor catapult-daemon "Daemon for reliable multi-process logging with catapult" +monitor catapult-file "File logger for catapult" +monitor catapult-sqlite "Sqlite-based backend for Catapult tracing" +monitor catapult "Tracing system based on the Catapult/TEF format" +monitor chrome-trace "Chrome trace event generation library" +monitor gdbprofiler "A profiler for native OCaml and other executables" +monitor genet "Genet is tool to build a continuous integration platform." +monitor landmarks "A simple profiling library" +monitor landmarks-ppx "Preprocessor instrumenting code using the landmarks library" +monitor magic-trace "Collects and displays high-resolution traces of what a process is doing" +monitor memprof-limits "Memory limits, allocation limits, and thread cancellation" +monitor memtrace-mirage "Streaming client for Memprof using MirageOS API" +monitor memtrace "Streaming client for Memprof" +monitor memtrace_viewer "Interactive memory profiler based on Memtrace" +monitor mem_usage "Cross-platform stats about memory usage" +monitor metrics-influx "Influx reporter for the Metrics library" +monitor metrics-lwt "Lwt backend for the Metrics library" +monitor metrics "Metrics infrastructure for OCaml" +monitor metrics-mirage "Mirage backend for the Metrics library" +monitor metrics-rusage "Resource usage (getrusage) sources for the Metrics library" +monitor metrics-unix "Unix backend for the Metrics library" +monitor ocamlviz "real-time profiling tool" +monitor oci "OCI is a framework for continuous integrations and benchmarks." +monitor ocveralls +monitor ometrics "OCaml analysis in a merge request changes" +monitor opentelemetry-client-ocurl "Collector client for opentelemetry, using http + ocurl" +monitor opentelemetry-cohttp-lwt "Opentelemetry tracing for Cohttp HTTP servers" +monitor opentelemetry "Instrumentation for https://opentelemetry.io" +monitor opentelemetry-lwt "Lwt-compatible instrumentation for https://opentelemetry.io" +monitor opsian "Low overhead profiling" +monitor papi "Performance Application Programming Interface (PAPI) bindings" +monitor perf "Binding to perf_event_open" +monitor profiler-plugin +monitor prof_spacetime "A viewer for OCaml spacetime profiles" +monitor prometheus-app "Client library for Prometheus monitoring" +monitor prometheus "Client library for Prometheus monitoring" +monitor prometheus-liquidsoap "Virtual package installing liquidsoap's prometheus dependencies" +monitor prom "Types and pretty printer for Prometheus text-based exposition format" +monitor raw_spacetime "Raw_spacetime_lib library distributed with the OCaml compiler" +monitor raygun4ocaml "Client for the Raygun error reporting API" +monitor runtime_events_tools "Tools for the runtime events tracing system in OCaml" +monitor sentry "Unofficial Async Sentry error monitoring client" +monitor spacetime_lib "Library for decoding OCaml spacetime profiles" +monitor statmemprof-emacs "Emacs client for statistical memory profiler" +monitor statsd-client "StatsD client library" +monitor travis-opam "Scripts for OCaml projects" +monitor travis-senv "Utility to manipulate Travis CI secure environment variables" +multimedia gstreamer +multimedia liquidsoap-daemon "Daemonization scripts for liquidsoap" +multimedia liquidsoap "Swiss-army knife for multimedia streaming" +multimedia mm "The mm library contains high-level to create and manipulate multimedia streams (audio, video, MIDI)" +multimedia mpris "Client library for the MPRIS D-Bus media player interface" +multimedia mpris-clients "Client implementations of the MPRIS D-Bus media player interface" +multimedia sfml "Bindings to the SFML multimedia library" +network amqp-client "Amqp client base library" +network amqp-client-async "Amqp client library, async version" +network amqp-client-lwt "Amqp client library, lwt version" +network apero-net "OCaml Networking Library" +network arp "Address Resolution Protocol purely in OCaml" +network async_durable "Durable connections for use with async" +network async_rpc_kernel "Platform-independent core of Async RPC library" +network async_rpc_websocket "Library to serve and dispatch Async RPCs over websockets" +network async_smtp "SMTP client and server" +network async_ssl "An Async-pipe-based interface with OpenSSL." +network async_udp "Monadic concurrency library" +network async-uri "Open Async (TLS) TCP connections with Uri.t" +network async_websocket "A library that implements the websocket protocol on top of Async" +network async-zmq "Async wrapper for OCaml's zeromq bindings" +network bitcoin +network bitcoinml "Bitcoin data-structures library for OCaml" +network bt "BitTorrent library and client using Lwt" +network ca-certs "Detect root CA certificates from the operating system" +network ca-certs-nss "X.509 trust anchors extracted from Mozilla's NSS" +network capnp "OCaml code generation plugin for the Cap'n Proto serialization framework" +network capnp-rpc +network capnp-rpc-lwt +network capnp-rpc-mirage +network capnp-rpc-net +network capnp-rpc-unix +network charrua-client "DHCP client implementation" +network charrua-client-lwt "A DHCP client using lwt as effectful layer" +network charrua-client-mirage "A DHCP client for MirageOS" +network charrua-core "DHCP - a DHCP client, server and wire frame encoder and decoder" +network charrua "DHCP wire frame encoder and decoder" +network charrua-server "DHCP server" +network charrua-unix "Unix DHCP daemon" +network conduit "A network connection establishment library" +network conduit-async "A network connection establishment library for Async" +network conduit-async-ssl "A network connection establishment library using Async and OpenSSL" +network conduit-async-tls "A network connection establishment library using Async and ocaml-tls" +network conduit-lwt "A portable network connection establishment library using Lwt" +network conduit-lwt-ssl "A portable network connection establishment library using Lwt and OpenSSL" +network conduit-lwt-tls "A portable network connection establishment library using Lwt and ocaml-tls" +network conduit-lwt-unix "A network connection establishment library for Lwt_unix" +network conduit-mirage "A network connection establishment library for MirageOS" +network conduit-tls "A network connection establishment library" +network cry "OCaml client for the various icecast & shoutcast source protocols" +network daft "DAFT Allows File Transfers" +network dht "OCaml bindings for Juliusz Chroboczek's dht C library" +network disml "An OCaml library for interfacing with the Discord API" +network dropbox "Binding to the Dropbox Remote API" +network dropbox_lwt_unix "Binding to the Dropbox Remote API (Unix)" +network facebook-sdk "Facebook Graph API SDK for OCaml" +network ftp "Functions for accessing files via FTP" +network functory "Distributed computing library." +network gammu "Cell phone and SIM card access" +network gluten "A reusable runtime library for network protocols" +network gluten-async "Async runtime for gluten" +network gluten-lwt "Lwt-specific runtime for gluten" +network gluten-lwt-unix "Lwt + Unix support for gluten" +network gluten-mirage "Mirage support for gluten" +network grpc "A modular gRPC library" +network grpc-async "An Async implementation of gRPC" +network grpc-lwt "An Lwt implementation of gRPC" +network happy-eyeballs "Connecting to a remote host via IP version 4 or 6" +network happy-eyeballs-lwt "Connecting to a remote host via IP version 4 or 6 using Lwt_unix" +network happy-eyeballs-mirage "Connecting to a remote host via IP version 4 or 6 using Mirage" +network hydro "An independent implementation of ICE, the object-oriented RPC protocol by ZeroC" +network ip2location "IP2Location OCaml module to get geolocation data" +network ipaddr "A library for manipulation of IP (and MAC) address representations" +network ipaddr-cstruct "A library for manipulation of IP address representations using Cstructs" +network ipaddr-sexp "A library for manipulation of IP address representations using sexp" +network ipv6-multicast-lwt "UNIX bindings for IPv6 multicast — Lwt" +network ipv6-multicast "UNIX bindings for IPv6 multicast" +network iri "Implementation of Internationalized Resource Identifiers (IRIs)" +network krb5 "Kerberos 5 bindings" +network krb "A library for using Kerberos for both Rpc and Tcp communication" +network ldap "Implementation of the Light Weight Directory Access Protocol" +network lpd "A Line Printer Daemon (LPD) server library written entirely in OCaml." +network macaddr "A library for manipulation of MAC address representations" +network macaddr-cstruct "A library for manipulation of MAC address representations using Cstructs" +network macaddr-sexp "A library for manipulation of MAC address representations using sexp" +network macaroons "Macaroons for OCaml" +network maxminddb "Bindings to Maxmind.com's libmaxminddb library, like geoip2" +network mechaml "A functional web scraping library" +network message-switch "A simple store-and-forward message switch." +network mimic "A simple protocol dispatcher" +network mimic-happy-eyeballs "A happy-eyeballs integration into mimic" +network mindstorm "Drive Lego Mindstorms bricks from OCaml" +network mindstorm-lwt "Drive Lego Mindstorms bricks from OCaml (LWT version)" +network mldonkey "Cross-platform multi-network peer-to-peer daemon" +network monorobot "Notification bot for monorepos" +network mosquitto "mosquitto" +network mpi "OCaml binding to the Message Passing Interface (MPI)" +network mqtt_client "MQTT pub/sub transport protocol client written in OCaml" +network mqtt "MQTT message parser in OCaml" +network nbd "Network Block Device (NBD) protocol implementation" +network nbd-tool "Network Block Device (NBD) protocol implementation" +network nbd-unix "Network Block Device (NBD) protocol implementation" +network netamqp "Implements an AMQP client for accessing a message broker" +network netkat "A clean slate implementation of NetKAT" +network netlink "Bindings to the Netlink Protocol Library Suite (libnl)" +network netml "Network packets authoring and parsing toolkit." +network netsnmp "An interface to the Net-SNMP client library" +network nsq "A client library for the NSQ messaging platform" +network nuscr "A tool to manipulate and validate Scribble-style multiparty protocols" +network obandit "Ocaml Multi-Armed Bandits" +network obeanstalk "Async based client for the beanstalk work queue" +network obus "Pure Ocaml implementation of the D-Bus protocol" +network ocaml-gist "A tool to create online OCaml gist experiences for the web" +network ocamlnet +network ocamltter "The OCAMLTTER OAuth1 library and twitter, flickr clients" +network ocaml-zmq "OCaml bindings for ZMQ 2.1" +network ocluster-api "Cap'n Proto API for OCluster" +network ocluster "Distribute build jobs to workers" +network ocplib-resto "Minimal OCaml library for type-safe HTTP/JSON RPCs." +network odisco "OCaml library for Disco workers." +network oidc "Base package for working with OIDC" +network oni "Oni - assorted components for low-level networking." +network openstellina "A http client for Stellina smart telescope by Vaonis" +network oraft "Raft consensus algorithm implemented in OCaml" +network ordma "Ordma provides OCaml bindings to librdmacm (rsocket)" +network ox "A platform for writing OpenFlow controllers" +network pb "Library for describing Protobuf messages" +network pb-plugin "Plugin for generating pb protobuf message descriptions" +network pbrt "Runtime library for Protobuf tooling" +network pbs "Helper library around PBS/Torque" +network plasma "Distributed filesystem for large files, implemented in user space" +network protobuf "Protobuf implementation for Ocaml" +network protocell "A Protobuf plugin for OCaml" +network protocol_version_header "Protocol versioning" +network rawlink-eio "Portable library to read and write raw packets with EIO bindings" +network rawlink-lwt "Portable library to read and write raw packets with Lwt bindings" +network rawlink "Portable library to read and write raw packets" +network resto-acl "Access Control Lists for Resto" +network resto "A minimal OCaml library for type-safe HTTP/JSON RPCs" +network resto-cohttp "A minimal OCaml library for type-safe HTTP/JSON RPCs" +network resto-cohttp-client "A minimal OCaml library for type-safe HTTP/JSON RPCs" +network resto-cohttp-self-serving-client "A minimal OCaml library for type-safe HTTP/JSON RPCs" +network resto-cohttp-server "A minimal OCaml library for type-safe HTTP/JSON RPCs - server library" +network resto-directory "A minimal OCaml library for type-safe HTTP/JSON RPCs" +network resto-json "A minimal OCaml library for type-safe HTTP/JSON RPCs" +network river "RSS2 and Atom feed aggregator for OCaml" +network rpc "A library to deal with RPCs in OCaml - meta-package" +network rpclib "A library to deal with RPCs in OCaml" +network rpclib-async "A library to deal with RPCs in OCaml - Async interface" +network rpclib-html +network rpclib-js "A library to deal with RPCs in OCaml - Bindings for js_of_ocaml" +network rpclib-lwt "A library to deal with RPCs in OCaml - Lwt interface" +network rpc_parallel "Type-safe parallel library built on top of Async_rpc" +network simple_pam "Tiny binding around PAM" +network sonet "Collection of modules for asynchronous network applications" +network srt "Binding for the Secure, Reliable, Transport protocol library" +network ssl "Bindings for OpenSSL" +network sslconf "An OCaml version of Openssl's NCONF library" +network tls-async "Transport Layer Security purely in OCaml, Async layer" +network tls-eio "Transport Layer Security purely in OCaml - Eio" +network tls-mirage "Transport Layer Security purely in OCaml, MirageOS layer" +network tls "Transport Layer Security purely in OCaml" +network tlstunnel "Tunnel -- a TLS reverse proxy" +network transmission-rpc "A client library for the Transmission Bittorrent client RPC" +network tuntap "OCaml library for handling TUN/TAP devices" +network unison "File-synchronization tool for Unix and Windows" +network utp "OCaml bindings for libutp" +network wamp-msgpck +network wamp "Web Application Messaging Protocol (WAMP) library — Core library" +network wamp-yojson "Web Application Messaging Protocol (WAMP) library — Yojson support" +network webdav "Implements the client side of the WebDAV protocol (RFC 4918)" +network zmq-async "Async-aware bindings to ZMQ" +network zmq-lwt "Lwt-aware bindings to ZMQ" +network zmq "OCaml bindings for ZeroMQ 4.x" +notebook down "An OCaml toplevel (REPL) upgrade" +notebook iocaml "A webserver for iocaml-kernel and iocamljs-kernel." +notebook iocamljs-kernel "An OCaml javascript kernel for the IPython notebook." +notebook iocaml-kernel "An OCaml kernel for the IPython notebook." +notebook jupyter "An OCaml kernel for Jupyter notebook" +notebook jupyter-archimedes "A Jupyter-friendly 2D plotting library (Archimedes backend)" +notebook jupyter-kernel "Library to write jupyter kernels (interactive notebooks)" +notebook nosetup "An `.ocamlinit` helper to `#require` packages in an OCaml toplevels" +notebook ocaml-top "The OCaml interactive editor for education" +notebook oloop "Evaluate code through the OCaml toploop for inclusion in educational material." +notebook rtop "Reason toplevel" +notebook tophide "Hides toplevel values whose name starts with an underscore" +notebook toplevel_backend "Shared backend for setting up toplevels" +notebook utop "Universal toplevel for OCaml" +opam ez_opam_file +opam hll "Create opam package files from a repository" +opam mirror "Mirror upstream OPAM package distribution files" +opam opam-0install-cudf "Opam solver using 0install backend using the CUDF interface" +opam opam-0install "Opam solver using 0install backend" +opam opam2web "Tool to generate the opam.ocaml.org website" +opam opam-bin +opam opam_bin_lib +opam opam-build "An opam plugin to build projects" +opam opam-build-revdeps "Build reverse dependencies of a package in OPAM" +opam opam-bundle "A tool that creates stand-alone source bundles from opam packages" +opam opam-ci "Query the opam package build status" +opam opam-client "Client library for opam 2.1" +opam opam-compiler "Plugin to create switches using custom compilers" +opam opamconfig "Virtual package owning parameters of opam installation." +opam opam-core "Core library for opam 2.1" +opam opam-custom-install "An opam plugin to install a package using a custom command" +opam opam-depext "Install OS distribution packages" +opam opam-devel "Bootstrapped development binary for opam 2.1" +opam opam-doc "Produce documentation for OPAM packages" +opam opam-dune-lint "Ensure dune and opam dependencies are consistent" +opam opam-ed "Command-line edition tool for handling the opam file syntax" +opam opam-file-format "Parser and printer for the opam file syntax" +opam opamfind +opam opam-format "Format library for opam 2.1" +opam opamfu "Functions over OPAM Universes" +opam opam-grep +opam opam-installer "Installation of files to a prefix, following opam conventions" +opam opam-installext "OPAM plugin to install external system dependencies" +opam opam-lib "The OPAM library" +opam opam-lock "Locking of development package definition dependency versions" +opam opam-monorepo "Assemble and manage fully vendored Dune repositories" +opam opam_of_packagejson "Simple tool to generate META, opam and .install files." +opam opam-package-upgrade "Upgrades opam package definition files to the latest format" +opam opam-publish "A tool to ease contributions to opam repositories" +opam opam-query "A tool to query opam files from shell scripts" +opam opam-repository "Repository library for opam 2.1" +opam opam-solver "Solver library for opam 2.1" +opam opam-spin "Opam plugin for Spin, the OCaml project generator" +opam opam-state "State library for opam 2.1" +opam opam-sync-github-prs "Sync OCaml GitHub issues with OPAM" +opam opam-test "An opam plugin to test projects" +packaging oasis2debian "Create and maintain Debian package for an OASIS package" +packaging oasis2opam "Tool to convert OASIS metadata to OPAM package descriptions" +packaging oasis-mirage "This is a fork of OASIS with support for native output-obj." +packaging oasis "Tooling for building OCaml libraries and applications" +packaging publish "opam-publish transition package" +packaging topkg-care """The transitory OCaml software packager""" +packaging topkg-jbuilder "Helpers for using topkg with jbuilder" +packaging topkg """The transitory OCaml software packager""" +parser acgtk "Abstract Categorial Grammar development toolkit" +parser angstrom-async "Angstrom - Async-specific support" +parser angstrom-lwt-unix "Angstrom - Lwt- and Unix-specific support" +parser angstrom "Parser combinators built for speed and memory-efficiency" +parser angstrom-unix "Angstrom - Unix-specific support" +parser bark "Unofficial OCaml port of elm/parser (v1.1.0)" +parser camlp4 "Camlp4 is a system for writing extensible parsers for programming languages" +parser cfg "CFG - Context-Free Grammars" +parser delimited_parsing "Parsing of character (e.g., comma) separated and fixed-width values" +parser dypgen "Self-extensible parsers and lexers for OCaml" +parser earley-ocaml +parser earley "Parsing library based on Earley Algorithm" +parser edn "Parsing OCaml library for EDN format" +parser fmlib_parse "Parsing with combinators and indentation sensitivity" +parser grain_dypgen "Self-extensible parsers and lexers for OCaml" +parser menhir "An LR(1) parser generator" +parser menhirLib "Runtime support library for parsers generated by Menhir" +parser menhirSdk "Compile-time library for auxiliary tools related to Menhir" +parser mparser "A simple monadic parser combinator library" +parser mparser-pcre "MParser plugin: PCRE-based regular expressions" +parser mparser-re "MParser plugin: RE-based regular expressions" +parser nacc "Not Another Compiler Compiler" +parser nice_parser "Nice parsers without the boilerplate" +parser nlp "Natural Language Processing tools for OCaml" +parser opal "Self-contained monadic parser combinators for OCaml" +parser ostap "Parser-combinator library" +parser pacomb "Parsing library based on combinators and ppx extension to write languages" +parser parsley "Parsley library" +parser planck "A small monadic parser combinator library" +parser pratter "An extended Pratt parser" +parser qinap "A (very small) monadic parsing library" +parser reparse-lwt "Reparse Lwt_stream.t input support" +parser reparse-lwt-unix "Reparse lwt-unix based input support" +parser reparse "Recursive descent parsing library for ocaml" +parser reparse-unix +parser tjr_simple_earley +parser transept "Generalized parser combinator library" +parser unstrctrd "Unstructured parser" +plt abt "OCaml port of CMU's abstract binding trees" +plt alonzo "STLC type system" +plt alphaCaml +plt anders "Modal Homotopy Type System" +plt bindlib "OCaml Bindlib library for bound variables" +plt bpf "Embedded eBPF assembler" +plt calipso "Rewrites C programs to remove non-structured control-flow" +plt cca "A framework for differential source code analyses" +plt cil "A front-end for the C programming language that facilitates program analysis and transformation" +plt clangml "OCaml bindings for Clang API" +plt clangml-transforms "Code transformers for clangml" +plt dap "Debug adapter protocol" +plt deadlock "Frama-C plugin for deadlock detection" +plt dolmen "A parser library for automated deduction" +plt dolmen_bin "A linter for logic languages" +plt dolmen_loop "A tool library for automated deduction tools" +plt dolmen_lsp "A LSP server for automated deduction languages" +plt dolmen_type "A typechecker for automated deduction languages" +plt ego "Ego (EGraphs OCaml) is extensible EGraph library for OCaml" +plt electrod "Formal analysis for the Electrod formal pivot language" +plt electrumAnalyzer "A tool for the analysis of Electrum formal specifications." +plt erlang "Libraries to manipulate Erlang sources" +plt flow_parser "The Flow parser is a JavaScript parser written in OCaml" +plt flowtype "Flow is a static typechecker for JavaScript." +plt frama-c +plt frama-c-base "Platform dedicated to the analysis of source code written in C." +plt frama-c-e-acsl "This package contains the Frama-C's E-ACSL plug-in." +plt frama-c-lannotate "Lannotate plugin of Frama-C, part of the LTest suite " +plt frama-c-luncov "Luncov plugin of Frama-C, part of the LTest suite " +plt frama-c-metacsl "MetACSL plugin of Frama-C for writing pervasives properties" +plt FrontC "Parses C programs to an abstract syntax tree" +plt gdb "GDB/MI (machine interface) library and stack-sampling profiler" +plt goblint-cil "A front-end for the C programming language that facilitates program analysis and transformation" +plt goblint "Static analysis framework for C" +plt grain_wasm_spec "An OCaml library to read and write Web Assembly (wasm) files and manipulate their AST" +plt herdtools7 "The herdtools suite for simulating and studying weak memory models" +plt inferno "A library for constraint-based Hindley-Milner type inference" +plt javalib "Javalib is a library written in OCaml with the aim to provide a high level representation of Java .class files" +plt kmt "Framework for deriving Kleene Algebras with Tests (KAT)" +plt lambdapi "Implementation of the λΠ-calculus modulo rewriting" +plt lambdapi "Proof assistant for the λΠ-calculus modulo rewriting" +plt lambda-runtime +plt lambda "λ-calculus ocaml library" +plt libwasmer "The official Wasmer library" +plt libwasmtime "The libwasmtime library package" +plt linksem "A formalisation of the core ELF file format written in Lem" +plt linol "LSP server library" +plt linol-lwt "LSP server library (with Lwt for concurrency)" +plt llopt "Just a tiny LLVM-IR optimizer for testing stuff." +plt llvmgraph "Ocamlgraph overlay for llvm" +plt llvm "The OCaml bindings distributed with LLVM" +plt lsp "LSP protocol implementation in OCaml" +plt malfunction "Compiler back-end for functional languages, based on OCaml" +plt memcad "The MemCAD analyzer" +plt modelica_ml "Modelica abstract syntax and parser" +plt morbig "A trustworthy parser for POSIX shell" +plt morsmall "A concise AST for POSIX shell" +plt nit "Nit, a static analysis tool, checks whether a java bytecode program is NullPointerException free." +plt obytelib "OCaml bytecode library tools to read, write and evaluate OCaml bytecode files" +plt ocaml-logicalform "LogicalForm provides modules for efficient and intuitive manipulation of logical expressions" +plt ollvm +plt ollvm-tapir "a fork of ollvm with added LLVM-Tapir support" +plt openQASM "Parser for OpenQASM (Open Quantum Assembly Language)" +plt ott "A tool for writing definitions of programming languages and calculi" +plt owee "OCaml library to work with DWARF format" +plt pds-reachability "A PDS reachability query library." +plt petr4 "Petr4: Formal Semantics for the P4 Programming Language" +plt pfff "Tools and APIs for program analysis, code visualization, refactoring" +plt promela "Library to create, manipulate and reason about PROMELA data structures." +plt pyast "Python AST" +plt pyre-ast "Full-fidelity Python parser in OCaml" +plt quest "Generates C code for testing a C compiler's calling convention" +plt rdr "Rdr is a cross-platform binary analysis and reverse engineering library," +plt remu_ts "External type infer" +plt rubytt "rubytt is a static code analyzer for Ruby." +plt sawja "Sawja provides a high level representation of Java bytecode programs and static analysis tools" +plt sparrow "A Static Analyzer for C" +plt spdiff "tool for automatic inference of semantic patches" +plt spirv "SPIR-V Compiler Library" +plt stitch "Refactoring framework" +plt systemverilog "SystemVerilog for OCaml" +plt tyabt "Strongly typed many-sorted abstract binding trees (ABTs)" +plt typerex-attic +plt typerex-binutils "Libraries and tools to work with object files" +plt typerex-build "Project manager for OCaml" +plt typerex-clibs "A set of bindings to common C libraries" +plt typerex-lldb +plt typerex-system "System utilities written in OCaml" +plt um-abt "An OCaml library implementing unifiable abstract binding trees (UABTs)" +plt wasmer "OCaml bindings for Wasmer" +plt wasm "Library to read and write WebAssembly (Wasm) files and manipulate their AST" +plt wasmtime "Wasmtime bindings for OCaml" +plt yuujinchou "A domain-specific language for manipulating hierarchical names" +ppx deriving "Extension to OCaml for deriving functions from type declarations" +ppx deriving-ocsigen "Extension to OCaml for deriving functions from type declarations" +ppx deriving-yojson "Parse/convert ocaml value from/to yojson ast" +ppx genprint "PPX syntax extension and library package for printing values of any type" +ppx let-if "A let%if syntax inspired by Rust's if let syntax" +ppx metapp "Meta-preprocessor for OCaml" +ppx metaquot "OCaml syntax extension for quoting code" +ppx mikmatch "OCaml syntax extension for regexps" +ppx node_of_ocaml "An OCaml ppx to require node modules" +ppx ocaml-embed-file "Files contents as module constants" +ppx ocamlify "Include files in OCaml code" +ppx ocaml-monadic "A PPX extension to provide an OCaml-friendly monadic syntax" +ppx override "PPX extension for overriding modules" +ppx pa_comprehension "Syntax extension for comprehension expressions" +ppx pa_do "Syntax extension to write arithmetic expressions" +ppx pa_monad_custom "Syntactic Sugar for Monads" +ppx pa_ppx_ag "A PPX Rewriter that Generates Attribute Grammar Evaulators" +ppx pa_ppx_hashcons "A PPX Rewriter for Hashconsing" +ppx pa_ppx_migrate "A PPX Rewriter for Migrating AST types (written using Camlp5)" +ppx pa_ppx "PPX Rewriters for Ocaml, written using Camlp5" +ppx pa_ppx_q_ast "A PPX Rewriter for automating generation of data-conversion code for use with Camlp5's Q_ast" +ppx pa_ppx_unique "A PPX Rewriter for Uniqifying ASTs" +ppx pa_qualified +ppx pa_sexp_conv "Library for serializing OCaml values to and from S-expressions" +ppx pa_typerep_conv "typerep is a library for runtime types." +ppx pa_variants_conv "Part of Jane Street’s Core library" +ppx pa_where "Backward declaration syntax" +ppx ppx_accessor "[@@deriving] plugin to generate accessors for use with the Accessor libraries" +ppx ppx_assert "Assert-like extension nodes that raise useful errors on failure" +ppx ppx_ast "OCaml AST used by Jane Street ppx rewriters" +ppx ppx_bap "The set of ppx rewriters for BAP" +ppx ppx_base "Base set of ppx rewriters" +ppx ppx_bench "Syntax extension for writing in-line benchmarks in ocaml code" +ppx ppx_bigarray "A PPX extension for big array literals" +ppx ppx_bin_prot "Generation of bin_prot readers and writers from types" +ppx ppx_bitstring "Bitstrings and bitstring matching for OCaml - PPX extension" +ppx ppx_blob "Include a file as a string at compile time" +ppx ppx_bsx "ReasonReact JSX for OCaml" +ppx ppx_camlrack "PPX for matching S-Expressions" +ppx ppx_catch +ppx ppx_cold "Expands [@cold] into [@inline never][@specialise never][@local never]" +ppx ppx_compare "Generation of comparison functions from types" +ppx ppx_compose "Inlined function composition" +ppx ppx_const "Compile-time \"if\" statement for conditional inclusion of code" +ppx ppx_conv_func "Deprecated" +ppx ppx_core "Standard library for ppx rewriters" +ppx ppx_counters "Generate useful code for stats gathering from records of counters" +ppx ppx_css "A ppx that takes in css strings and produces a module for accessing the unique names defined within" +ppx ppx_cstruct "Access C-like structures directly from OCaml" +ppx ppx_cstubs "Preprocessor for easier stub generation with ctypes" +ppx ppx_csv_conv "Generate functions to read/write records in csv format" +ppx ppx_curried_constr "ppx_curried_constr: ppx extension for curried constructors" +ppx ppx_custom_printf "Printf-style format-strings for user-defined string conversion" +ppx ppx_debugger +ppx ppx_defer "Go-like [%defer later]; now syntax" +ppx ppx_derivers "Shared [@@deriving] plugin registry" +ppx ppx_deriving_argparse "Very simple ppx deriver of command line parser for Ocaml >=4.02" +ppx ppx_deriving_cad "PPX Deriver for OCADml transformation functions" +ppx ppx_deriving_cmdliner "Cmdliner.Term.t generator" +ppx ppx_deriving_crowbar "ppx_deriving plugin for crowbar generators" +ppx ppx_deriving_encoding "Ppx deriver for json-encoding" +ppx ppx_deriving_hardcaml "Rewrite OCaml records for use as Hardcaml Interfaces" +ppx ppx_deriving_hash "[@@deriving hash]" +ppx ppx_deriving_jsoo "Ppx deriver for Js_of_ocaml" +ppx ppx_deriving_madcast "Library deriving cast functions based on their types." +ppx ppx_deriving_morphism "Morphism generator for OCaml >=4.02" +ppx ppx_deriving_popper "A ppx deriving sample-functions for Popper" +ppx ppx_deriving_protobuf "A Protocol Buffers codec generator for OCaml" +ppx ppx_deriving_protocol +ppx ppx_deriving_qcheck "PPX Deriver for QCheck" +ppx ppx_deriving_rpc "Ppx deriver for ocaml-rpc, a library to deal with RPCs in OCaml" +ppx ppx_deriving_scad "PPX Deriver for Scad_ml transformation functions" +ppx ppx_deriving "Type-driven code generation for OCaml" +ppx ppx_deriving_yaml "Yaml PPX Deriver" +ppx ppx_deriving_yojson "JSON codec generator for OCaml" +ppx ppx_disable_unused_warnings "Expands [@disable_unused_warnings] into [@warning \"-20-26-32-33-34-35-36-37-38-39-60-66-67\"]" +ppx ppx_distr_guards "Extension to distribute guards over or-patterns" +ppx ppx_dotbracket +ppx ppx_driver "Feature-full driver for OCaml AST transformers" +ppx ppx_dryunit "A detection tool for traditional unit testing in OCaml" +ppx ppx_enumerate "Generate a list containing all values of a finite type" +ppx ppx_enum "PPX to derive enum-like modules from variant type definitions" +ppx ppx_expect "Cram like framework for OCaml" +ppx ppx_factory "PPX to derive factories and default values" +ppx ppx_fail "Add location to calls to failwiths" +ppx ppx_fast_pipe "Fast pipe, pipe first as a syntax transform" +ppx ppx_fields_conv "Generation of accessor and iteration functions for ocaml records" +ppx ppxfind "Tool combining ocamlfind and ppx" +ppx ppx_fixed_literal "Simpler notation for fixed point literals" +ppx ppx_fun +ppx ppx_gen_rec "A ppx rewriter that transforms a recursive module expression into a `struct`" +ppx ppx_getenv "A sample syntax extension using OCaml's new extension points API" +ppx ppx_graphql "Write type-safe GraphQL queries" +ppx ppx_hardcaml "PPX extension for HardCaml" +ppx ppx_hash +ppx ppx_here "Expands [%here] into its location" +ppx ppx_ignore_instrumentation "Ignore Jane Street specific instrumentation extensions" +ppx ppx_implicits +ppx ppx_import "A syntax extension for importing declarations from interface files" +ppx ppx_include "Include OCaml source files in each other" +ppx ppx_inline_alcotest "Inline tests backend for alcotest" +ppx ppx_inline_test "Syntax extension for writing in-line tests in ocaml code" +ppx ppx_integer +ppx ppx_irmin "PPX deriver for Irmin type representations" +ppx ppx_jane "Standard Jane Street ppx rewriters" +ppx ppx_jsobject_conv +ppx ppx_jsonaf_conv "[@@deriving] plugin to generate Jsonaf conversion functions" +ppx ppx_json_types "JSON type providers" +ppx ppx_js_style "Code style checker for Jane Street Packages" +ppx ppx_let "Monadic let-bindings" +ppx ppxlib "Base library and tools for ppx rewriters" +ppx ppx_log "Ppx_sexp_message-like extension nodes for lazily rendering log messages" +ppx ppx_make "Ppxlib based make deriver" +ppx ppx_map "A PPX rewriter to simplify the declaration of maps" +ppx ppx_matches "Small ppx to help check if a value matches a pattern" +ppx ppx_measure "Provide a Type-safe way to manage unit of measure" +ppx ppx_meta_conv "PPX for converting between OCaml values and JSON, Sexp and camlon" +ppx ppx_metaquot "Write OCaml AST fragment using OCaml syntax" +ppx ppx_module_timer "Ppx rewriter that records top-level module startup times" +ppx ppx_monad "A Syntax Extension for all Monadic Syntaxes" +ppx ppx_monadic +ppx ppx_monoid "Syntax extension for building values of monoids" +ppx ppx_mysql_identity "Convenience package for using ppx_mysql with Mysql and the identity monad for IO" +ppx ppx_mysql "Syntax extension for facilitating usage of MySQL bindings" +ppx ppx_nanocaml "Framework for writing nanopass-style compilers" +ppx ppx_netblob "type-driven generation of HTTP calling code" +ppx ppx_open "Idiomatic selective `open`s in OCaml" +ppx ppx_optcomp "Optional compilation for OCaml" +ppx ppx_optional "Pattern matching on flat options" +ppx ppx_orakuda "ORakuda, Perlish string literals in OCaml" +ppx ppx_overload "Virtual package for ppx_overload, now provided by typpx" +ppx ppx-owl-opt "Ppx tool for owl-opt" +ppx ppx_pattern_bind "A ppx for writing fast incremental bind nodes in a pattern match" +ppx ppx_pattern_guard "ppx_pattern_guard: ppx extension for pattern guard" +ppx ppx_pbt "PPX Rewriter for property based testing" +ppx ppx_pipebang +ppx ppx_poly_record "ppx for polymorphic records" +ppx ppx_protocol_conv +ppx ppx_protocol_conv_json "Json driver for Ppx_protocol_conv" +ppx ppx_protocol_conv_jsonm "Jsonm driver for Ppx_protocol_conv" +ppx ppx_protocol_conv_msgpack "MessagePack driver for Ppx_protocol_conv" +ppx ppx_protocol_conv_xml_light "Xml driver for Ppx_protocol_conv" +ppx ppx_protocol_conv_xmlm "Xmlm driver for Ppx_protocol_conv" +ppx ppx_protocol_conv_yaml "Json driver for Ppx_protocol_conv" +ppx ppx_pyformat +ppx ppx_python "[@@deriving] plugin to generate Python conversion functions" +ppx ppx_rapper_async "Async support for ppx_rapper" +ppx ppx_rapper_lwt "Lwt support for ppx_rapper" +ppx ppx_rapper "Syntax extension for Caqti/PostgreSQL queries" +ppx ppx_regexp "Matching Regular Expressions with OCaml Patterns" +ppx ppx_relit "An implementation of Typed Literal Macros for Reason" +ppx ppx_repr "PPX deriver for type representations" +ppx ppx_seq "Seq literals ppx for OCaml" +ppx ppx_sexp +ppx ppx_sexp_conv +ppx ppx_sexp_message "A ppx rewriter for easy construction of s-expressions" +ppx ppx_sexp_value +ppx ppx_show "OCaml PPX deriver for deriving show based on ppxlib" +ppx ppx_sqlexpr +ppx ppx_stable "Stable types conversions generator" +ppx ppx_string_interpolation "String interpolation PPX preprocessor" +ppx ppx_string "Ppx extension for string interpolation" +ppx ppx_system "A ppx to know host operating system at compile time" +ppx ppx_test "A ppx replacement of pa_ounit" +ppx ppx_there "PPX extension for improved __MODULE__" +ppx ppx_tools "Tools for authors of ppx rewriters and other syntactic tools" +ppx ppx_tools_versioned "A variant of ppx_tools based on ocaml-migrate-parsetree" +ppx ppx_traverse "Automatic generation of open-recursion classes" +ppx ppx_traverse_builtins "Builtins for Ppx_traverse" +ppx ppx_ts "A PPX helps binding to typescript modules" +ppx ppx_type_conv "Support Library for type-driven code generators" +ppx ppx_typed_fields "GADT-based field accessors and utilities" +ppx ppx_type_directed_value "Get [@@deriving]-style generation of type-directed values without writing a ppx" +ppx ppx_typerep_conv "Generation of runtime types from type declarations" +ppx ppx_tyre "PPX syntax for tyre regular expressions and routes" +ppx ppx_units "Generate unit types for every record field" +ppx ppx_variants_conv +ppx ppx_view +ppx ppx_viewpattern "View patterns in OCaml" +ppx ppx_where "Haskell-style `where` clauses as a PPX syntax extension" +ppx ppx_wideopen "Ppx_wideopen syntax extension" +ppx ppx_xml_conv "Generate XML conversion functions from records" +ppx ppxx "Ppxx: a small extension library for writing PPX preprocessors" +ppx ppx_yojson_conv "[@@deriving] plugin to generate Yojson conversion functions" +ppx ppx_yojson_conv_lib "Runtime lib for ppx_yojson_conv" +ppx ppx_yojson "PPX extension for Yojson literals and patterns" +ppx refl "PPX deriver for reflection" +ppx res_tailwindcss "PPX validates the tailwindcss class names" +ppx typpx "a library for PPX with types" +ppx visitors "An OCaml syntax extension for generating visitor classes" +prover abella "Interactive theorem prover based on lambda-tree syntax" +prover alt-ergo-free "The Alt-Ergo SMT prover" +prover alt-ergo-lib-free "The Alt-Ergo SMT prover library" +prover alt-ergo-lib "The Alt-Ergo SMT prover library" +prover alt-ergo-parsers-free "The Alt-Ergo SMT prover parser library" +prover alt-ergo-parsers "The Alt-Ergo SMT prover parser library" +prover alt-ergo "The Alt-Ergo SMT prover" +prover altgr-ergo "The GUI for the Alt-Ergo SMT prover" +prover archsat "A first-order theorem prover with formal proof output" +prover cfml "The CFML program verification tool" +prover coq "Formal proof management system" +prover coqide "IDE of the Coq formal proof management system" +prover coq-native "Package flag enabling coq's native-compiler flag" +prover coq-of-ocaml "Compile a subset of OCaml to Coq" +prover coq-serapi "Sexp-based serialization library and protocol for machine interaction with the Coq proof assistant" +prover coq-shell "Simplified OPAM shell for Coq" +prover eprover "E Theorem Prover" +prover libzipperposition "Library for Zipperposition" +prover phox "PhoX is an implementation of Higher Order Logic" +prover profound "Interactive proof exploration based on formula linking" +prover squirrel "The Squirrel Prover is a proof assistant for protocols, based on first-order logic and provides guarantees in the computational model" +prover why3-base "Why3 environment for deductive program verification (base)" +prover why3-coq "Why3 environment for deductive program verification" +prover why3-ide "Why3 environment for deductive program verification" +prover why3 "Why3 environment for deductive program verification" +prover why "Why is a software verification platform." +prover zenon "An Extensible Automated Theorem Prover Producing Checkable Proofs" +prover zipperposition "A fully automatic theorem prover for typed higher-order and beyond" +prover zipperposition-tools "Support tools for Zipperposition" +retrocompatibility bigarray-compat +retrocompatibility core_compat "Compatibility for core 0.14" +retrocompatibility either "Compatibility Either module" +retrocompatibility ocaml-syntax-shims "Backport new syntax to older OCaml versions" +retrocompatibility result "Compatibility Result module" +retrocompatibility rresult """Result value combinators for OCaml""" +retrocompatibility seq +retrocompatibility stdcompat "Compatibility module for OCaml standard library" +retrocompatibility stdlib-shims "Backport some of the new stdlib features to older compiler" +science bistro "A library to build and run distributed scientific workflows" +science fasmifra "Molecular Generation by Fast Assembly of SMILES Fragments" +science gdal "Bindings to the GDAL and OGR libraries" +science grib "Bindings for the ECMWF GRIB API" +science hlarp "Normalize and compare HLA typing output." +science hts_shrink "Distance-Based Boolean Applicability Domain for High Throughput Screening data" +science igvxml "Create IGV session files from the command-line" +science jhupllib "A collection of OCaml utilities used by the JHU PL lab" +science ketrew "A Workflow Engine for Computational Experiments" +science kicadsch "Library to read and convert Kicad Sch files" +science lbvs_consent "Chemoinformatics software for consensus fingerprint queries" +science libra-tk "Learning and inference with discrete probabilistic models" +science lutin "Lutin: modeling stochastic reactive systems" +science molenc "Molecular encoder/featurizer using rdkit and OCaml" +science np "Fundamental scientific computing with Numpy for OCaml" +science npy "Numpy npy file format reading/writing." +science oc45 "Pure OCaml implementation of the C4.5 algorithm." +science OCADml "Types and functions for building CAD packages in OCaml" +science oolc "An Ocaml implementation of Open Location Code." +science orandforest "A random forest classifier based on OC4.5." +science oranger "OCaml wrapper for the ranger (C++) random forests implementation" +science orf "OCaml Random Forests" +science orgeat "Ocaml Random Generation of Arbitrary Types" +science orrandomForest "Classification or regression using Random Forests" +science orsvm_e1071 "OCaml wrapper to SVM R packages e1071 and svmpath" +science orxgboost "Gradient boosting for OCaml using the R xgboost package" +science osbx "Implementation of SeqBox in OCaml" +science phylogenetics "Algorithms and datastructures for phylogenetics" +science prbnmcn-clustering "Clustering library" +science proj4 "Bindings to the PROJ.4 projection library" +science qiskit "Qiskit for OCaml" +science rankers "Vanishing Ranking Kernels (VRK)" +science scid "Sierra Chart's Intraday Data File Format library" +science scipy "SciPy scientific computing library for OCaml" +science skkserv-lite "SKK server using sqlite3 dictionaries" +science sklearn "Scikit-learn machine learning library for OCaml" +science svmwrap "Wrapper on top of libsvm-tools" +science testu01 "OCaml bindings for TestU01 1.2.3" +science trexio "Binding for the TREXIO Input/Output library" +science udunits "Bindings to the UDUNITS-2 library" +science voqc "A verified optimizer for quantum circuits (VOQC)" +security argon2 "OCaml bindings to Argon2" +security binsec "Semantic analysis of binary executables" +security blake2 "Blake2 cryptography" +security blake3 "Blake3 cryptography" +security bls12-381-gen "Functors to generate BLS12-381 primitives based on stubs" +security bls12-381-hash +security bls12-381 "Implementation of BLS12-381 and some cryptographic primitives built on top of it" +security bls12-381-js """\ +security bls12-381-js-gen +security bls12-381-legacy +security bls12-381-signature +security bls12-381-unix """\ +security bn128 +security callipyge "Pure OCaml implementation of Curve25519" +security chacha "The Chacha functions, in OCaml" +security checkseum "Adler-32, CRC32 and CRC32-C implementation in C and OCaml" +security class_group_vdf "Verifiable Delay Functions bindings to Chia's VDF" +security crc "CRC implementation supporting strings and cstructs" +security cryptgps "Cryptographic functions" +security cryptodbm "Utilities for Versioned RPC communication with a child process over stdin and stdout" +security cryptohash "hash functions for OCaml" +security cryptokit "Cryptographic primitives library." +security cryptoverif "CryptoVerif: Cryptographic protocol verifier in the computational model" +security crypt "Tiny binding for the unix crypt function" +security curve-sampling "Sampling of parametric and implicit curves" +security digestif "Hashes implementations (SHA*, RIPEMD160, BLAKE2* and MD5)" +security dirsp-exchange-kbb2017 +security dirsp-exchange "Published protocols for the authenticated message exchange" +security dirsp-proscript-mirage +security dirsp-proscript "OCaml-ified interfaces for the ProScript Cryptography Library" +security dirsp-ps2ocaml "ProScript to OCaml translator" +security dnscurve "DNSCurve protocol for DNS queries over a secure channel" +security yara "OCaml bindings for YARA matching engine" +sexp camlrack "S-Expression parsing for OCaml" +sexp csexp "Parsing and printing of S-expressions in Canonical form" +sexp decoders-sexplib "Sexplib backend for decoders" +sexp parsexp_io "S-expression parsing library (IO functions)" +sexp parsexp "S-expression parsing library" +sexp pa_structural_sexp +sexp sexp_decode "A library to decode S-expression into structured data" +sexp sexp_diff "Code for computing the diff of two sexps" +sexp sexp_diff_kernel "Code for computing the diff of two sexps" +sexp sexp_grammar "Sexp grammar helpers" +sexp sexplib0 "Library containing the definition of S-expressions and some base converters" +sexp sexplib "Library for serializing OCaml values to and from S-expressions" +sexp sexp_macro "Sexp macros" +sexp sexp_pretty "S-expression pretty-printer" +sexp sexp_select "A library to use CSS-style selectors to traverse sexp trees" +sexp sexp "S-expression swiss knife" +sexp sexp_string_quickcheck "Quickcheck helpers for strings parsing to sexps" +solver 0install-solver "Package dependency solver" +solver absolute "AbSolute solver" +solver aez "Alt-Ergo Zero is an OCaml library for an SMT solver." +solver batsat "OCaml bindings for batsat, a SAT solver in rust" +solver bdd +solver bddapron "Logico-numerical domain(s) based on BDDs and APRON" +solver bddrand "A simple front-end to the lutin Random toss machinary" +solver bes "boolean expression simplifier" +solver bitwuzla-bin "Bitwuzla SMT solver executable" +solver bitwuzla-c "SMT solver for AUFBVFP (C API)" +solver bitwuzla "SMT solver for AUFBVFP" +solver colibri2 "A CP solver for smtlib" +solver colibrics "A CP solver proved in Why3" +solver combine "Combine is a library for combinatorics problem solving." +solver cubicle "SMT based model checker for parameterized systems" +solver facile "Constraint programming library over integer finite domains" +solver gbddml "The Verimag bdd library" +solver kind2 "Multi-engine, parallel, SMT-based automatic model checker for safety properties of Lustre programs" +solver logical "Logical is a minimalistic logic programming inspired by microKanren" +solver logtk "Core types and algorithms for logic" +solver mc2 "A mcsat-based SMT solver in pure OCaml" +solver mccs "Multi Criteria CUDF Solver with OCaml bindings" +solver minisat "Bindings to Minisat-C-1.14.1, with the solver included" +solver mlbdd "An OCaml library for Binary Decision Diagrams (BDDs)" +solver mlcuddidl "OCaml interface to the CUDD BDD library" +solver msat-bin "SAT solver binary based on the msat library" +solver msat "Library containing a SAT solver that can be parametrized by a theory" +solver noCanren "Translator from subset of OCaml to OCanren" +solver nunchaku "A counter-example finder for higher-order logic, designed to be used from various proof assistants" +solver ocaml-buddy "Bindings for the Buddy BDD library." +solver ocaml-sat-solvers "An abstraction layer for integrating SAT Solvers into OCaml." +solver ocamlyices "Yices SMT solver binding" +solver OCanren "Implementation of miniKanren relational (logic) EDSL" +solver OCanren-ppx +solver osdp "OCaml Interface to SDP solvers" +solver pa_solution "A DSL for solving programming contest problems" +solver pgsolver "A collection of tools for generating, manipulating and - most of all - solving parity games." +solver psmt2-frontend "The psmt2-frontend project" +solver qbf "QBF solving in OCaml, including bindings to solvers" +solver regstab "SAT-Solver able to deal with formulae patterns" +solver satML-plugin "Alt-Ergo, an SMT Solver for Software Verification: satML Plugin" +solver sattools +solver satyrographos "A package manager for SATySFi" +solver simple-bmc "A tool to translate Hybrid automata into SMT formula which is solvable by dReal" +solver smbc "Experimental model finder/SMT solver for functional programming" +solver smtlib-utils "Parser for SMTLIB2" +solver space-search "SpaceSearch is a library that turns Coq into a solver-aided host language" +solver sundialsml "Interface to the Sundials suite of numerical solvers" +solver touist "The solver for the Touist language" +solver yices2_bindings "Ocaml bindings for yices2" +solver yices2 "Yices2 SMT solver binding" +solver z3_tptp "TPTP front end for Z3 solver" +solver z3 "Z3 solver" +ssh awa-lwt "SSH implementation in OCaml" +ssh awa-mirage "SSH implementation in OCaml" +ssh awa "SSH implementation in OCaml" +ssh libssh "Bindings to libssh" +ssh ssh-agent "Ssh-agent protocol parser and serialization implementation" +ssh ssh-agent-unix "Ssh-agent protocol parser and serialization implementation for unix platforms" +stdlib base_bigstring "String type based on [Bigarray], for use in I/O and C-bindings" +stdlib base-bytes "Bytes library distributed with the OCaml compiler" +stdlib base "Full standard library replacement for OCaml" +stdlib base-implicits "Dummy base package for compilers with modular implicits support." +stdlib base-metaocaml-ocamlfind "Findlib toolchain configuration for MetaOCaml" +stdlib base-native-int63 "Virtual package for enabling native int63 support in Base" +stdlib base-nnp "Naked pointers prohibited in the OCaml heap" +stdlib base-no-ppx "A pseudo-library to indicate lack of extension points support" +stdlib base-unsafe-string "A pseudo-library to indicate OCaml versions that equate 'string' and 'bytes' (by default)" +stdlib batteries "A community-maintained standard library extension" +stdlib containers "A modular, clean and powerful extension of the OCaml standard library" +stdlib containers-data "A set of advanced datatypes for containers" +stdlib containers-thread "An extension of containers for threading" +stdlib core-and-more "Includes core, and some more useful extensions" +stdlib core_extended +stdlib core "Industrial strength alternative to OCaml's standard library" +stdlib core_kernel "Industrial strength alternative to OCaml's standard library" +stdlib cps_toolbox "A partial OCaml standard library replacement written with continuation passing style in mind" +stdlib devkit "Development kit - general purpose library" +stdlib extlib "A complete yet small extension for OCaml standard library" +stdlib extlib-compat +stdlib faillib "Part of Jane Street’s Core library" +stdlib fmlib "Functional monadic library" +stdlib fmlib_std "Standard datatypes of Fmlib" +stdlib General "Rich functionality for built-in and basic OCaml types" +stdlib nonstd "Non-standard mini-library" +stdlib preface "An opinionated library for function programming (à La Haskell)" +stdlib stdio "Standard IO library for OCaml" +stdlib tablecloth-native "Native OCaml library implementing Tablecloth, a cross-platform standard library for OCaml and Rescript" +stdlib TCSLib "A multi-purpose library for OCaml." +system b0 "Software construction and deployment kit" +system bos "Basic OS interaction for OCaml" +system bwrap "Use Bubblewrap to sandbox executables" +system corecount "Get count of cores on machine" +system directories "An OCaml library that provides configuration, cache and data paths (and more!) following the suitable conventions on Linux, macOS and Windows" +system dirsift "Search for directories by type" +system docker-api "Binding to the Docker Remote API" +system dockerfile-cmd "Dockerfile eDSL - generation support" +system dockerfile "Dockerfile eDSL in OCaml" +system dockerfile-opam "Dockerfile eDSL -- opam support" +system docker_hub "Library aiming to provide data from hub.docker.com" +system dotenv "Javascript's dotenv port to OCaml" +system dtools "Library providing various helper functions to make daemons" +system env_config "Helper library for retrieving configuration from an environment variable" +system esperanto "An OCaml compiler with Cosmopolitan" +system esperanto-cosmopolitan "Cosmopolitan toolchain for OCaml compiler" +system exit "Get exit status as declared in `stdlib.h`" +system ez_config "Easy management of configuration files" +system ezdl "Easy dynamic linking of C functions from ocaml" +system ez_file "Easy file manipulation (read_file, write_file, etc.)" +system ezxenstore "An easy-to-use interface to xenstore" +system feather "A minimal shell interface" +system feather_async "Async interface to Feather" +system febusy "Embedded build system library" +system file_path "A library for typed manipulation of UNIX-style file paths" +system fileutils "API to manipulate files (POSIX like) and filenames" +system forkwork "Fork child processes to perform work on multiple cores" +system fpath """File system paths for OCaml""" +system frag "File fragment extraction" +system fswatch_async "JaneStreet Async extension for fswatch" +system fswatch "Bindings for libfswatch -- file change monitor" +system fswatch_lwt "Lwt extension for fswatch" +system gasoline "Unix-ish application development framework" +system genspio "Typed EDSL to generate POSIX Shell scripts" +system get_line "Robustly select lines from file; can replace the head and tail shell commands and do even more" +system globlon "A globbing library for OCaml" +system hidapi "Bindings to Signal11's hidapi library" +system hvsock "Bindings for Hyper-V AF_VSOCK" +system ivy "This OCaml-library interfaces the Ivy software bus C-library" +system kinetic-client "Client for Seagate's kinetic drives." +system kqueue "OCaml bindings for kqueue event notification interface" +system kubecaml "Kubernetes API client for OCaml" +system libevent "OCaml wrapper for the libevent API" +system libudev "Bindings to libudev for OCaml" +system libvirt +system line_oriented "Library to operate on files made of lines of text" +system lo "Bindings for the lo library which provides functions for communicating with input controls using the OSC protocol" +system luv "Binding to libuv: cross-platform asynchronous I/O" +system luv_unix "Helpers for interfacing Luv and Unix" +system mlfenv "OCaml C bindings for fenv(3)" +system mmap "File mapping functionality" +system named-pipe "Bindings for named pipes" +system obuilder "Run build scripts for CI" +system obuilder-spec "Build specification format" +system obuild "simple package build system for OCaml" +system ocaml9p "ocaml9p is a library for the 9p protocol." +system ocamlfuse "OCaml bindings for FUSE (Filesystem in UserSpacE)" +system ocaml-xdg-basedir +system ocapic "Development tools to run OCaml programs on PIC microcontrollers" +system ocplib-file "A simple library to manage accesses to files" +system opasswd +system open "Open files in their default applications" +system order-i3-xfce "Order-i3-xfce is a small utility that allow you to keep a synchronized order between i3 tabs and the xfce pannel window buttons plugin" +system path_glob "Globbing file paths" +system pci "Ctypes bindings to libpci for OCaml" +system pci-db "Library to parse and query the pci.ids database of PCI devices" +system pf-qubes "QubesOS firewall ruleset handling library" +system pixel_pusher "Control LED strips on Pixel Pusher hardware" +system posixat "Bindings to the posix *at functions" +system posix-base "Base module for the posix bindings" +system posix-bindings "POSIX bindings" +system posix-clock "POSIX clock" +system posix-getopt "Bindings for posix getopt/getopt_long" +system posix-math "POSIX math" +system posix-mqueue "POSIX message queues" +system posix-semaphore "POSIX semaphore" +system posix-signal "Bindings for the types defined in " +system posix-socket "Bindings for posix sockets" +system posix-socket-unix "Bindings for posix sockets" +system posix-time2 "Bindings for posix time functions" +system posix-time "POSIX time" +system posix-types "Bindings for the types defined in " +system posix-uname "Bindings for posix uname" +system process "Easy process control" +system processor "Processor Topology & Affinity for ocaml" +system procord "Procord: a portable library to delegate tasks to other processes." +system proc-smaps "Proc-smaps: An ocaml parser of /proc/[pid]/smaps" +system protocol-9p "An implementation of the 9p protocol in pure OCaml" +system protocol-9p-tool "An implementation of the 9p protocol in pure OCaml" +system protocol-9p-unix "A Unix implementation of the 9p protocol in pure OCaml" +system pvem_lwt_unix "Access to the Operating system with Pvem and Lwt_unix" +system qfs "Bindings to libqfs - client library to access QFS" +system qmp "OCaml implementation of a Qemu Message Protocol (QMP) client" +system rashell "A resilient and replicant shell programming library" +system redirect "Redirect channels" +system rusage "Bindings to the GETRUSAGE(2) syscall" +system sanlock "Ctypes bindings to libsanlock for OCaml" +system semaphore-compat "Compatibility Semaphore module" +system setcore "Pin current process to given core number" +system shared-memory-ring-lwt "Shared memory rings for RPC and bytestream communications using Lwt" +system shared-memory-ring "Shared memory rings for RPC and bytestream communications" +system shcaml "Library for Unix shell programming" +system shell "Yet another implementation of fork&exec and related functionality" +system shexp "Process library and s-expression based shell" +system sibylfs +system sibylfs-lem +system so "Open file depending on their extension" +system spawn "Spawning sub-processes" +system syslog "syslog(3) routines for ocaml (RFC 3164)" +system sys-socket +system sys-socket-unix +system teash "TEA for the shell" +system usbmux "Control port remapping for iOS devices" +system usb "OCaml bindings for libusb-1.0" +system username_kernel "An identifier for a user" +system vhd-format-lwt "Pure OCaml library for reading and writing .vhd format data" +system vhd-format "Pure OCaml library for reading and writing .vhd format data" +system vhdlib "Bindings to libvhd" +system vhd-tool +system wiringpi "WiringPi for OCaml, low level Raspberry Pi hardware access" +system xdg-basedir "XDG basedir location for data/cache/configuration files" +system xdg "XDG Base Directory Specification" +terminal ansi "ANSI escape sequence parser" +terminal ansicolor +terminal ansi-parse "Ansiparse is a library for converting raw terminal output, replete with escape codes, into formatted HTML" +terminal ANSITerminal "Basic control of ANSI compliant terminals and the windows shell" +terminal arg-complete "Bash completion support for Stdlib.Arg" +terminal async_interactive "Utilities for building simple command-line based user interfaces." +terminal async_shell "Shell helpers for Async" +terminal async_unix "Monadic concurrency library" +terminal box "Render boxes in the terminal" +terminal chalk "Composable and simple terminal highlighting package" +terminal charInfo_width "Determine column width for a character" +terminal clap "Command-Line Argument Parsing, imperative style with a consumption mechanism" +terminal clim "Command Line Interface Maker" +terminal clim-ppx "Derivates cmdliner terms from type definitions" +terminal cmdliner "Declarative definition of command line interfaces for OCaml" +terminal cmdtui "Interactive command completion and execution for building REPLs" +terminal cmdtui-lambda-term "Interactive command completion and execution for building REPLs" +terminal curses "Bindings to ncurses" +terminal epictetus "Elegant Printer of Insanely Complex Tables Expressing Trees with Uneven Shapes" +terminal ez_cmdliner "Easy interface to Cmdliner à la Arg.parse with sub-commands" +terminal fmlib_pretty "Pretty printing support for tree like structures" +terminal fmt """OCaml Format pretty-printer combinators""" +terminal format +terminal getopt +terminal getopts "Analyse command line arguments" +terminal inquire "Create beautiful interactive command line interface in OCaml" +terminal inuit "Make interactive text-based user-interfaces in OCaml" +terminal lambda-term "Terminal manipulation library for OCaml" +terminal libdash "Bindings to the dash shell's parser" +terminal linenoise "Lightweight readline alternative" +terminal line-up-words "Align words in an intelligent way" +terminal mew "Modal editing witch" +terminal mew_vi "Modal editing witch, VI interpreter" +terminal minicli "Minimalist library for command line parsing" +terminal nottui-lwt "Run Nottui UIs in Lwt" +terminal nottui-pretty "A pretty-printer based on PPrint rendering UIs" +terminal nottui "UI toolkit for the terminal built on top of Notty and Lwd" +terminal notty_async "An Async driver for Notty" +terminal notty "Declaring terminals" +terminal ocaml-arg "A simple library to handle subcommand arguments" +terminal ocamline "Command line interface for user input" +terminal ocolor "Print with style in your terminal using Format's semantic tags" +terminal parse-argv "Process strings into sets of command-line arguments" +terminal printbox "Allows to print nested boxes, lists, arrays, tables in several formats" +terminal printbox-html "Printbox unicode handling" +terminal printbox-text "Text renderer for printbox, using unicode edges" +terminal progress "User-definable progress bars" +terminal termbox +terminal terminal "Basic utilities for interacting with terminals" +terminal terminal_size "Get the dimensions of the terminal" +terminal tqdm "OCaml library for progress bars" +tests afl +tests afl-persistent "Use afl-fuzz in persistent mode" +tests alcotest "Alcotest is a lightweight and colourful test framework" +tests alcotest-async "Async-based helpers for Alcotest" +tests alcotest-js +tests alcotest-lwt "Lwt-based helpers for Alcotest" +tests alcotest-mirage "Mirage implementation for Alcotest" +tests alg_structs_qcheck "Provides qCheck generators for laws of alg_structs" +tests assertions "Basic assert statements" +tests base_quickcheck "Randomized testing framework, designed for compatibility with Base" +tests boltzgen "Generate test using boltzman sampling" +tests broken "The Broken package is a simple testsuite framework." +tests bun "simple management of afl-fuzz processes" +tests caravan "A framework for testing arbitrary systems, in OCaml" +tests cinaps "Trivial metaprogramming tool" +tests craml "A CRAM-testing framework for testing command line applications" +tests crowbar "Write tests, let a fuzzer find failing cases" +tests dryunit "A detection tool for traditional and popular testing frameworks" +tests exenum "Build efficient enumerations for datatypes. Inspired by Feat for Haskell." +tests expect "Simple implementation of "expect" to help building unitary testing of interactive program" +tests expect_test_helpers_async "Async helpers for writing expectation tests" +tests expect_test_helpers "Async helpers for writing expectation tests" +tests expect_test_helpers_core "Helpers for writing expectation tests" +tests expect_test_helpers_kernel "Helpers for writing expectation tests" +tests feat +tests feat-core "Facilities for enumerating and sampling algebraic data types" +tests feat-num +tests junit_alcotest "JUnit" +tests junit "JUnit" +tests junit_ounit "JUnit" +tests kaputt "Testing tool" +tests lreplay "Executes a test suite and computes test coverage" +tests mock "Configurable functions to test impure code" +tests mock-ounit "OUnit wrapper for OCaml mock" +tests monolith "A framework for testing a library using afl-fuzz" +tests ocamlcodoc "Extract test code from doc-comments" +tests ocaml-topexpect "Simulate and post-process ocaml toplevel sessions" +tests osnap "OCaml random snapshot testing" +tests ospec "Behavior-Driven Development tool for OCaml, inspired by RSpec" +tests otf "otf is a simple Output Test Framework" +tests oth "Ocaml Test Harness - Simple library for running tests" +tests otto "Otto is a testing / autograding library" +tests ounit2-lwt "OUnit testing framework (Lwt)" +tests ounit2 "OUnit testing framework" +tests ounit-lwt "This is a transition package, ounit-lwt is now ounit2-lwt" +tests ounit "This is a transition package, ounit is now ounit2" +tests pa_ounit "Syntax extension for oUnit" +tests pa_test "Quotation expander for assertions." +tests popper "Property-based testing at ease" +tests prbnmcn-proptest "Property-based test helpers for prbnmcn packages" +tests qcheck-alcotest "QuickCheck inspired property-based testing for OCaml." +tests qcheck-core "QuickCheck inspired property-based testing for OCaml." +tests qcheck-ounit "QuickCheck inspired property-based testing for OCaml." +tests qcheck "QuickCheck inspired property-based testing for OCaml." +tests qcstm "A simple state-machine framework for OCaml based on QCheck" +tests qtest "qtest : Inline (Unit) Tests for OCaml." +tests quickcheck "Translation of QuickCheck from Haskell into OCaml" +tests radamsa "Radamsa bindings for OCaml" +tests regenerate "Regenerate is a tool to generate test-cases for regular expression engines" +tests should "Literate assertions" +tests testrunner +tests testsimple "A simple unit testing framework" +tests tezt "Test framework for unit tests, integration tests, and regression tests" +tests toplevel_expect_test "Expectation tests for the OCaml toplevel" +tests webtest "An in-browser js_of_ocaml testing framework - core library" +tests webtest-js "An in-browser js_of_ocaml testing framework - js_of_ocaml integration" +text acme "A library to interact with the acme text editor." +text camelsnakekebab "A Ocaml library for word case conversion" +text camlhighlight "Camlhighlight provides syntax highlighting facilities for OCaml applications." +text camlon "Camlmix is a generic preprocessor which converts text with embedded" +text camltemplate "Library for generating text from templates" +text camomile "A Unicode library" +text charset "Fast char sets" +text coin "Mapper of KOI8-{U,R} to Unicode" +text custom_printf "Extension for printf format strings" +text duff "Rabin's fingerprint and diff algorithm in OCaml" +text ecaml "Library for writing Emacs plugin in OCaml" +text embedded_ocaml_templates "EML is a simple templating language that lets you generate text with plain OCaml" +text emoji "Use emojis by name" +text estring "Extension for string literals" +text ez_search "The ez_search library" +text ez_subst "Ez_subst is a simple module to perform string substitutions" +text fuzzy_compare "Fastest bounded Levenshtein comparator over generic structures" +text fuzzy_match "A library for fuzzy string matching" +text gettext-camomile "Internationalization library using camomile (i18n)" +text gettext "Internationalization library (i18n)" +text gettext-stub "Internationalization using C gettext library (i18n)" +text higlo "Syntax highlighting library" +text hilite "Build time syntax highlighting" +text humane-re "A human friendly interface to regular expressions in OCaml" +text jingoo "Template engine almost compatible with Jinja2(python template engine)" +text levenshtein "Levenshtein distance algorithm for general array" +text lipsum +text m17n "Multilingualization for OCaml source code" +text mecab "An OCaml binding of MeCab, a part-of-speech and morphological analyzer." +text mustache "Mustache logic-less templates in OCaml" +text mutf8 "The Modified UTF-8 encoding used by Java and related systems" +text ocamldiff "OCamldiff is a small OCaml library providing functions to parse and display diff results" +text odb-server "Text editors/IDE helper module" +text odiff-gtk "OCaml library to display and merge diffs using Lablgtk." +text omg "Generate text using Markov chains" +text oniguruma "Bindings to the Oniguruma regular expression library" +text opencc0 "Bindings for OpenCC (v0) - Open Chinese Convert" +text opencc1_1 "Bindings for OpenCC (v1.1) - Open Chinese Convert" +text opencc1 "Bindings for OpenCC (v1) - Open Chinese Convert" +text opencc "Bindings for OpenCC (v1) - Open Chinese Convert" +text orakuda "Perlish string literals in OCaml" +text pandoc-abbreviations "Pandoc filter to add non-breaking spaces after abbreviations" +text pandoc-crossref "Pandoc filter to have LaTeX cross-references" +text pandoc-include "Pandoc filter to include other files" +text pandoc-inspect "Pandoc filter to inspect pandoc's JSON" +text pandoc "Library to write pandoc filters" +text patch "Patch library purely in OCaml" +text patdiff "File Diff using the Patience Diff algorithm" +text patience_diff "Diff library using Bram Cohen's patience diff algorithm." +text pcre "Bindings to the Perl Compatibility Regular Expressions library" +text phonetic "Phonetic algorithm in OCaml" +text pla "Pla is a simple library and ppx syntax extension to create composable templates based on verbatim strings" +text pp_loc "Quote and highlight input fragments at a given source location" +text pp "Pretty-printing library" +text pprint "A pretty-printing combinator library and rendering engine" +text prettiest "Non-greedy pretty printer" +text re2 "OCaml bindings for RE2, Google's regular expression library" +text re2_stable "Re2_stable adds an incomplete but stable serialization of Re2" +text re "RE is a regular expression library for OCaml" +text rosa "String manipulation library " +text rosetta "Universal mapper to Unicode" +text sedlex "An OCaml lexer generator for Unicode" +text simple-diff "Simple_diff is a pure OCaml diffing algorithm." +text smart-print "A pretty-printing library in OCaml" +text snabela "Logic-less template system" +text sosa "Sane OCaml String API" +text spelll "Fuzzy string searching, using Levenshtein automaton" +text stdlib-diff "Symmetric Diffs for OCaml stdlib and ReasonML" +text stemmer "Porter stemming algorithm in pure OCaml" +text stemming "Collection of stemmers" +text stringext "Extra string functions for OCaml" +text text "Library for dealing with "text", i.e. sequence of unicode characters, in a convenient way" +text textmate-language "Tokenizing code with TextMate grammars for syntax highlighting" +text textrazor "An OCaml wrapper for the TextRazor API" +text text-tags "A library for rich formatting using semantics tags" +text textutils_kernel "Text output utilities" +text textutils "Text output utilities" +text textwrap "Text wrapping and filling library" +text tyre "Typed Regular Expressions" +text ubase "Remove diacritics from latin utf8 strings" +text uchar "Compatibility library for OCaml's Uchar module" +text ucorelib "A light weight Unicode library for OCaml" +text ulex-camlp5 "A lexer generator for Unicode (backported to camlp5)" +text ulex "lexer generator for Unicode and OCaml" +text unidecode "Convert unicode strings into its ASCII representation" +text uucd "Unicode character database decoder for OCaml" +text uucp "Unicode character properties for OCaml" +text uuidm "Universally unique identifiers (UUIDs) for OCaml" +text uunf "Unicode text normalization for OCaml" +text uuseg "Unicode text segmentation for OCaml" +text uutf "Non-blocking streaming Unicode codec for OCaml" +text uuuu "Mapper of ISO-8859-* to Unicode" +text vcaml "OCaml bindings for the Neovim API" +text wseg "A word identification system" +text wtf8 "Encoder and decoder for WTF-8" +text wu-manber-fuzzy-search "Wu-Manber approximate string matching" +text xstr "Functions for string searching/matching/splitting" +text xstrp4 "Brace expansion (alias 'interpolation') performed by camlp4" +text yuscii "Mapper of UTF-7 to Unicode" +text zed "Abstract engine for text edition in OCaml" +tezos tezos-008-PtEdo2Zk-test-helpers "Tezos/Protocol: protocol testing framework" +tezos tezos-009-PsFLoren-test-helpers "Tezos/Protocol: protocol testing framework" +tezos tezos-010-PtGRANAD-test-helpers "Tezos/Protocol: protocol testing framework" +tezos tezos-011-PtHangz2-test-helpers "Tezos/Protocol: protocol testing framework" +tezos tezos-012-Psithaca-test-helpers "Tezos/Protocol: protocol testing framework" +tezos tezos-013-PtJakart-test-helpers "Tezos/Protocol: protocol testing framework" +tezos tezos-014-PtKathma-test-helpers "Tezos/Protocol: protocol testing framework" +tezos tezos-accuser-006-PsCARTHA "Tezos/Protocol: 006_PsCARTHA accuser binary" +tezos tezos-accuser-007-PsDELPH1 "Tezos/Protocol: accuser binary" +tezos tezos-accuser-008-PtEdo2Zk "Tezos/Protocol: accuser binary" +tezos tezos-accuser-008-PtEdoTez "Tezos/Protocol: accuser binary" +tezos tezos-accuser-009-PsFLoren "Tezos/Protocol: accuser binary" +tezos tezos-accuser-010-PtGRANAD "Tezos/Protocol: accuser binary" +tezos tezos-accuser-011-PtHangz2 "Tezos/Protocol: accuser binary" +tezos tezos-accuser-012-Psithaca "Tezos/Protocol: accuser binary" +tezos tezos-accuser-013-PtJakart "Tezos/Protocol: accuser binary" +tezos tezos-accuser-014-PtKathma "Tezos/Protocol: accuser binary" +tezos tezos-accuser-alpha "Tezos/Protocol: accuser binary" +tezos tezos-alpha-test-helpers "Tezos/Protocol: protocol testing framework" +tezos tezos-baker-006-PsCARTHA "Tezos/Protocol: 006_PsCARTHA baker binary" +tezos tezos-baker-007-PsDELPH1 "Tezos/Protocol: baker binary" +tezos tezos-baker-008-PtEdo2Zk "Tezos/Protocol: baker binary" +tezos tezos-baker-008-PtEdoTez "Tezos/Protocol: baker binary" +tezos tezos-baker-009-PsFLoren "Tezos/Protocol: baker binary" +tezos tezos-baker-010-PtGRANAD "Tezos/Protocol: baker binary" +tezos tezos-baker-011-PtHangz2 "Tezos/Protocol: baker binary" +tezos tezos-baker-012-Psithaca "Tezos/Protocol: baker binary" +tezos tezos-baker-013-PtJakart "Tezos/Protocol: baker binary" +tezos tezos-baker-014-PtKathma "Tezos/Protocol: baker binary" +tezos tezos-baker-alpha "Tezos/Protocol: baker binary" +tezos tezos-baking-006-PsCARTHA-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-006-PsCARTHA "Tezos/Protocol: base library for `tezos-baker/endorser/accuser`" +tezos tezos-baking-007-PsDELPH1-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-007-PsDELPH1 "Tezos/Protocol: base library for `tezos-baker/endorser/accuser`" +tezos tezos-baking-008-PtEdo2Zk-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-008-PtEdo2Zk "Tezos/Protocol: base library for `tezos-baker/endorser/accuser`" +tezos tezos-baking-008-PtEdoTez-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-008-PtEdoTez "Tezos/Protocol: base library for `tezos-baker/endorser/accuser`" +tezos tezos-baking-009-PsFLoren-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-009-PsFLoren "Tezos/Protocol: base library for `tezos-baker/endorser/accuser`" +tezos tezos-baking-010-PtGRANAD-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-010-PtGRANAD "Tezos/Protocol: base library for `tezos-baker/endorser/accuser`" +tezos tezos-baking-011-PtHangz2-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-011-PtHangz2 "Tezos/Protocol: base library for `tezos-baker/endorser/accuser`" +tezos tezos-baking-012-Psithaca-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-012-Psithaca "Tezos/Protocol: base library for `tezos-baker/accuser`" +tezos tezos-baking-013-PtJakart-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-013-PtJakart "Tezos/Protocol: base library for `tezos-baker/accuser`" +tezos tezos-baking-014-PtKathma-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-014-PtKathma "Tezos/Protocol: base library for `tezos-baker/accuser`" +tezos tezos-baking-alpha-commands "Tezos/Protocol: protocol-specific commands for baking" +tezos tezos-baking-alpha "Tezos/Protocol: base library for `tezos-baker/endorser/accuser`" +tezos tezos-base58 "Base58 encoding for Tezos" +tezos tezos-base-test-helpers "Tezos: Tezos base test helpers" +tezos tezos-base "Tezos: meta-package and pervasive type definitions for Tezos" +tezos tezos-bls12-381-polynomial "Polynomials over BLS12-381 finite field" +tezos tezos-clic "Tezos: library of auto-documented command-line-parsing combinators" +tezos tezos-client-000-Ps9mPmXa "Tezos/Protocol: 000-Ps9mPmXa (protocol-specific commands for `tezos-client`)" +tezos tezos-client-001-PtCJ7pwo-commands "Tezos/Protocol: 001_PtCJ7pwo (protocol-specific commands for `tezos-client`)" +tezos tezos-client-001-PtCJ7pwo "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-002-PsYLVpVv-commands "Tezos/Protocol: 002_PsYLVpVv (protocol-specific commands for `tezos-client`)" +tezos tezos-client-002-PsYLVpVv "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-003-PsddFKi3-commands "Tezos/Protocol: 003_PsddFKi3 (protocol-specific commands for `tezos-client`)" +tezos tezos-client-003-PsddFKi3 "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-004-Pt24m4xi-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-004-Pt24m4xi "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-005-PsBabyM1-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-005-PsBabyM1 "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-006-PsCARTHA-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-006-PsCARTHA "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-007-PsDELPH1-commands-registration "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-007-PsDELPH1-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-007-PsDELPH1 "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-008-PtEdo2Zk-commands-registration "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-008-PtEdo2Zk-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-008-PtEdo2Zk "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-008-PtEdoTez-commands-registration "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-008-PtEdoTez-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-008-PtEdoTez "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-009-PsFLoren-commands-registration "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-009-PsFLoren-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-009-PsFLoren "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-010-PtGRANAD-commands-registration "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-010-PtGRANAD-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-010-PtGRANAD "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-011-PtHangz2-commands-registration "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-011-PtHangz2-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-011-PtHangz2 "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-012-Psithaca-commands-registration "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-012-Psithaca-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-012-Psithaca "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-013-PtJakart-commands-registration "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-013-PtJakart-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-013-PtJakart "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-014-PtKathma "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-alpha-commands-registration "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-alpha-commands "Tezos/Protocol: protocol-specific commands for `tezos-client`" +tezos tezos-client-alpha "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-base "Tezos: common helpers for `tezos-client`" +tezos tezos-client-base-unix "Tezos: common helpers for `tezos-client` (unix-specific fragment)" +tezos tezos-client-commands "Tezos: protocol agnostic commands for `tezos-client`" +tezos tezos-client-demo-counter "Tezos/Protocol: protocol specific library for `tezos-client`" +tezos tezos-client-genesis-carthagenet "Tezos/Protocol: genesis (protocol-specific commands for `tezos-client`)" +tezos tezos-client-genesis "Tezos/Protocol: genesis (protocol-specific commands for `tezos-client`)" +tezos tezos-client-sapling-008-PtEdo2Zk "Tezos: sapling support for `tezos-client`" +tezos tezos-client-sapling-008-PtEdoTez "Tezos: sapling support for `tezos-client`" +tezos tezos-client-sapling-009-PsFLoren "Tezos: sapling support for `tezos-client`" +tezos tezos-client-sapling-010-PtGRANAD "Tezos: sapling support for `tezos-client`" +tezos tezos-client-sapling-011-PtHangz2 "Tezos: sapling support for `tezos-client`" +tezos tezos-client-sapling-012-Psithaca "Tezos: sapling support for `tezos-client`" +tezos tezos-client-sapling-013-PtJakart "Tezos: sapling support for `tezos-client`" +tezos tezos-client-sapling-alpha "Tezos: sapling support for `tezos-client`" +tezos tezos-client "Tezos: `tezos-client` binary" +tezos tezos-codec "Tezos: `tezos-codec` binary to encode and decode values" +tezos tezos-context-hash-irmin "Irmin implementation of the Tezos context hash specification" +tezos tezos-context-hash "Specification of the Tezos context hash" +tezos tezos-context-ops "Tezos: backend-agnostic operations on contexts" +tezos tezos-context "Tezos: on-disk context abstraction for `tezos-node`" +tezos tezos-crypto "Tezos: library with all the cryptographic primitives used by Tezos" +tezos tezos-embedded-protocol-000-Ps9mPmXa "Tezos/Protocol: 000-Ps9mPmXa (economic-protocol definition, embedded in `tezos-node`)" +tezos tezos-embedded-protocol-001-PtCJ7pwo "Tezos/Protocol: 001_PtCJ7pwo (economic-protocol definition, embedded in `tezos-node`)" +tezos tezos-embedded-protocol-002-PsYLVpVv "Tezos/Protocol: 002_PsYLVpVv (economic-protocol definition, embedded in `tezos-node`)" +tezos tezos-embedded-protocol-003-PsddFKi3 "Tezos/Protocol: 003_PsddFKi3 (economic-protocol definition, embedded in `tezos-node`)" +tezos tezos-embedded-protocol-004-Pt24m4xi "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-005-PsBABY5H "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-005-PsBabyM1 "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-006-PsCARTHA "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-007-PsDELPH1 "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-008-PtEdo2Zk "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-008-PtEdoTez "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-009-PsFLoren "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-010-PtGRANAD "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-011-PtHangz2 "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-012-Psithaca "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-013-PtJakart "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-014-PtKathma "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-alpha "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" +tezos tezos-embedded-protocol-demo-counter "Tezos/Protocol: demo_counter (economic-protocol definition, embedded in `tezos-node`)" +tezos tezos-embedded-protocol-demo-noops "Tezos/Protocol: demo_noops (economic-protocol definition, embedded in `tezos-node`)" +tezos tezos-embedded-protocol-genesis-carthagenet "Tezos/Protocol: genesis_carthagenet (economic-protocol definition, embedded in `tezos-node`)" +tezos tezos-embedded-protocol-genesis "Tezos/Protocol: genesis (economic-protocol definition, embedded in `tezos-node`)" +tezos tezos-endorser-006-PsCARTHA "Tezos/Protocol: 006_PsCARTHA endorser binary" +tezos tezos-endorser-007-PsDELPH1 "Tezos/Protocol: endorser binary" +tezos tezos-endorser-008-PtEdo2Zk "Tezos/Protocol: endorser binary" +tezos tezos-endorser-008-PtEdoTez "Tezos/Protocol: endorser binary" +tezos tezos-endorser-009-PsFLoren "Tezos/Protocol: endorser binary" +tezos tezos-endorser-010-PtGRANAD "Tezos/Protocol: endorser binary" +tezos tezos-endorser-011-PtHangz2 "Tezos/Protocol: endorser binary" +tezos tezos-endorser-alpha "Tezos/Protocol: endorser binary" +tezos tezos-error-monad "Tezos: error monad" +tezos tezos-event-logging-test-helpers "Tezos: test helpers for the event logging library" +tezos tezos-event-logging "Tezos event logging library" +tezos tezos-hacl-glue "Tezos: thin layer of glue around hacl-star (virtual package)" +tezos tezos-hacl-glue-unix "Tezos: thin layer of glue around hacl-star (unix implementation)" +tezos tezos-hacl "Tezos: thin layer around hacl-star" +tezos tezos-injector-013-PtJakart "Tezos/Protocol: protocol specific library building injectors" +tezos tezos-injector-014-PtKathma "Tezos/Protocol: protocol specific library building injectors" +tezos tezos-injector-alpha "Tezos/Protocol: protocol specific library building injectors" +tezos tezos-legacy-store "Tezos: legacy low-level key-value store for `tezos-node`" +tezos tezos-lmdb "Legacy Tezos OCaml binding to LMDB (Consider ocaml-lmdb instead)" +tezos tezos-lwt-result-stdlib "Tezos: error-aware stdlib replacement" +tezos tezos-mempool-006-PsCARTHA "Tezos/Protocol: mempool-filters for protocol 006-PsCARTHA" +tezos tezos-mempool-007-PsDELPH1 "Tezos/Protocol: mempool-filters" +tezos tezos-mempool-008-PtEdoTez "Tezos/Protocol: mempool-filters" +tezos tezos-micheline-rewriting "Tezos: library for rewriting Micheline expressions" +tezos tezos-micheline "Tezos: internal AST and parser for the Michelson language" +tezos tezos-mockup-commands "Tezos: library of auto-documented RPCs (commands)" +tezos tezos-mockup-proxy "Tezos: local RPCs" +tezos tezos-mockup-registration "Tezos: protocol registration for the mockup mode" +tezos tezos-mockup "Tezos: library of auto-documented RPCs (mockup mode)" +tezos tezos-node "Tezos: `tezos-node` binary" +tezos tezos-openapi "Tezos: a library for querying RPCs and converting into the OpenAPI format" +tezos tezos-p2p-services "Tezos: descriptions of RPCs exported by `tezos-p2p`" +tezos tezos-p2p "Tezos: library for a pool of P2P connections" +tezos tezos-plompiler "Library to write arithmetic circuits for Plonk" +tezos tezos-plonk "Plonk zero-knowledge proving system" +tezos tezos-protocol-000-Ps9mPmXa "Tezos/Protocol: 000_Ps9mPmXa (economic-protocol definition, functor version)" +tezos tezos-protocol-001-PtCJ7pwo "Tezos/Protocol: 001_PtCJ7pwo (economic-protocol definition, functor version)" +tezos tezos-protocol-002-PsYLVpVv "Tezos/Protocol: 002_PsYLVpVv (economic-protocol definition, functor version)" +tezos tezos-protocol-003-PsddFKi3 "Tezos/Protocol: 003_PsddFKi3 (economic-protocol definition, functor version)" +tezos tezos-protocol-004-Pt24m4xi "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-005-PsBABY5H "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-005-PsBabyM1 "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-006-PsCARTHA-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-006-PsCARTHA "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-007-PsDELPH1-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-007-PsDELPH1 "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-008-PtEdo2Zk-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-008-PtEdo2Zk "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-008-PtEdoTez-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-008-PtEdoTez "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-009-PsFLoren-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-009-PsFLoren "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-010-PtGRANAD-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-010-PtGRANAD "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-011-PtHangz2-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-011-PtHangz2 "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-012-Psithaca-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-012-Psithaca "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-013-PtJakart-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-013-PtJakart "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-014-PtKathma "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-alpha-parameters "Tezos/Protocol: parameters" +tezos tezos-protocol-alpha "Tezos/Protocol: economic-protocol definition" +tezos tezos-protocol-compiler "Tezos: economic-protocol compiler" +tezos tezos-protocol-demo-counter "Tezos/Protocol: demo_counter economic-protocol definition" +tezos tezos-protocol-demo-noops "Tezos/Protocol: demo_noops economic-protocol definition" +tezos tezos-protocol-environment-packer "Tezos: sigs/structs packer for economic protocol environment" +tezos tezos-protocol-environment-sigs "Tezos: restricted typing environment for the economic protocols" +tezos tezos-protocol-environment-structs "Tezos: restricted typing environment for the economic protocols" +tezos tezos-protocol-environment "Tezos: custom economic-protocols environment implementation for `tezos-client` and testing" +tezos tezos-protocol-genesis-carthagenet "Tezos/Protocol: genesis_carthagenet economic-protocol definition" +tezos tezos-protocol-genesis "Tezos/Protocol: genesis economic-protocol definition" +tezos tezos-protocol-plugin-007-PsDELPH1-registerer "Tezos/Protocol: protocol plugin registerer" +tezos tezos-protocol-plugin-007-PsDELPH1 "Tezos/Protocol: protocol plugin" +tezos tezos-protocol-plugin-008-PtEdo2Zk-registerer "Tezos/Protocol: protocol plugin registerer" +tezos tezos-protocol-plugin-008-PtEdo2Zk "Tezos/Protocol: protocol plugin" +tezos tezos-protocol-plugin-009-PsFLoren-registerer "Tezos/Protocol: protocol plugin registerer" +tezos tezos-protocol-plugin-009-PsFLoren "Tezos/Protocol: protocol plugin" +tezos tezos-protocol-plugin-010-PtGRANAD-registerer "Tezos/Protocol: protocol plugin registerer" +tezos tezos-protocol-plugin-010-PtGRANAD "Tezos/Protocol: protocol plugin" +tezos tezos-protocol-plugin-011-PtHangz2-registerer "Tezos/Protocol: protocol plugin registerer" +tezos tezos-protocol-plugin-011-PtHangz2 "Tezos/Protocol: protocol plugin" +tezos tezos-protocol-plugin-012-Psithaca-registerer "Tezos/Protocol: protocol plugin registerer" +tezos tezos-protocol-plugin-012-Psithaca-tests "Tezos/Protocol: protocol plugin tests" +tezos tezos-protocol-plugin-012-Psithaca "Tezos/Protocol: protocol plugin" +tezos tezos-protocol-plugin-013-PtJakart-registerer "Tezos/Protocol: protocol plugin registerer" +tezos tezos-protocol-plugin-013-PtJakart-tests "Tezos/Protocol: protocol plugin tests" +tezos tezos-protocol-plugin-013-PtJakart "Tezos/Protocol: protocol plugin" +tezos tezos-protocol-plugin-014-PtKathma-registerer "Tezos/Protocol: protocol plugin registerer" +tezos tezos-protocol-plugin-014-PtKathma "Tezos/Protocol: protocol plugin" +tezos tezos-protocol-plugin-alpha-registerer "Tezos/Protocol: protocol plugin registerer" +tezos tezos-protocol-plugin-alpha-tests "Tezos/Protocol: protocol plugin tests" +tezos tezos-protocol-plugin-alpha "Tezos/Protocol: protocol plugin" +tezos tezos-protocol-updater "Tezos: economic-protocol dynamic loading for `tezos-node`" +tezos tezos-proxy-server-config "Tezos: proxy server configuration" +tezos tezos-proxy-server "Tezos: `tezos-proxy-server` binary" +tezos tezos-proxy "Tezos: proxy" +tezos tezos-requester "Tezos: generic resource fetching service" +tezos tezos-rpc-http-client "Tezos: library of auto-documented RPCs (http client)" +tezos tezos-rpc-http-client-unix "Tezos: unix implementation of the RPC client" +tezos tezos-rpc-http-server "Tezos: library of auto-documented RPCs (http server)" +tezos tezos-rpc-http "Tezos: library of auto-documented RPCs (http server and client)" +tezos tezos-rpc "Tezos: library of auto-documented RPCs (service and hierarchy descriptions)" +tezos tezos-rust-libs "Tezos: all rust dependencies and their dependencies" +tezos tezos-sapling "OCaml library for the Sapling protocol, using librustzcash" +tezos tezos-sapling-parameters "Sapling parameters used in Tezos" +tezos tezos-scoru-wasm "Protocol environment dependency providing WASM functionality for SCORU" +tezos tezos-shell-benchmarks "Tezos: shell benchmarks" +tezos tezos-shell-context-test "Testing the Shell Context" +tezos tezos-shell-context "Tezos: economic-protocols environment implementation for `tezos-node`" +tezos tezos-shell-services-test-helpers "Tezos: Tezos shell_services test helpers" +tezos tezos-shell-services "Tezos: descriptions of RPCs exported by `tezos-shell`" +tezos tezos-shell "Tezos: core of `tezos-node` (gossip, validation scheduling, mempool, ...)" +tezos tezos-signer-backends "Tezos: remote-signature backends for `tezos-client`" +tezos tezos-signer-services "Tezos: descriptions of RPCs exported by `tezos-signer`" +tezos tezos-signer "Tezos: `tezos-signer` binary" +tezos tezos-stdlib "Tezos: yet-another local-extension of the OCaml standard library" +tezos tezos-stdlib-unix "Tezos: yet-another local-extension of the OCaml standard library (unix-specific fragment)" +tezos tezos-storage "Tezos: low-level key-value store for `tezos-node`" +tezos tezos-store "Tezos: store for `tezos-node`" +tezos tezos-test-helpers-extra "Test helpers dependent on tezos-base" +tezos tezos-test-helpers "Tezos-agnostic test helpers" +tezos tezos-test-services "Tezos: Alcotest-based test services" +tezos tezos "Tezos meta package installing all active binaries" +tezos tezos-tooling "Tezos: tooling for the project" +tezos tezos-tx-rollup-013-PtJakart "Tezos/Protocol: protocol specific library for `tezos-tx-rollup`" +tezos tezos-tx-rollup-014-PtKathma "Tezos/Protocol: protocol specific library for `tezos-tx-rollup`" +tezos tezos-tx-rollup-alpha "Tezos/Protocol: protocol specific library for `tezos-tx-rollup`" +tezos tezos-tx-rollup-client-013-PtJakart "Tezos/Protocol: `tezos-tx-rollup-client-alpha` client binary" +tezos tezos-tx-rollup-client-014-PtKathma "Tezos/Protocol: `tezos-tx-rollup-client-alpha` client binary" +tezos tezos-tx-rollup-client-alpha "Tezos/Protocol: `tezos-tx-rollup-client-alpha` client binary" +tezos tezos-tx-rollup-node-013-PtJakart "Tezos/Protocol: Transaction Rollup node binary" +tezos tezos-tx-rollup-node-014-PtKathma "Tezos/Protocol: Transaction Rollup node binary" +tezos tezos-tx-rollup-node-alpha "Tezos/Protocol: Transaction Rollup node binary" +tezos tezos-validation "Tezos: library for blocks validation" +tezos tezos-validator "Tezos: `tezos-validator` binary for external validation of blocks" +tezos tezos-version "Tezos: version information generated from Git" +tezos tezos-webassembly-interpreter "WebAssembly reference interpreter with tweaks for Tezos" +tezos tezos-workers "Tezos: worker library" +time ago "ago(1) - compute the number of days between two calendar dates" +time apero-time "OCaml Time Stamping Library" +time caldav "A CalDAV server" +time calendar "Library for handling dates and times in your program" +time calendars "Convert dates between gregorian/julian/french/hebrew calendars" +time dates_calc "A date calculation library" +time daypack-lib "A schedule, time and time slots handling library" +time duration "Conversions to various time units" +time glical "Glical: glancing at iCalendar data." +time icalendar "A library to parse and print the iCalendar (RFC 5545) format" +time ISO8601 "ISO 8601 and RFC 3999 date parsing for OCaml" +time mtime "Monotonic wall-clock time for OCaml" +time oclock "Oclock: Precise POSIX clock for OCaml" +time odate "Date & Duration Library" +time ptime "POSIX time for OCaml" +time timedesc-json "Timedesc JSON backend" +time timedesc "OCaml date time handling library" +time timedesc-sexp "Timedesc Sexp backend" +time timedesc-tzdb "Virtual library for Timedesc time zone database backends" +time timedesc-tzlocal-js "JS implementation for timedesc-tzlocal" +time timedesc-tzlocal "Virtual library for Timedesc local time zone detection backends" +time timed "Timed references for imperative state" +time time_now "Reports the current time" +time timere "OCaml date time reasoning library" +time timere-parse "OCaml date time and duration natural language parsing library" +time timezone "Time-zone handling" +tooling BetterErrors "Better compiler error output." +tooling bisect "Code coverage tool for the OCaml language" +tooling bisect_ppx "Code coverage for OCaml" +tooling bisect_ppx-ocamlbuild "Ocamlbuild plugin for Bisect_ppx, the coverage tool" +tooling bisect-summary +tooling camelot "An OCaml Linter / Style Checker" +tooling camlidl "Stub code generator for OCaml" +tooling camlmix "Camlmix is a generic preprocessor which converts text with embedded" +tooling camlp5 "Preprocessor-pretty-printer of OCaml" +tooling cmitomli "Converts compiled interface files (.cmi) into source interface files (.mli)" +tooling cmon "A library for printing OCaml values with sharing" +tooling codept "alternative ocaml dependency analyzer" +tooling coinst "Coinst tool suite to perform analysis on package repositories." +tooling cppo "Code preprocessor like cpp for OCaml" +tooling cppo_ocamlbuild "Plugin to use cppo with ocamlbuild" +tooling dead_code_analyzer "dead_code_analyzer -- Dead code analyzing tool." +tooling depgraph "dot graphs out of ocamldep output" +tooling drom_lib "The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like user experience" +tooling drom "The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like user experience" +tooling dum "Inspect the runtime representation of arbitrary OCaml values" +tooling dumpast "OCaml AST dumper" +tooling dump_ocamlformat "Dump preset configuration files for ocamlformat" +tooling earlybird "Debug adapter for OCaml 4.11" +tooling exn-source "Exception backtrace for OCaml with source code printing" +tooling findlib_top "Exposes findlib_top.cma without the need for using predicates" +tooling fromager "A CLI to format an ocaml codebase" +tooling gospel "A tool-agnostic formal specification language for OCaml" +tooling headache "Automatic generation of files headers" +tooling inspect "Inspect the runtime representation of arbitrary OCaml values." +tooling mascot "A style-checker for OCaml sources (code, documentation, interface, metrics, and typography)." +tooling mkocaml "Tool to generate OCaml projects" +tooling mld "The MLD package makes directory foo.mld turn into module Foo" +tooling namespaces "Turn directories into OCaml modules" +tooling not-ocamlfind "A small frontend for ocamlfind that adds a few useful commands" +tooling obelisk "Pretty-printing for Menhir files" +tooling objsize "Small library to compute sizes of OCaml heap values" +tooling ocaml_at_p "OCaml@p : A debugging print system for OCaml" +tooling ocamlclean "Reduce size of OCaml bytecode files by dead-code removing" +tooling ocamlc-loc "Parse ocaml compiler output into structured form" +tooling ocamldsort "Sorts a set of OCaml source files according to their dependencies" +tooling ocamlfind "A library manager for OCaml" +tooling ocamlfind-lint "Simple tool performing checks on installed findlib META files" +tooling ocamlfind-secondary "Adds support for ocaml-secondary-compiler to ocamlfind" +tooling ocamlformat "Auto-formatter for OCaml code" +tooling ocamlformat-rpc "Auto-formatter for OCaml code (RPC mode)" +tooling ocamlformat-rpc-lib "Auto-formatter for OCaml code (RPC mode)" +tooling ocamlformat_support "Support package for OCamlFormat" +tooling ocaml-indent "OCaml-indent: OCaml source code indenter" +tooling ocamllint "Detect common errors in OCaml code" +tooling ocaml-migrate-parsetree "Convert OCaml parsetrees between different versions" +tooling ocaml-migrate-parsetree-ocamlbuild "Ocamlbuild plugin for ocaml-migrate-parsetree" +tooling ocamlmod "Generate OCaml modules from source files" +tooling ocamlpp "OCaml binary files (.byte and .cmo) pretty printers." +tooling ocaml-print-intf "Display human-readable OCaml interface from a compiled .cmi" +tooling ocamlscript "Tool which compiles OCaml scripts into native code" +tooling ocaml-version "Manipulate, parse and generate OCaml compiler version strings" +tooling ocamlwc "Count lines in OCaml source code" +tooling ocp-build "Project manager for OCaml" +tooling ocp-indent "A simple tool to indent OCaml programs" +tooling ocp-indent-nlfork "ocp-indent library, "newline tokens" fork" +tooling ocp-manager "Global Manager for OCaml versions and OPAM switches" +tooling ocp-ocamlres "Manipulation, injection and extraction of embedded resources" +tooling ocp-pack-split "ocp-pack and ocp-split" +tooling ocp-pp "A simple preprocessor for OCaml" +tooling ocp-reloc "Relocation of OCaml bytecode executables" +tooling odoc-depgraph +tooling ogen "A tool for creating new OCaml projects with OPAM, Oasis, and Merlin" +tooling omod "Lookup and load installed OCaml modules" +tooling opaca "A friendly OCaml project scaffolding tool" +tooling optcomp "Optional compilation with cpp-like directives" +tooling oqamldebug "Graphical front-end to ocamldebug" +tooling oskel "Skeleton generator for OCaml projects" +tooling podge "Shortcuts and helpers for common tasks in OCaml ecosystem" +tooling rdbg "RDBG: a reactive programs debugger." +tooling reanalyze "Dead values/types, exception, and termination analysis for OCaml/ReScript" +tooling rotor "An automatic refactoring tool for OCaml" +tooling spin "OCaml project generator" +tooling spotinstall "A tool to facilitate the installation of OCaml annotation files (.cmt, .cmti, .spot, .spit)" +tooling starterkit "Virtual package for starting OCaml" +tooling trax "Stack-independent exception tracing" +tooling user-setup +unix build_path_prefix_map "An OCaml implementation of the BUILD_PATH_PREFIX_MAP specification" +unix extunix "Collection of thin bindings to various low-level system API" +unix fd-send-recv "Bindings for sendmsg/recvmsg that allow Unix.file_descrs to be sent and received over Unix domain sockets" +unix unix-dirent +unix unix-errno "Unix errno types, maps, and support" +unix unix-fcntl "Unix fcntl.h types, maps, and support" +unix unix-sys-resource +unix unix-sys-stat +unix unix-time "Unix time.h types, maps, and support" +unix unix-type-representations +unix unix-unistd "Host-independent unistd.h bindings" +utils accessor "A library that makes it nicer to work with nested functional data structures" +utils accessor_async "Accessors for Async types, for use with the Accessor library" +utils accessor_base "Accessors for Base types, for use with the Accessor library" +utils accessor_core "Accessors for Core types, for use with the Accessor library" +utils annexlib "An extension to the standard library" +utils apero-core "OCaml Utility Library" +utils archi +utils archi-async +utils archi-lwt +utils atomic +utils bau "Bigarray utilities" +utils bear "Bare essential additions to the stdlib" +utils bigarray-overlap "Bigarray.overlap" +utils bigstringaf "Bigstring intrinsics and fast blits based on memcpy/memmove" +utils bigstring "A set of utils for dealing with `bigarrays` of `char`" +utils bigstring-unix "I/O functions for bigstrings using file descriptors and memory-maps" +utils bitstring "Bitstrings and bitstring matching for OCaml" +utils bytearray "Efficient marshaling to and from bigarrays" +utils bytebuffer "Extensible buffers built on top of bigarrays" +utils camlix "Simple circuit breaker" +utils camllib "Utility Library (including various datatypes)" +utils camlp-streams "The Stream and Genlex libraries for use with Camlp4 and Camlp5" +utils canary "Capture unhandled exceptions and automatically report them through various channels" +utils captureio "Capture output to Stderr and Stdout" +utils cfstream "Stream operations in the style of Core's API" +utils clarity "Functional programming library" +utils comparelib "Part of Jane Street’s Core library" +utils crunch "Convert a filesystem into a static OCaml module" +utils delimcc "Oleg's delimited continuations library for byte-code and native OCaml" +utils domainslib "Nested-parallel programming library" +utils dtoa "Converts OCaml floats into strings (doubles to ascii, 'd to a'), using the efficient Grisu3 algorithm" +utils dyn "Dynamic type" +utils dynload-sys "Sys.argv override for dynamically loaded libraries" +utils easy-format +utils ez_api "Easy API library and tools" +utils fieldslib "Syntax extension to define first class values representing record fields, to get and set record fields, iterate and fold over all fields of a record and create new record values" +utils gen "Iterators for OCaml, both restartable and consumable" +utils GT "Generic programming with extensible transformations" +utils hack_parallel "Parallel and shared memory library" +utils higher_kinded "A library with an encoding of higher kinded types in OCaml" +utils higher "Library for higher-kinded programming" +utils iter "Simple abstraction over `iter` functions, intended to iterate efficiently on collections while performing some transformations" +utils lens "Functional lenses" +utils linkage "easier plugin loading" +utils make-random "Helper to build a module similar to Stdlib.Random" +utils maki "Persistent incremental computations, for repeatable tests and benchmarks." +utils missinglib "Collection of OCaml-related utilities" +utils mixture "The Mixture package is a mixin library for the module system" +utils monomorphic +utils more-ocaml "Support code for the book 'More OCaml'" +utils mwt "Mediumweight thread library for OCaml via Lwt" +utils nproc "Process pool implementation for OCaml." +utils ocaml-basics "Implements common functionnal patterns / abstractions" +utils ocaml_intrinsics "Intrinsics" +utils ocaml_plugin "Automatically build and dynlink OCaml source files" +utils ocplib-endian +utils ocplib_stuff "Basic stuff used by some OCP libraries and tools" +utils offheap "Copies OCaml objects out of the OCaml heap" +utils optint "Efficient integer types on 64-bit architectures" +utils orec "dynamic open records" +utils pa_ovisitor +utils parany "Parallelize any computation" +utils parmap "Minimalistic library allowing to exploit multicore architecture" +utils pattern "Run-time patterns that explain match failures" +utils plato "Python Library Adapted To OCaml" +utils prbnmcn-basic-structures "Base package for prbnmcn-* packages" +utils prbnmcn-stats "Basic statistics" +utils pringo "Pseudo-random, splittable number generators" +utils pumping "Regular languages in types" +utils pure-splitmix "Purely functional splittable PRNG" +utils record_builder "A library which provides traversal of records with an applicative" +utils records "Records" +utils regular "Library for regular data types" +utils reins +utils repr "Dynamic type representations. Provides no stability guarantee" +utils revops "Reversible operations" +utils selective "Selective applicative functors in OCaml" +utils sendmsg "π-calculus? In _my_ kernel?" +utils shared-secret "Exceptions are shared secrets" +utils simple63 "Integer compression and decompression module" +utils spotlib "Useful functions for OCaml programming used by @camlspotter" +utils stdint "Signed and unsigned integer types having specified widths" +utils stdune "Dune's unstable standard library" +utils subtype-refinement "Refinement types encoded with private types in OCaml" +utils traits "Common traits for generic functionality" +utils type_conv "Library for building type-driven syntax extensions" +utils typehashlib "Part of Jane Street’s Core library" +utils typerep_extended "Runtime types for OCaml" +utils typerep "typerep is a library for runtime types." +utils typeset "An embedded DSL for defining source code pretty printers" +utils unmagic "Runtime tag-checking of marshaled ocaml data" +utils variantslib "Part of Jane Street's Core library" +utils zephyrus "Zephyrus automatic configuration generation tool." +variants bsbnative "bsb-native is BuckleScript's bsb but for ocamlc and ocamlopt" +variants dkml-base-compiler "OCaml cross-compiler and libraries from the DKML distribution that works with at least Win32 and macOS" +variants dkml-component-staging-ocamlrun "DKML component for ocamlrun" +variants dkml-component-staging-opam32 "DKML component for 32-bit versions of opam" +variants dkml-component-staging-opam64 "DKML component for 64-bit versions of opam" +variants dkml-component-xx-console +variants dkml-c-probe +variants dkml-dune-dsl +variants dkml-dune-dsl-show +variants dkml-install "API and registry for Diskuv OCaml (DKML) installation components" +variants dkml-install-installer "Build tools for DKML installers" +variants dkml-install-runner "Runner executable for Diskuv OCaml (DKML) installation" +variants dkml-package-console +variants dkml-workflows +variants flowcaml +variants genlet "Let-insertion for MetaOCaml." +variants ocaml-base-compiler "First beta release of OCaml 5.0.0" +variants ocaml-beta "Virtual package for enabling OCaml beta releases" +variants ocamlcc "Compiler from OCaml bytecode executable files to C source code" +variants ocaml-compiler-libs "OCaml compiler libraries repackaged" +variants ocaml-config "OCaml Switch Configuration" +variants ocaml-freestanding-cross-aarch64 "Freestanding OCaml compiler" +variants ocaml-freestanding "Freestanding OCaml compiler" +variants ocaml-option-32bit "Set OCaml to be compiled in 32-bit mode for 64-bit Linux and OS X hosts" +variants ocaml-option-afl "Set OCaml to be compiled with afl-fuzz instrumentation" +variants ocaml-option-bytecode-only "Compile OCaml without the native-code compiler" +variants ocaml-option-default-unsafe-string "Set OCaml to be compiled without safe strings by default" +variants ocaml-option-flambda "Set OCaml to be compiled with flambda activated" +variants ocaml-option-fp "Set OCaml to be compiled with frame-pointers enabled" +variants ocaml-option-musl "Set OCaml to be compiled with musl-gcc" +variants ocaml-option-nnpchecker "Set OCaml to be compiled with --enable-naked-pointers-checker" +variants ocaml-option-nnp "Set OCaml to be compiled with --disable-naked-pointers" +variants ocaml-option-no-flat-float-array "Set OCaml to be compiled with --disable-flat-float-array" +variants ocaml-options-only-afl "Ensure that OCaml is compiled with AFL support enabled, and no other custom options" +variants ocaml-options-only-flambda "Ensure that OCaml is compiled with flambda activated, and no other custom options" +variants ocaml-options-only-flambda-fp "Ensure that OCaml is compiled with flambda and frame-pointer enabled, and no other custom options" +variants ocaml-options-only-fp "Ensure that OCaml is compiled with only frame-pointer enabled, and no other custom options" +variants ocaml-options-only-nnpchecker "Ensure that OCaml is compiled with enable-naked-pointers-checker, and no other custom options" +variants ocaml-options-only-nnp "Ensure that OCaml is compiled with no-naked-pointers, and no other custom options" +variants ocaml-options-only-no-flat-float-array "Ensure that OCaml is compiled with no-flat-float-array, and no other custom options" +variants ocaml-option-spacetime "Set OCaml to be compiled with spacetime activated" +variants ocaml-option-static "Set OCaml to be compiled with musl-gcc -static" +variants ocaml-options-vanilla "Ensure that OCaml is compiled with no special options enabled" +variants ocaml-secondary-compiler "OCaml 4.08.1 Secondary Switch Compiler" +variants ocaml-solo5-cross-aarch64 "Freestanding OCaml compiler" +variants ocaml-solo5 "Freestanding OCaml compiler" +variants ocaml-src "Compiler sources" +variants ocaml-system "The OCaml compiler (system version, from outside of opam)" +variants ocaml "The OCaml compiler (virtual package)" +variants ocaml-twt "The Whitespace Thing, a layout preprocessor for OCaml code" +variants ocaml-variants "Current trunk" +video ffmpeg-av "Bindings for the ffmpeg libraries -- top-level helpers" +video ffmpeg-avcodec "Bindings for the ffmpeg avcodec library" +video ffmpeg-avdevice "Bindings for the ffmpeg avdevice library" +video ffmpeg-avfilter "Bindings for the ffmpeg avfilter library" +video ffmpeg-avutil "Bindings for the ffmpeg avutil libraries" +video ffmpeg "Bindings for the ffmpeg libraries" +video ffmpeg-swresample "Bindings for the ffmpeg swresample library" +video ffmpeg-swscale "Bindings for the ffmpeg swscale library" +video frei0r "Bindings for the frei0r API which provides video effects" +video oplay "Raw YUV video player" +video schroedinger "Bindings for the schroedinger library to decode video files in Dirac format" +video theora "Bindings to libtheora" +web CamlGI "FastCGI and CGI library" +web camyll "A static site generator" +web ccss "CCSS is a preprocessor for CSS, extending the language with arithmetic operations and variables." +web cgi "Library for writing CGIs" +web cookie "Cookie handling for OCaml and ReasonML" +web cookies "HTTP cookies library for OCaml" +web cowabloga "Simple static blogging support" +web cow "Caml on the Web" +web css-parser "A CSS parser written in OCaml" +web dispatch "Path-based dispatching for client- and server-side applications" +web dream-accept "Accept headers parsing for Dream" +web dream-cli "Command Line Interface for Dream applications" +web dream-encoding "Encoding primitives for Dream" +web dream-htmx "Htmx utilities for Dream" +web dream-httpaf "Internal: shared http/af stack for Dream (server) and Hyper (client)" +web dream-livereload "Live reloading for Dream applications" +web dream-pure "Internal: shared HTTP types for Dream (server) and Hyper (client)" +web dream-serve "Static site server with live reload" +web dream "Tidy, feature-complete Web framework" +web eliom "Client/server Web framework" +web finch "Simple and fast site generator" +web FPauth-core "Easy authentication system for Dream framework" +web FPauth "Easy authentication system for Dream framework" +web FPauth-responses "Responses on basic events in FPauth-core authentication system" +web FPauth-strategies "Strategies to be used with FPauth-core authentication system" +web horned_worm "An easy functional Web app micro framework" +web jerboa "Jerboa is a minimalistic web framework for everyone" +web lambdoc "Library providing support for semantically rich documents in web applications." +web litiom "Extensions to Ocsigen's Eliom." +web minima-theme "OCaml port of the Jekyll Minima theme" +web naboris "Simple http server" +web ocamlapi_async "Path-based HTTP request routing for Ocaml" +web ocamlapi_lwt_unix "Path-based HTTP request routing for Ocaml" +web ocamlapi "Path-based HTTP request routing for Ocaml" +web ocamlapi_ppx "Path-based HTTP request routing for Ocaml" +web ocsigen-i18n "I18n made easy for web sites written with eliom" +web ocsigen-ppx-rpc "This PPX adds a syntax for RPCs for Eliom and Ocsigen Start" +web ocsigenserver "A full-featured and extensible Web server" +web ocsigen-start "An Eliom application skeleton ready to use to build your own application with users, (pre)registration, notifications, etc" +web ocsigen-toolkit "Reusable UI components for Eliom applications (client only, or client-server)" +web openapi_router "Http server agnostic Openapi documentation generation" +web opium-graphql "Run GraphQL servers with Opium" +web opium_kernel "Sinatra like web toolkit based on Lwt + Cohttp" +web opium "Sinatra like web toolkit based on Async + Cohttp" +web opium-testing "Testing library for Opium" +web owebl "A fast, light, and concurrent web framework inspired by Flask and Sinatra." +web rock "Minimalist framework to build extensible HTTP servers and clients" +web routes "Typed routing for OCaml applications" +web scgi "Simple Common Gateway Interface (SCGI) protocol support for interface with HTTP servers" +web sihl-cache "Cache service implementations for Sihl" +web sihl-contract "Sihl serivce interfaces" +web sihl-core "The core of the Sihl web framework" +web sihl-email "Email service implementations for Sihl" +web sihl-facade +web sihl-persistence "Sihl services to deal with data persistence" +web sihl-queue "Queue service implementations for Sihl" +web sihl-session "Sihl service to deal with sessions" +web sihl-storage "Storage service implementations for Sihl" +web sihl "The Sihl web framework" +web sihl-token "Token service implementations for Sihl" +web sihl-type "Contains Sihl types that are returned by Sihl services" +web sihl-user "User service implementations for Sihl" +web sihl-web "Sihl HTTP service and middlewares" +web sill "Implementation of Linear Session Types" +web slug "Url safe slug generator" +web soupault "Static website generator based on HTML rewriting" +web stationary "Static site generator" +web stone "Simple static website generator, useful for a portfolio or documentation pages" +web tiny_httpd_camlzip "Interface to camlzip for tiny_httpd" +web tiny_httpd "Minimal HTTP server using good old threads" +web wdialog "Dialog-oriented web applications" +web webbrowser "Open and reload URIs in browsers from OCaml" +web weberizer "Compile HTML templates into OCaml modules" +web webmachine "A REST toolkit for OCaml" +web wtr-ppx "Ppx to create routers" +web wtr "Well Typed Router" +web yurt "An HTTP framework for OCaml" +windows win-error "Manipulate Windows system errors" +windows win-eventlog "Log via the Windows event log from OCaml programs" +windows winsvc "Library to make OCaml program act as a Windows service" +xen libvhd "OCaml bindings for the C library 'libvhd' which allows the manipulation" +xen minios-xen "A minimal OS for running under the Xen hypervisor" +xen netchannel "Network device for reading and writing Ethernet frames via then Xen netfront/netback protocol" +xen vchan-unix "Xen Vchan implementation" +xen vchan "Xen Vchan implementation" +xen vchan-xen "Xen Vchan implementation" +xen xapi-backtrace "A simple library for recording and managing backtraces" +xen xapi-forkexecd "Sub-process control service for xapi" +xen xapi-idl "Interface descriptions and common boilerplate for xapi services." +xen xapi-inventory "Library for accessing the xapi toolstack inventory file" +xen xapi-libs-transitional "Further transitional libraries required by xapi" +xen xapi-rrdd "Performance monitoring daemon for xapi" +xen xapi-rrd "RRD library for use with xapi" +xen xapi-rrd-transport "Shared-memory protocols for exposing performance counters" +xen xapi-stdext "A deprecated collection of utility functions" +xen xapi-stdext-date "Xapi's standard library extension, Dates" +xen xapi-stdext-encodings "Xapi's standard library extension, Encodings" +xen xapi-stdext-pervasives "Xapi's standard library extension, Pervasives" +xen xapi-stdext-std "Xapi's standard library extension, Stdlib" +xen xapi-stdext-threads "Xapi's standard library extension, Threads" +xen xapi-stdext-unix "Xapi's standard library extension, Unix" +xen xapi-stdext-zerocheck "Xapi's standard library extension, Zerocheck" +xen xapi-tapctl "A library to control tapdisk on a Xen host" +xen xapi-xenops "Create/destroy/manipulate Xen domains" +xen xe "A command-line client for the 'xapi' service (as used in XenServer)" +xen xen-api-client +xen xenbigarray "Portable Bigarray intended for embedded Xen use" +xen xen-block-driver +xen xenctrl "Low-level Xen hypercall bindings." +xen xen-disk +xen xen-evtchn-unix "Xen event channel interface for Linux" +xen xen-evtchn "Xen event channel interface for MirageOS" +xen xen-gnt-unix "Xen grant table bindings for OCaml" +xen xen-gnt "Xen grant table bindings for OCaml" +xen xenstore_transport "Low-level libraries for connecting to a xenstore service on a xen host" +xen xenstore "Xenstore protocol in pure OCaml" +xen xentropyd "Xentropyd: provide entropy to Xen VMs" +xen xe-unikernel-upload "A simple tool to upload a Unikernel to a XenServer pool." +xml decoders-ezxmlm "Ezxmlm backend for decoders" +xml erm_xml "XML stream parser" +xml ezxmlm "Combinators for parsing and selection of XML structures" +xml ocaml-expat "Write XML-Parsers using the SAX method" +xml ocaml-xml-rpc +xml pxp "Polymorphic XML Parser" +xml tyxml "A library for building correct HTML and SVG documents" +xml tyxml-jsx "JSX syntax to write TyXML documents" +xml tyxml-lwd "Make reactive webpages in Js_of_ocaml using Tyxml and Lwd" +xml tyxml-ppx "PPX to write TyXML documents with the HTML syntax" +xml tyxml-syntax "Common layer for the JSX and PPX syntaxes for Tyxml" +xml xmelly "Simplest way to do simple parsing of simple XML files in OCaml" +xml xmldiff "Computing and applying diffs on XML trees" +xml xmldiff_js "Using Xmldiff on DOM" +xml xml-light "Xml-Light is a minimal XML parser & printer for OCaml" +xml xmlm "Streaming XML codec for OCaml" +xml xtmpl_js "Xml templating library, javascript library" +xml xtmpl_ppx "Xml templating library, ppx extension" +xml xtmpl "Small XML templating library." diff --git a/static/style.css b/static/style.css index e96039198e..03804e1f25 100644 --- a/static/style.css +++ b/static/style.css @@ -163,10 +163,45 @@ code { } .ad { - padding-top: 3rem; + padding: 3rem 0; font-family: monospace; font-style: italic; font-size: 1rem; } .ad svg { vertical-align: middle; margin-right: 0.5rem } + +.categories { + margin: 0; + margin-top: 3em; + margin-left: 2.5em; + margin-right: 2.5em; + padding: 0; + column-count: 4; + column-gap: 1em; + column-width: 20em; + line-height: 1.1em; +} + +.categories .category { + margin: 0; + padding: 0; + display: inline-block; +} + +.category h3 { + margin: 0; + padding: 0; + margin-top: 1.5em; + margin-bottom: 0.7em; +} + +.packages a { + display: inline-block; + white-space: nowrap; + margin-right: 1.5em; + font-family: monospace; +} +.packages a:hover { + background: #eee; +} diff --git a/www/packages.ml b/www/packages.ml new file mode 100644 index 0000000000..8b2b97cb67 --- /dev/null +++ b/www/packages.ml @@ -0,0 +1,162 @@ +type package = + { category : string + ; name : string + ; description : string + } + +module M = Map.Make (String) + +module S = Set.Make (struct + type t = package + + let compare a b = + String.compare + (String.lowercase_ascii a.name) + (String.lowercase_ascii b.name) +end) + +let pretty = function + | "ai" -> "Sciences" + | "app" -> "Applications" + | "ascii" -> "Formats: Restricted alphabet" + | "audio" -> "Multimedia: Audio" + | "bap" -> "PLT: Binary Analysis Platform" + | "bench" -> "Benchmarking" + | "bindings" -> "Various bindings" + | "bio" -> "Sciences" + | "build" -> "Tooling: Build systems" + | "chemistry" -> "Sciences" + | "cloud" -> "Cloud" + | "color" -> "Multimedia: Images" + | "compression" -> "Formats: Compression" + | "conf" -> "conf" + | "cordova" -> "Javascript: Cordova" + | "crypto" -> "Cryptography" + | "data" -> "Datastructures" + | "databases" -> "Databases" + | "dns" -> "Network: DNS" + | "document" -> "Formats: Text document" + | "documentation" -> "Tooling: Documentation" + | "email" -> "Network: Email" + | "format" -> "Formats" + | "frp" -> "Reactive programming" + | "graphics2d" -> "Graphics: 2D" + | "graphics3d" -> "Graphics: 3D" + | "gui" -> "GUI" + | "hardcaml" -> "Hardcaml" + | "http" -> "Network: HTTP client" + | "ide" -> "Tooling: IDE" + | "images" -> "Multimedia: Images" + | "interoperability" -> "Interoperability" + | "io" -> "I/O" + | "irc" -> "Network: IRC" + | "irmin" -> "Databases: Irmin" + | "javascript" -> "Javascript" + | "js" -> "Javascript" + | "json" -> "Formats: Json" + | "language" -> "Programming languages" + | "linux" -> "System: Linux" + | "log" -> "Logs" + | "macos" -> "System: Mac Os" + | "maths" -> "Maths" + | "mirage" -> "Mirage" + | "monads" -> "Stdlib monadic" + | "monitor" -> "Monitoring" + | "multimedia" -> "Multimedia" + | "network" -> "Network" + | "notebook" -> "Tooling: Toplevel / Notebook" + | "opam" -> "Tooling: Opam / Packaging" + | "packaging" -> "Tooling: Opam / Packaging" + | "parser" -> "Parsers" + | "plt" -> "PLT" + | "ppx" -> "PPX" + | "prover" -> "Theorem provers" + | "retrocompatibility" -> "Stdlib retrocompatibility" + | "science" -> "Sciences" + | "security" -> "Cryptography" + | "sexp" -> "Formats: Sexp" + | "solver" -> "Constraint solvers" + | "ssh" -> "Network: SSH" + | "stdlib" -> "Stdlib extended" + | "system" -> "System" + | "terminal" -> "Terminal" + | "tests" -> "Testing" + | "text" -> "Text" + | "tezos" -> "Tezos" + | "time" -> "Date and Time" + | "tooling" -> "Tooling" + | "unix" -> "System: Unix" + | "utils" -> "Stdlib complements" + | "variants" -> "OCaml variants" + | "video" -> "Multimedia: Video" + | "web" -> "Web server" + | "windows" -> "System: Windows" + | "xen" -> "Xen" + | "xml" -> "Formats: Xml" + | "" -> "--- TODO ---" + | other -> + Format.printf "TODO: missing category name %S@." other ; + other + +let unescape str = + let str = String.trim str in + let buf = Buffer.create (String.length str) in + for i = 0 to String.length str - 1 do + let chr = str.[i] in + if not (chr = '\'' || chr = '"') then Buffer.add_char buf chr + done ; + Buffer.contents buf + +let load filename = + let h = open_in filename in + let rec go acc = + match input_line h with + | exception End_of_file -> acc + | line -> + let package = + match String.split_on_char '\t' line with + | [ category; name; description ] -> + { category = pretty category + ; name + ; description = unescape description + } + | [ name; description ] -> + { category = pretty ""; name; description = unescape description } + | _ -> failwith (Printf.sprintf "invalid package: %S" line) + in + let set = try M.find package.category acc with Not_found -> S.empty in + let set = S.add package set in + let acc = M.add package.category set acc in + go acc + in + let result = go M.empty in + close_in h ; + result + +let packages = + List.fold_left + (fun acc p -> M.remove p acc) + (load "./static/packages.csv") + [ "Tezos"; "conf" ] + +open Tyxml.Html + +let html = + div + ~a:[ a_class [ "categories" ] ] + (M.bindings packages + |> List.map (fun (category, packages) -> + div + ~a:[ a_class [ "category" ] ] + [ h3 [ txt (if category = "" then "Not classified" else category) ] + ; div + ~a:[ a_class [ "packages" ] ] + (S.elements packages + |> List.map (fun package -> + a + ~a: + [ a_href ("https://ocaml.org/p/" ^ package.name) + ; a_title package.description + ] + [ txt package.name ])) + ])) diff --git a/www/ui.ml b/www/ui.ml index 4063bb37e1..4e6cbd4bdb 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -166,5 +166,6 @@ let explain = ; link ": 'a list -> ('a * int -> bool) -> 'a list" ] ] + ; Packages.html ; link_to_repo ] From 1f0cdabb8beda8e3dd1c5a767e10b5516e86b5b5 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 13 Apr 2023 14:33:02 +0200 Subject: [PATCH 010/285] filter results by package name --- query/succ.ml | 42 +++++++++++++++++++++++------------------- www/www.ml | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/query/succ.ml b/query/succ.ml index e6966521ba..9d07a5167a 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -110,24 +110,28 @@ let rec first = function and first_opt t = try Some (first t) with Not_found -> None -let first t = - let rec go n elt acc = - if n <= 0 - then Lwt.return (List.rev acc) - else - let open Lwt.Syntax in - let* () = Lwt.pause () in - match succ_ge elt t with - | elt' -> - assert (Elt.compare elt elt' = 0) ; - go_gt (n - 1) elt (elt :: acc) - | exception Gt elt -> go n elt acc - | exception Not_found -> Lwt.return (List.rev acc) - and go_gt n elt acc = - match succ_gt elt t with - | elt -> go n elt acc - | exception Not_found -> Lwt.return (List.rev acc) +let to_stream t = + let state = ref None in + let rec go elt = + let open Lwt.Syntax in + let* () = Lwt.pause () in + match succ_ge elt t with + | elt' -> + assert (Elt.compare elt elt' = 0) ; + state := Some elt ; + Lwt.return (Some elt) + | exception Gt elt -> go elt + | exception Not_found -> Lwt.return None in - Lwt.catch (fun () -> go 100 (first t) []) (fun (_ : exn) -> Lwt.return []) + let go_gt () = + match !state with + | None -> go (first t) + | Some previous_elt -> ( + match succ_gt previous_elt t with + | elt -> go elt + | exception Not_found -> Lwt.return None) + in + let next () = Lwt.catch (fun () -> go_gt ()) (fun _ -> Lwt.return None) in + Lwt_stream.from next -let to_list t = first t.s +let to_stream t = to_stream t.s diff --git a/www/www.ml b/www/www.ml index 37972a8902..a897a53917 100644 --- a/www/www.ml +++ b/www/www.ml @@ -23,24 +23,39 @@ let search (has_typ, query_name, query_typ) = open Lwt.Syntax module H = Tyxml.Html -let api raw_query = +let match_packages ~packages { Db.Elt.pkg = package, _version; _ } = + List.exists (String.equal package) packages + +let match_packages ~packages results = + match packages with + | [] -> results + | _ -> Lwt_stream.filter (match_packages ~packages) results + +let api ~packages raw_query = let has_typ, query_name, query_typ, query_typ_arrow, pretty = Query.Parser.of_string raw_query in let* results = search (has_typ, query_name, query_typ) in - let+ results = Succ.to_list results in + let results = Succ.to_stream results in + let results = match_packages ~packages results in + let+ results = Lwt_stream.nget 100 results in let results = Sort.list query_name query_typ_arrow results in Ui.render ~pretty results -let api query = - if String.trim query = "" then Lwt.return Ui.explain else api query +let api ~packages query = + if String.trim query = "" then Lwt.return Ui.explain else api ~packages query open Lwt.Syntax let get_query params = Option.value ~default:"" (Dream.query params "q") -let root ~query fn _params = - let* result = fn query in +let get_packages params = + match Dream.query params "packages" with + | None -> [] + | Some str -> String.split_on_char ',' str + +let root fn ~query ~packages = + let* result = fn ~packages query in Dream.html result let string_of_tyxml html = Format.asprintf "%a" (Tyxml.Html.pp ()) html @@ -48,7 +63,8 @@ let string_of_tyxml' html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) html let root fn params = let query = get_query params in - try root ~query fn params + let packages = get_packages params in + try root fn ~query ~packages with err -> Format.printf "ERROR: %S@." (Printexc.to_string err) ; Dream.html (string_of_tyxml @@ Ui.template query Ui.explain) @@ -66,15 +82,15 @@ let cache : int -> Dream.middleware = let () = Dream.run ~interface:"127.0.0.1" ~port:1234 - @@ Dream.logger @@ cache 3600 + @@ Dream.logger (* @@ cache 3600 *) @@ Dream.router [ Dream.get "/" - (root (fun q -> - let+ result = api q in + (root (fun ~packages q -> + let+ result = api ~packages q in string_of_tyxml @@ Ui.template q result)) ; Dream.get "/api" - (root (fun q -> - let+ result = api q in + (root (fun ~packages q -> + let+ result = api ~packages q in string_of_tyxml' result)) ; Dream.get "/s.css" (Dream.from_filesystem "static" "style.css") ; Dream.get "/robots.txt" (Dream.from_filesystem "static" "robots.txt") From c560c88b8654726815b04ae8a163017bfe9bc5e0 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 13 Apr 2023 14:51:42 +0200 Subject: [PATCH 011/285] limit number of results --- query/query_parser.ml | 11 +++---- www/www.ml | 68 +++++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/query/query_parser.ml b/query/query_parser.ml index 11becbe881..f4c4395b0f 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -17,13 +17,13 @@ let guess_type_search str = let of_string str = let str = String.trim str in - let ok, str_name, str_typ = + let has_typ, str_name, str_typ = match String.split_on_char ':' str with | [ a; b ] -> true, a, b | _ when guess_type_search str -> true, "", str | _ -> false, str, "" in - let pretty, ps, ps_arrow = + let pretty_typ, query_typ, paths_typ = match parse str_typ with | Any -> "_", [], [] | typ -> @@ -34,6 +34,7 @@ let of_string str = , paths_arrow ~prefix:[] ~sgn:Db.Types.Pos typ ) | exception _ -> "", [], [] in - let keywords = naive_of_string str_name in - let keywords_pretty = String.concat " " keywords in - ok, keywords, ps, ps_arrow, keywords_pretty ^ " : " ^ pretty + let query_name = naive_of_string str_name in + let query_typ = if has_typ then Some query_typ else None in + let pretty_query = String.concat " " query_name ^ " : " ^ pretty_typ in + query_name, query_typ, paths_typ, pretty_query diff --git a/www/www.ml b/www/www.ml index a897a53917..2bb822d5cf 100644 --- a/www/www.ml +++ b/www/www.ml @@ -2,21 +2,27 @@ module Storage = Db.Storage module Succ = Query.Succ module Sort = Query.Sort +type params = + { query : string + ; packages : string list + ; limit : int + } + let db_filename = Sys.argv.(1) let shards = let h = Storage.db_open_in db_filename in Array.to_list h.Storage.shards -let search (has_typ, query_name, query_typ) = +let search query_name query_typ = let open Lwt.Syntax in let* results_name = Query.find_names ~shards query_name in let+ results = - if has_typ - then - let+ results_typ = Query.find_inter ~shards query_typ in - Succ.inter results_name results_typ - else Lwt.return results_name + match query_typ with + | None -> Lwt.return results_name + | Some query_typ -> + let+ results_typ = Query.find_inter ~shards query_typ in + Succ.inter results_name results_typ in results @@ -31,19 +37,19 @@ let match_packages ~packages results = | [] -> results | _ -> Lwt_stream.filter (match_packages ~packages) results -let api ~packages raw_query = - let has_typ, query_name, query_typ, query_typ_arrow, pretty = - Query.Parser.of_string raw_query +let api params = + let query_name, query_typ, query_typ_arrow, pretty = + Query.Parser.of_string params.query in - let* results = search (has_typ, query_name, query_typ) in + let* results = search query_name query_typ in let results = Succ.to_stream results in - let results = match_packages ~packages results in - let+ results = Lwt_stream.nget 100 results in + let results = match_packages ~packages:params.packages results in + let+ results = Lwt_stream.nget params.limit results in let results = Sort.list query_name query_typ_arrow results in Ui.render ~pretty results -let api ~packages query = - if String.trim query = "" then Lwt.return Ui.explain else api ~packages query +let api params = + if String.trim params.query = "" then Lwt.return Ui.explain else api params open Lwt.Syntax @@ -54,20 +60,32 @@ let get_packages params = | None -> [] | Some str -> String.split_on_char ',' str -let root fn ~query ~packages = - let* result = fn ~packages query in +let get_limit params = + let default = 100 in + match Dream.query params "limit" with + | None -> default + | Some str -> ( + try max 1 (min default (int_of_string str)) with _ -> default) + +let get_params params = + { query = get_query params + ; packages = get_packages params + ; limit = get_limit params + } + +let root fn params = + let* result = fn params in Dream.html result let string_of_tyxml html = Format.asprintf "%a" (Tyxml.Html.pp ()) html let string_of_tyxml' html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) html let root fn params = - let query = get_query params in - let packages = get_packages params in - try root fn ~query ~packages + let params = get_params params in + try root fn params with err -> Format.printf "ERROR: %S@." (Printexc.to_string err) ; - Dream.html (string_of_tyxml @@ Ui.template query Ui.explain) + Dream.html (string_of_tyxml @@ Ui.template params.query Ui.explain) let root fn params = try root fn params @@ -85,12 +103,12 @@ let () = @@ Dream.logger (* @@ cache 3600 *) @@ Dream.router [ Dream.get "/" - (root (fun ~packages q -> - let+ result = api ~packages q in - string_of_tyxml @@ Ui.template q result)) + (root (fun params -> + let+ result = api params in + string_of_tyxml @@ Ui.template params.query result)) ; Dream.get "/api" - (root (fun ~packages q -> - let+ result = api ~packages q in + (root (fun params -> + let+ result = api params in string_of_tyxml' result)) ; Dream.get "/s.css" (Dream.from_filesystem "static" "style.css") ; Dream.get "/robots.txt" (Dream.from_filesystem "static" "robots.txt") From f11bc70c983bc7bf7002bad3079fe1117ce2b32a Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 13 Apr 2023 16:09:01 +0200 Subject: [PATCH 012/285] option to set cache max age --- www/dune | 2 +- www/www.ml | 55 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/www/dune b/www/dune index 96fec40001..80cfd2bc17 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,3 @@ (executable (name www) - (libraries dream db query)) + (libraries cmdliner dream db query)) diff --git a/www/www.ml b/www/www.ml index 2bb822d5cf..781457c55e 100644 --- a/www/www.ml +++ b/www/www.ml @@ -8,13 +8,11 @@ type params = ; limit : int } -let db_filename = Sys.argv.(1) - -let shards = +let load_shards db_filename = let h = Storage.db_open_in db_filename in Array.to_list h.Storage.shards -let search query_name query_typ = +let search ~shards query_name query_typ = let open Lwt.Syntax in let* results_name = Query.find_names ~shards query_name in let+ results = @@ -37,19 +35,21 @@ let match_packages ~packages results = | [] -> results | _ -> Lwt_stream.filter (match_packages ~packages) results -let api params = +let api ~shards params = let query_name, query_typ, query_typ_arrow, pretty = Query.Parser.of_string params.query in - let* results = search query_name query_typ in + let* results = search ~shards query_name query_typ in let results = Succ.to_stream results in let results = match_packages ~packages:params.packages results in let+ results = Lwt_stream.nget params.limit results in let results = Sort.list query_name query_typ_arrow results in Ui.render ~pretty results -let api params = - if String.trim params.query = "" then Lwt.return Ui.explain else api params +let api ~shards params = + if String.trim params.query = "" + then Lwt.return Ui.explain + else api ~shards params open Lwt.Syntax @@ -91,26 +91,51 @@ let root fn params = try root fn params with _ -> Dream.html (string_of_tyxml @@ Ui.template "" Ui.explain) -let cache : int -> Dream.middleware = +let cache : int option -> Dream.middleware = fun max_age f req -> let+ response = f req in - Dream.add_header response "Cache-Control" - ("public, max-age=" ^ string_of_int max_age) ; + begin + match max_age with + | None -> () + | Some max_age -> + Dream.add_header response "Cache-Control" + ("public, max-age=" ^ string_of_int max_age) + end ; response -let () = +let main db_filename cache_max_age = + let shards = load_shards db_filename in Dream.run ~interface:"127.0.0.1" ~port:1234 - @@ Dream.logger (* @@ cache 3600 *) + @@ Dream.logger @@ cache cache_max_age @@ Dream.router [ Dream.get "/" (root (fun params -> - let+ result = api params in + let+ result = api ~shards params in string_of_tyxml @@ Ui.template params.query result)) ; Dream.get "/api" (root (fun params -> - let+ result = api params in + let+ result = api ~shards params in string_of_tyxml' result)) ; Dream.get "/s.css" (Dream.from_filesystem "static" "style.css") ; Dream.get "/robots.txt" (Dream.from_filesystem "static" "robots.txt") ; Dream.get "/favicon.ico" (Dream.from_filesystem "static" "favicon.ico") ] + +open Cmdliner + +let path = + let doc = "Database filename" in + Arg.(required & pos 0 (some file) None & info [] ~docv:"DB" ~doc) + +let cache_max_age = + let doc = "HTTP cache max age (in seconds)" in + Arg.(value & opt (some int) None & info [ "c"; "cache" ] ~docv:"MAX_AGE" ~doc) + +let www = Term.(const main $ path $ cache_max_age) + +let cmd = + let doc = "Webserver for sherlodoc" in + let info = Cmd.info "www" ~doc in + Cmd.v info www + +let () = exit (Cmd.eval cmd) From d5f38adba08b32c2ca45b7e0b55586ea8c141dd5 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 13 Apr 2023 16:12:39 +0200 Subject: [PATCH 013/285] add favicon --- static/favicon.ico | Bin 0 -> 34494 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 static/favicon.ico diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3ae37187ff2cb846b9fabf76664bd75aede150c3 GIT binary patch literal 34494 zcmeI5d6X2@y~jJ}y!S``c_)8*vM4SX5Tk&s9Fr}>y#U(cA}rU_O3_r>$+WiTc@jQ z?I`KsS>EyQ)`i}!Z|`&s8+N+I&+gLkx*c4HpRs-lZAAO6Z|`z*ANiv@^Y$0rX*WFQ zCf&T%oxSGwuJO4y9KY4I?C629*Sl(u{!YB;DR;>9W$x4evD%$-WxMaKG+gsM>(&zWO>G%HJeRR?V?u=WXca57~@995GFWzt1 z(Cv;t?-4iq!T(iTy9{31S-AF9ckr~!-0}bQu(jET79qOxY<}HquIahm)&{tb{_6ei zpvf1x&-~A0{l33Qv;l|w`fhjnO`F}PzHpB_Z1$Dzps5$TLuM><)9?GawHbyx{GEQe zKKhIIx`U=%tm7iVeX09o{mpK&#v=)L-v(ne@w#UX*2Csp<&OQvgKo;5KeRTNzWBF* z_M!3f@7Y=OfPb|FA z@bEP9@Au+C;l}Tb!OYdawlSD^!zOp;Z7&!+y`EK{T$>!}?AzmPyd++w9el57J(vXQZlfQb(r0c)w0MEBa|{?_N;X+WC5Zy>vksj|#pAZFRnG zZMSvqY}gnto0aruZK~~Ja0g@AW&DNw!DptgB4Zl|OJdvbliEQB-~-x22IfEcvRm-< zE5>V$(i44nqePm*tLJ?GPwv#K*Sk-DZM9@%x%;?u<*)@e*!hV3a?_vl9{+QocS>y6 zOj^Uii4_ilK9_aWn4!Wl{a&+x2JU9r;8@ z&3xe3Zi#etdseYHDy`ekn7^_xr$ij$LC#dupc_>3ZwhzuRdUY2lhP)#<=@N7twpH26oz= zy5h$s+a|+FwlM)8Xo*cfRI~+V;61YWP8&zY7JF^-ARK`u>^sH58@&fF;D5mz_z}o2 zJ`}tIy!d+18~ULm!u%U;EAATD@bi%0p=VzsS^7&45Ai&0Gd?4l?r^6_N2TRWU<5AY zXNbmj+RC4~bEOk#6JEi;K%W}#U;k|C_JI+YPQQ7J@gQJ=8#smEq z$ky&u{9`ne9-t5O+Zg#%_#x2y=Ljim1l8x7~3^=;krg?mvu zpVUs=eGhlOWygZ3Ka}+~e%KHl<8%;5^0|NjF!EWrrRyVgZC&f@+eP;_>4XHDXLX-G z=!-t{&%OEKd|PL0^R~aI))ke&6WG$fJNo8(T0K=s-~L_SZ(94r`#tY^*md^pra70| zH_xF<%zjAspnuQ}-k$jD2HE`nV%apX`Df7w^o?JNZJcoJM)N_B`{ws7E<5g9Yuva? z*Sg7f{J``SzH!tq^KGR)W7~+`k6L=S?CEu8`#*NZg=U|yujpFt<8R6S{&I?c*=eKK?B^0Q?_6e)xpYgPg)adUo_z?hkaTXy@B1=gjy{z57SjE-~-C z$Nyq^5bPy1_6Kk_Z+%lRtT8_fcu%=%o#iYl;RpJkqW+=nxJ#Zke?Cc88TXm@|H^z< ze3RjeZ!=!3gcsoP$;wxJ^z=fmM|dXD5njQ^I{cjL%nlR7FfRBNN$(W9Z}_YKLuXxS zZP7>UJCc8Vm$UBqsrhB*XUq4Pe(%rBj>o=Jik?@y#0uE{xN(I4;01D8_bR;%^O;Kg1XuF8Y%(A@km`C`N)qrSK@$S;aUVSLK{PQS?CXXJB(Yv6+`meP0MFK6Nj`k(p0 zuS`Fe+h6!S`kuD(rv)9jtQW4nZ}2Clh;NO~YTCRf6TIQCIct8WvAx=O+xN%Wk2$nJ z-q3-Jx%FM9O$_4=@4>(1j=|0MZMaGw!*53|y~}bM@IUzh;0?D?$#>#Qc#VFIzr@@0 z$#?SD*d`xmTdXUbk;zJQUKn25qz}dvTEpwZ8*g)GKl}&Fqgot592t@mvq>4yo;Jh% zgEM*^9Y;;e8xG*=s_%Kg_Z-(xJM~cO;{q>df8#DzD^S8|hCr0;2!7tbSG`=To zCiU0feRwl^cpKf{d*R>c+v35D^hLPsV&8qg_3a%k&D;KAa1?tdtKaF{`c&WfmQKaM zJ6fS#xnq$Au7Kv6XHuW^9Z3gN{gONdb47JJdh!&S!;bqjZQMCZa`kLoTgTpj*UF1~ z)6gsZvw{hJ7L56pj!nP}E_JQjN7T1=yxIJ`c&$vCOAkwF^Y?M>0;9nyn3t^IJ-n{9 ztBvcpXKVRh0CQKHVBBMQr;x8w%W!+x3NY_Ut6Tm1HE}lmUW>9?s(fSzyV*?1miOIy z^4^-)<(}z=L9mBOd;&c96Xs_Wd=9R`gWLeVUwBRte=*1h_MIP1>SLhp0|!1lc^Uju za#AN~9+LSH;x>GBd`SFt<`Iuva;G~+xie~pc)qTs!{Ys{{Mb_Q#CL?gr(Uzcjr`mS z%ctPi`*}|04)Jq2$oVlBY}fM7ITNe$EI82yJeFl#S_}{RgD1$tPp0au0UNb2lW+fl&6zQ`P7DF;#2NVY%mp$hO}r5ocNK%BoZp$-TDW$*!ATy8_z$>8 zG~Mpb5WM7G10Q_1s>58or7$Rf1v19MEj;6|Mn zF&c5A&!3PZB2SYhJ}RZZ=rdvX;r~&ppF=OE@%!K}bP)I>JH~^`a}odZTeQzCuY2H^ zoT5+2HCdl=JQG8IU_sx&Lq2x|{EP)TI_fuK`7fcZw73QOXS>aflNXq@d|PUoVee)X z<`cXOkb4`Y8cOJsW-QagFa3l3sz!-EXFv4YRPzYX78$0N$n!t+XDp6da#zLkBBkOp zPx&ZvQl&o6b3T_fO?f`#)ziKQe%WpCtAFR@U+8TIuyde? zO&7=~8A$#qh2GE*J!o~sf}NZd{t-SA{)6S43vhe*sVg!YAU!;g^4lN$&@HgJK~9id z+|ggUPqb$KLGu6wo9kirXLKmPr>)8B50*5)K`(SDc7VB*G0GXj+rd1Jbi8~e4{O{R z+Ec%6zPD(QrteChHNQdgIn+zxi+MlPcw~OS+i@`ad+0Fa0X>FZtrVU#@1v{n8}Tin zb=aPI_!7_J8S_O2JA9MXoK~su8?TFJnDZm|jz66UYe-hTuZ`bHoCDp_O{Mmm)pPj6 zRtqN|BCN+_aS*MMVb5E@J!$z?^Hodr`?7+YcJLvHZ;21#-B_4Kb7TOXB0j+9ryd2{ z#rxo24LcQwH#8%*g6F9XjKYs?;x~9@%-0{Z+C*Y3bQJGeeP~AhSR8!)-7{S&7|efH zEEt6y9{I$g8_izfW0*ZawGLH2LUAVi zll8oEf3)W}^bT-gSMgaq{NDey98U>)93G-(0Xas0n$M7gYldS4{P<(kQ+xWu=lH_R z&rz>jj0XIUZ$!P>hbNpTzxmF9zp7w+-g5O3o{`}zlT;<3u( z024KTK8H@8j_>3h@!zn2j0ZAL%@BGy+HN(ky|r%wE!G$CK~Hc%E_)w-E{S>Qm^^Q2T#NPd?(bQ(Q|g>smd|BLhb-YLu`R}0 z^YDW$KkxEFiExY0{QR}8^Vmo02dI^y2BN-Y$D7SByyJ1IDSZ$f8+gTF70kd+4T{yz zw05l3vwNsP()#Nf#DTd_)rARe@%&m}KLh;le+G{N)M<^=ae)qBrRWeoiqGE3&JLBXd!jOt*|pi!&Uf;y9Ub6U*Va8YOox1H*B2VMXs?PbZ@YT-MJdbP z)&QPG;08BvY!a>w>$^S=4eHl*jaj^Dk89lg)_WH3=y-xFIM+YZHHJNKnzsIJzro$p z!f+PulJ!??50fIilH)9WCr3UO^`6zH^?ty$C>z=^x_|jt`ywKn{toZQRXU+=B<8nXf^j4c?TbBd+gUoJ{ns2IdJG;bK;u2pZ%cf zQEG?=9)D`AkY|s-)lqBCfce-Nt9}{OnrZF^J#Tqm&9j1cKnKx6dIMd_JSTO`)Fedf z0BE1RgQ(BLj$|=@m9`OwKl~0aTivU81Ni{YQu~5Nj4|^SQJ%7WK{ZF=?MkU_4%Bmf z@Q3Fm2jjJ_bm{YN8;_UMH~3N8VS6J;Z+gChw#ddb?GsV$x~w=nqWGJxll~6&0xZAg znRc1iWWTboTtNrui+q4T&&9!2t$R`Yv2lTnzHGigC2$}&%#VV9*q#J7WVz{4n{zMI zZdU@Ee>aLhwwszqbbA_^_w9wxj4yRr*uXIUUcazk2D&2rPPM;B@rO6Fs<$=#SH|F9 z&@pG+`hwLpR2%1Te;$9<(zEv>^Wmpy-(q+-{9HNTk$>7U8z7v$4#Y1&CRmF^T}L@> zXZ4Q9pE38f4#YT>@}0k66F-j?G50dCZ8@`r@{n6kjbX~8p_xMZCc>gM?y?x<6HiFtj zk2m=M>QJl(Ee?0#k1as{dA1gOptN*GXTU2~BPu_hyvV7Fjldgz?<4PwdFUX%B)(w% z2koTof3Tj1zp)F98G7Qh8#mj!UhpB-87e&&w)0_}!`}~6ULaVLlWu+9VBu}KA=xte zhiBP;20W2(@*m(I#;?Ec_MYm_*mE}v8#|CR@%oH?&RJhY-5Ie9vTHbt2L0h0_Zxgt z&f3g@#51mK>_4)JToc0)w_1*`44ge3;1%ov`hxf{uHRa?2Vb%W8aW^QLGpSYhjP!x zGm5Rq6JslC0na!X@JIOH3i5f_FrULJ7jNVQ8X`NkCP;OuasAf9J@}nEOk0mAIWHGy zXy(_t5bJ*Sq9=uOuztT5@Qj1O;sEhIb=u@>%fa2}PJFJDHQd;E_#K}(uHRa@hdv@6 zM^0mX){y@arVY=c7tI#R{J#@XhPG@rDu%mHHOk$d(CL0)5VE{s3(Jn%QqvhO4N{}Ka$Gd8o*oY7#& z13b!}o9L`0-e)Zkc(WJh>H0qgYS@jxB{$GdwRbfw-~G`Qf1deH^G{;@8)$-DpvP^j zHOE1IBMpD^oe?!XkS)na4 zBkPV>Q^b5?+I?vTnl9+SS?oC+(SJTq!&)!!NDYU^m{@{+04y(}_=ojL_?fk2C(Qmy zpZmR=dh8$LFMo*t@hc}*2S;)T>`RWHfPSq-{JrmMIdIvy9{gqVng3_sFxzJ(rOYzU zRB=$P;tyXV1MD-5z6?$-wmTDP)Y&kk^{IXVC z9|^pk51`2rT9XTXpaJ^Q>{+M=0$vB_#f4lje9sz0;%HCLn#Nx|VDQU_Wp0`^q8{#H z3$>3Be4+fs*bASqdXSzP7}>Ib7Qz31P)9}lbCha=@E6UWR{jWD);j*|_eT7JAAi!N z!9G^#ZSNC951-$r#)nvseI41qkzCOT`NrXA!aM~2=u-Yiwbt~1FS{lhzz4_z|M$hd z5fHkNCkCrsvVQR%mFPJe{?@|HRXul38a z5yXAu2Z?*xUxWY3VIBOGyL8z3CDZxTjFI~xu0|K)KXC9p?SBBKfp;LE^*SE;MMuCN z*aCdR-bbMxTF)U%=If>O9R?DQ_uJlga}}{;w?FfiaF Date: Thu, 13 Apr 2023 16:55:14 +0200 Subject: [PATCH 014/285] allow CORS http header --- www/www.ml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/www/www.ml b/www/www.ml index 781457c55e..41915f1666 100644 --- a/www/www.ml +++ b/www/www.ml @@ -91,7 +91,7 @@ let root fn params = try root fn params with _ -> Dream.html (string_of_tyxml @@ Ui.template "" Ui.explain) -let cache : int option -> Dream.middleware = +let cache_header : int option -> Dream.middleware = fun max_age f req -> let+ response = f req in begin @@ -103,10 +103,15 @@ let cache : int option -> Dream.middleware = end ; response +let cors_header f req = + let+ response = f req in + Dream.add_header response "Access-Control-Allow-Origin" "*" ; + response + let main db_filename cache_max_age = let shards = load_shards db_filename in Dream.run ~interface:"127.0.0.1" ~port:1234 - @@ Dream.logger @@ cache cache_max_age + @@ Dream.logger @@ cache_header cache_max_age @@ cors_header @@ Dream.router [ Dream.get "/" (root (fun params -> From 234d175fe832691d42c1e75b7b976fd9faecdcf1 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 13 Apr 2023 17:16:01 +0200 Subject: [PATCH 015/285] handle CORS options request --- www/www.ml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/www/www.ml b/www/www.ml index 41915f1666..93f309831c 100644 --- a/www/www.ml +++ b/www/www.ml @@ -108,6 +108,13 @@ let cors_header f req = Dream.add_header response "Access-Control-Allow-Origin" "*" ; response +let cors_options = + Dream.options "**" (fun _ -> + let+ response = Dream.empty `No_Content in + Dream.add_header response "Access-Control-Allow-Methods" "GET, OPTIONS" ; + Dream.add_header response "Access-Control-Allow-Headers" "*" ; + response) + let main db_filename cache_max_age = let shards = load_shards db_filename in Dream.run ~interface:"127.0.0.1" ~port:1234 @@ -124,6 +131,7 @@ let main db_filename cache_max_age = ; Dream.get "/s.css" (Dream.from_filesystem "static" "style.css") ; Dream.get "/robots.txt" (Dream.from_filesystem "static" "robots.txt") ; Dream.get "/favicon.ico" (Dream.from_filesystem "static" "favicon.ico") + ; cors_options ] open Cmdliner From b674e9999bbbc2308ec63073a8baf3187b1e49ad Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 14 Apr 2023 17:52:16 +0200 Subject: [PATCH 016/285] add background image --- static/bg.jpg | Bin 0 -> 27401 bytes static/style.css | 6 ++++++ www/www.ml | 1 + 3 files changed, 7 insertions(+) create mode 100644 static/bg.jpg diff --git a/static/bg.jpg b/static/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..748bbcfc45075425fd2f0bcbc37a54440c786796 GIT binary patch literal 27401 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 KzPkNu{(k^U%CMgR literal 0 HcmV?d00001 diff --git a/static/style.css b/static/style.css index 03804e1f25..56c11b1dea 100644 --- a/static/style.css +++ b/static/style.css @@ -1,7 +1,13 @@ +html { + min-height: 100%; +} + body { margin: 0; padding: 0; margin-bottom: 1em; + min-height: 100%; + background: url("/bg.jpg") no-repeat bottom right; } form { diff --git a/www/www.ml b/www/www.ml index 93f309831c..e934b521d9 100644 --- a/www/www.ml +++ b/www/www.ml @@ -131,6 +131,7 @@ let main db_filename cache_max_age = ; Dream.get "/s.css" (Dream.from_filesystem "static" "style.css") ; Dream.get "/robots.txt" (Dream.from_filesystem "static" "robots.txt") ; Dream.get "/favicon.ico" (Dream.from_filesystem "static" "favicon.ico") + ; Dream.get "/bg.jpg" (Dream.from_filesystem "static" "bg.jpg") ; cors_options ] From de12bee1b8f56f71234a9d70f86eb027e76289ce Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 17 Apr 2023 10:17:20 +0200 Subject: [PATCH 017/285] fix conflict --- query/parser.mly | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/query/parser.mly b/query/parser.mly index c59275fd97..d576b8576f 100644 --- a/query/parser.mly +++ b/query/parser.mly @@ -13,6 +13,9 @@ %% +separated_twolong_list(sep, elt): + | e1=elt sep e2=elt sep li=separated_list(sep, elt) { e1 :: e2 :: li } + main: | t=typ EOF { t } | EOF { Any } @@ -20,7 +23,7 @@ main: typ: | a=typ1 ARROW b=typ { Arrow (a, b) } - | a=typ1 ARROW EOF { Arrow (a, Any) } + | a=typ1 ARROW { Arrow (a, Any) } | ARROW b=typ { Arrow (Any, b) } | ARROW EOF { Arrow (Any, Any) } | t=typ1 { t } @@ -47,4 +50,4 @@ typ0: | PARENS_OPEN t=typ EOF { t } ; -typ_list: ts=separated_list(COMMA, typ) { ts } ; +typ_list: ts=separated_twolong_list(COMMA, typ) { ts } ; From 859380b10911352eaa4595f9ed3aa5c17ccbe31d Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 17 Apr 2023 10:40:41 +0200 Subject: [PATCH 018/285] Some mlis --- index/cache.mli | 13 ++++ index/files.mli | 5 ++ index/load_doc.mli | 155 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 index/cache.mli create mode 100644 index/files.mli create mode 100644 index/load_doc.mli diff --git a/index/cache.mli b/index/cache.mli new file mode 100644 index 0000000000..a8186687de --- /dev/null +++ b/index/cache.mli @@ -0,0 +1,13 @@ +module type S = sig + type t + + val copy : t -> t +end + +module Make : functor (Element : S) -> sig + module H : Hashtbl.S with type key = Element.t + + val cache : Element.t H.t + val clear : unit -> unit + val memo : H.key -> Element.t +end diff --git a/index/files.mli b/index/files.mli new file mode 100644 index 0000000000..c29ec535a6 --- /dev/null +++ b/index/files.mli @@ -0,0 +1,5 @@ +val packages : string -> string array +val versions : string -> string -> string list +val untar : string -> unit +val contains : string -> string -> bool +val list : string -> string list diff --git a/index/load_doc.mli b/index/load_doc.mli new file mode 100644 index 0000000000..e33fcae500 --- /dev/null +++ b/index/load_doc.mli @@ -0,0 +1,155 @@ +module Types = Db.Types +module ModuleName = Odoc_model.Names.ModuleName + +val copy : string -> string +val deep_copy : 't -> 't + +module Cache_doc : sig + module H : Hashtbl.S with type key = Html_types.li_content_fun Tyxml_html.elt + + val cache : Html_types.li_content_fun Tyxml_html.elt H.t + val clear : unit -> unit + val memo : H.key -> Html_types.li_content_fun Tyxml_html.elt +end + +module Cache_name : sig + module H : sig + type key = string + type !'a t + + val create : int -> 'a t + val clear : 'a t -> unit + val reset : 'a t -> unit + val copy : 'a t -> 'a t + val add : 'a t -> key -> 'a -> unit + val remove : 'a t -> key -> unit + val find : 'a t -> key -> 'a + val find_opt : 'a t -> key -> 'a option + val find_all : 'a t -> key -> 'a list + val replace : 'a t -> key -> 'a -> unit + val mem : 'a t -> key -> bool + val iter : (key -> 'a -> unit) -> 'a t -> unit + val filter_map_inplace : (key -> 'a -> 'a option) -> 'a t -> unit + val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b + val length : 'a t -> int + val stats : 'a t -> Hashtbl.statistics + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_keys : 'a t -> key Seq.t + val to_seq_values : 'a t -> 'a Seq.t + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + val of_seq : (key * 'a) Seq.t -> 'a t + end + + val cache : string H.t + val clear : unit -> unit + val memo : H.key -> string +end + +module Cache : sig + module H : sig + type key = string + type !'a t + + val create : int -> 'a t + val clear : 'a t -> unit + val reset : 'a t -> unit + val copy : 'a t -> 'a t + val add : 'a t -> key -> 'a -> unit + val remove : 'a t -> key -> unit + val find : 'a t -> key -> 'a + val find_opt : 'a t -> key -> 'a option + val find_all : 'a t -> key -> 'a list + val replace : 'a t -> key -> 'a -> unit + val mem : 'a t -> key -> bool + val iter : (key -> 'a -> unit) -> 'a t -> unit + val filter_map_inplace : (key -> 'a -> 'a option) -> 'a t -> unit + val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b + val length : 'a t -> int + val stats : 'a t -> Hashtbl.statistics + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_keys : 'a t -> key Seq.t + val to_seq_values : 'a t -> 'a Seq.t + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + val of_seq : (key * 'a) Seq.t -> 'a t + end + + val cache : string H.t + val clear : unit -> unit + val memo : H.key -> string +end + +val clear : unit -> unit +val type_size : Odoc_model.Lang.TypeExpr.t -> int +val rev_concat : 'a list list -> 'a list +val tails : 'a list -> 'a list list +val fullname : 'a -> 'b +val all_type_names : 'a -> string list list + +val paths : + prefix:string list + -> sgn:Types.sgn + -> Odoc_model.Lang.TypeExpr.t + -> string list list + +val type_paths : + prefix:string list + -> sgn:Types.sgn + -> Odoc_model.Lang.TypeExpr.t + -> string list list + +val save_item : + pkg:string * string + -> path_list:char list + -> path:'a list + -> Odoc_model.Names.ValueName.t + -> Odoc_model.Lang.TypeExpr.t + -> 'b + -> unit + +val item : + pkg:string * string + -> path_list:char list + -> path:string list + -> Odoc_model.Lang.Signature.item + -> unit + +val items : + pkg:string * string + -> path_list:char list + -> path:string list + -> Odoc_model.Lang.Signature.item list + -> unit + +val module_items : + pkg:string * string + -> path_list:char list + -> path:string list + -> Odoc_model.Lang.Module.t + -> unit + +val module_type_expr : + pkg:string * string + -> path_list:char list + -> path:string list + -> Odoc_model.Lang.ModuleType.expr + -> unit + +val simple_expansion : + pkg:string * string + -> path_list:char list + -> path:string list + -> Odoc_model.Lang.ModuleType.simple_expansion + -> unit + +val module_items_ty : + pkg:string * string + -> path_list:char list + -> path:string list + -> Odoc_model.Lang.ModuleType.simple_expansion + -> unit + +module Resolver = Odoc_odoc.Resolver + +val run : odoc_directory:string -> string * string -> unit From da354344b2974947d1b143d87eec3db32a500004 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 17 Apr 2023 10:41:16 +0200 Subject: [PATCH 019/285] format version update --- .ocamlformat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ocamlformat b/.ocamlformat index 49b1202627..17e03264a5 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version = 0.24.1 +version = 0.25.1 let-binding-spacing = compact sequence-style = separator doc-comments = after-when-possible From 2536f313287587b9ff81a0ac2968dfef2a233956 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 17 Apr 2023 17:29:00 +0200 Subject: [PATCH 020/285] functor :) --- db/db.ml | 264 ++++++++++++----------- db/db.mli | 19 ++ db/storage.ml | 97 ++++++--- db/storage.mli | 18 ++ index/index.ml | 7 +- index/load_doc.ml | 511 +++++++++++++++++++++++---------------------- index/load_doc.mli | 155 +------------- www/www.ml | 6 +- 8 files changed, 511 insertions(+), 566 deletions(-) create mode 100644 db/db.mli create mode 100644 db/storage.mli diff --git a/db/db.ml b/db/db.ml index edc4593d2c..8284a6eeda 100644 --- a/db/db.ml +++ b/db/db.ml @@ -1,127 +1,145 @@ module Types = Types -module Storage = Storage +module Storage_toplevel = Storage include Types -let load_counter = ref 0 let list_of_string s = List.init (String.length s) (String.get s) -let db = ref (T.empty ()) -let db_names = ref (Tchar.empty ()) - -module Hset2 = Hashtbl.Make (struct - type t = Elt_set.t * Elt_set.t - - let hash = Hashtbl.hash - let equal (a, b) (a', b') = a == a' && b == b' -end) - -module Hocc2 = Hashtbl.Make (struct - type t = Elt_set.t Occ.t * Elt_set.t Occ.t - - let hash = Hashtbl.hash - let equal (a, b) (a', b') = a == a' && b == b' -end) - -let elt_set_union ~hs a b = - try Hset2.find hs (a, b) - with Not_found -> - let r = Elt_set.union a b in - Hset2.add hs (a, b) r ; - Hset2.add hs (b, a) r ; - r - -let occ_merge ~hs a b = - if a == b - then a - else - Occ.merge - (fun _ ox oy -> - match ox, oy with - | Some x, Some y -> Some (elt_set_union ~hs x y) - | opt, None | None, opt -> opt) - a b - -let occ_merge ~ho ~hs a b = - try Hocc2.find ho (a, b) - with Not_found -> - let r = occ_merge ~hs a b in - Hocc2.add ho (a, b) r ; - Hocc2.add ho (b, a) r ; - r - -let export h = - load_counter := 0 ; - let t = { Storage.db = !db; db_names = !db_names } in - let ho = Hocc2.create 16 in - let hs = Hset2.create 16 in - let (_ : Elt_set.t Occ.t) = T.summarize (occ_merge ~ho ~hs) Occ.empty !db in - let (_ : Elt_set.t) = - Tchar.summarize (elt_set_union ~hs) Elt_set.empty !db_names - in - Storage.save ~db:h t ; - db := T.empty () ; - db_names := Tchar.empty () - -module Hset = Hashtbl.Make (struct - type t = Elt_set.t option - - let hash = Hashtbl.hash - let equal x y = Option.equal (fun x y -> x == y) x y -end) - -module Hocc = Hashtbl.Make (struct - type t = Elt_set.t Occ.t option - - let hash = Hashtbl.hash - let equal x y = Option.equal (fun x y -> x == y) x y -end) - -let set_add elt = function - | None -> Elt_set.singleton elt - | Some s -> Elt_set.add elt s - -let set_add ~hs elt opt = - try Hset.find hs opt - with Not_found -> - let r = set_add elt opt in - Hset.add hs opt r ; - r - -let candidates_add ~hs elt ~count = function - | None -> Occ.singleton count (set_add ~hs elt None) - | Some m -> - let s = Occ.find_opt count m in - let s = set_add ~hs elt s in - Occ.add count s m - -let candidates_add ~ho ~hs elt ~count opt = - try Hocc.find ho opt - with Not_found -> - let r = candidates_add ~hs ~count elt opt in - Hocc.add ho opt r ; - r - -let store ~ho ~hs name typ ~count = - let rec go db = function - | [] -> db - | _ :: next as name -> - incr load_counter ; - let db = T.add name (candidates_add ~ho ~hs typ ~count) db in - go db next - in - db := go !db name - -let store_all typ paths = - let ho = Hocc.create 16 in - let hs = Hset.create 16 in - List.iter (fun (path, count) -> store ~ho ~hs ~count path typ) (regroup paths) - -let store_name name typ = - let hs = Hset.create 16 in - let rec go db = function - | [] -> db - | _ :: next as name -> - incr load_counter ; - let db = Tchar.add name (set_add ~hs typ) db in - go db next - in - db_names := go !db_names name + +module type S = sig + type writer + + val export : writer -> unit + val store_all : Elt_set.elt -> String_list_map.key list -> unit + val store_name : Tchar.M.key list -> Elt_set.elt -> unit + val load_counter : int ref +end + +module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct + type writer = Storage.writer + + let load_counter = ref 0 + let db = ref (T.empty ()) + let db_names = ref (Tchar.empty ()) + + module Hset2 = Hashtbl.Make (struct + type t = Elt_set.t * Elt_set.t + + let hash = Hashtbl.hash + let equal (a, b) (a', b') = a == a' && b == b' + end) + + module Hocc2 = Hashtbl.Make (struct + type t = Elt_set.t Occ.t * Elt_set.t Occ.t + + let hash = Hashtbl.hash + let equal (a, b) (a', b') = a == a' && b == b' + end) + + let elt_set_union ~hs a b = + try Hset2.find hs (a, b) + with Not_found -> + let r = Elt_set.union a b in + Hset2.add hs (a, b) r ; + Hset2.add hs (b, a) r ; + r + + let occ_merge ~hs a b = + if a == b + then a + else + Occ.merge + (fun _ ox oy -> + match ox, oy with + | Some x, Some y -> Some (elt_set_union ~hs x y) + | opt, None | None, opt -> opt) + a b + + let occ_merge ~ho ~hs a b = + try Hocc2.find ho (a, b) + with Not_found -> + let r = occ_merge ~hs a b in + Hocc2.add ho (a, b) r ; + Hocc2.add ho (b, a) r ; + r + + let export h = + load_counter := 0 ; + let t = { Storage_toplevel.db = !db; db_names = !db_names } in + let ho = Hocc2.create 16 in + let hs = Hset2.create 16 in + let (_ : Elt_set.t Occ.t) = T.summarize (occ_merge ~ho ~hs) Occ.empty !db in + let (_ : Elt_set.t) = + Tchar.summarize (elt_set_union ~hs) Elt_set.empty !db_names + in + Storage.save ~db:h t ; + db := T.empty () ; + db_names := Tchar.empty () + + module Hset = Hashtbl.Make (struct + type t = Elt_set.t option + + let hash = Hashtbl.hash + let equal x y = Option.equal (fun x y -> x == y) x y + end) + + module Hocc = Hashtbl.Make (struct + type t = Elt_set.t Occ.t option + + let hash = Hashtbl.hash + let equal x y = Option.equal (fun x y -> x == y) x y + end) + + let set_add elt = function + | None -> Elt_set.singleton elt + | Some s -> Elt_set.add elt s + + let set_add ~hs elt opt = + try Hset.find hs opt + with Not_found -> + let r = set_add elt opt in + Hset.add hs opt r ; + r + + let candidates_add ~hs elt ~count = function + | None -> Occ.singleton count (set_add ~hs elt None) + | Some m -> + let s = Occ.find_opt count m in + let s = set_add ~hs elt s in + Occ.add count s m + + let candidates_add ~ho ~hs elt ~count opt = + try Hocc.find ho opt + with Not_found -> + let r = candidates_add ~hs ~count elt opt in + Hocc.add ho opt r ; + r + + let store ~ho ~hs name typ ~count = + let rec go db = function + | [] -> db + | _ :: next as name -> + incr load_counter ; + let db = T.add name (candidates_add ~ho ~hs typ ~count) db in + go db next + in + db := go !db name + + let store_all typ paths = + let ho = Hocc.create 16 in + let hs = Hset.create 16 in + List.iter + (fun (path, count) -> store ~ho ~hs ~count path typ) + (regroup paths) + + let store_name name typ = + let hs = Hset.create 16 in + let rec go db = function + | [] -> db + | _ :: next as name -> + incr load_counter ; + let db = Tchar.add name (set_add ~hs typ) db in + go db next + in + db_names := go !db_names name +end + +module Storage = Storage diff --git a/db/db.mli b/db/db.mli new file mode 100644 index 0000000000..c693da2dcf --- /dev/null +++ b/db/db.mli @@ -0,0 +1,19 @@ +module Elt = Types.Elt +module Types = Types +module Storage = Storage +module Tchar = Types.Tchar +module Elt_set = Types.Elt_set +module String_list_map = Types.String_list_map + +val list_of_string : string -> char list + +module type S = sig + type writer + + val export : writer -> unit + val store_all : Elt_set.elt -> String_list_map.key list -> unit + val store_name : Tchar.M.key list -> Elt_set.elt -> unit + val load_counter : int ref +end + +module Make (Storage : Storage.S) : S with type writer = Storage.writer diff --git a/db/storage.ml b/db/storage.ml index a1e4c33915..4ea9d43087 100644 --- a/db/storage.ml +++ b/db/storage.ml @@ -1,43 +1,74 @@ -let base_addr = 0x100000000000n - -type writer = - { mutable write_shard : int - ; ancient : Ancient.md - } - -let open_out filename = - let handle = Unix.openfile filename Unix.[ O_RDWR; O_TRUNC; O_CREAT ] 0o640 in - let ancient = Ancient.attach handle base_addr in - { write_shard = 0; ancient } - type t = { db : Types.db ; db_names : Types.Elt_set.t Types.Tchar.t } -let save ~db (t : t) = - ignore (Ancient.share db.ancient db.write_shard t) ; - db.write_shard <- db.write_shard + 1 +module type S = sig + type writer + + val open_out : string -> writer + val save : db:writer -> t -> unit + val close_out : writer -> unit + val load : string -> t list +end + +module Ancient = struct + let base_addr = 0x100000000000n + + type writer = + { mutable write_shard : int + ; ancient : Ancient.md + } + + let open_out filename = + let handle = + Unix.openfile filename Unix.[ O_RDWR; O_TRUNC; O_CREAT ] 0o640 + in + let ancient = Ancient.attach handle base_addr in + { write_shard = 0; ancient } + + let save ~db (t : t) = + ignore (Ancient.share db.ancient db.write_shard t) ; + db.write_shard <- db.write_shard + 1 + + let close_out db = Ancient.detach db.ancient + + type reader = { shards : t array } + + let load_shard md shard = + match Ancient.get md shard with + | t -> Some (Ancient.follow t) + | exception _ -> None + + let load_shards md = + let rec go i = + match load_shard md i with + | None -> [] + | Some t -> t :: go (i + 1) + in + Array.of_list (go 0) -let close_out db = Ancient.detach db.ancient + let db_open_in db : reader = + let filename = db in + let handle = Unix.openfile filename Unix.[ O_RDWR ] 0o640 in + let md = Ancient.attach handle base_addr in + { shards = load_shards md } -type reader = { shards : t array } + let load db_filename = + let h = db_open_in db_filename in + Array.to_list h.shards +end -let load_shard md shard = - match Ancient.get md shard with - | t -> Some (Ancient.follow t) - | exception _ -> None +module Marshal = struct + type writer = out_channel -let load_shards md = - let rec go i = - match load_shard md i with - | None -> [] - | Some t -> t :: go (i + 1) - in - Array.of_list (go 0) + let open_out = open_out + let close_out = close_out + let save ~db t = Marshal.to_channel db t [] -let db_open_in db : reader = - let filename = db in - let handle = Unix.openfile filename Unix.[ O_RDWR ] 0o640 in - let md = Ancient.attach handle base_addr in - { shards = load_shards md } + let load name = + let file = open_in name in + let t = Marshal.from_channel file in + close_in file ; + [ t ] +end diff --git a/db/storage.mli b/db/storage.mli new file mode 100644 index 0000000000..08d5f81642 --- /dev/null +++ b/db/storage.mli @@ -0,0 +1,18 @@ +type t = +{ db : Types.db +; db_names : Types.Elt_set.t Types.Tchar.t +} + + +module type S = sig + type writer + + val open_out : string -> writer + val save : db:writer -> t -> unit + val close_out : writer -> unit + val load : string -> t list +end + +module Ancient : S + +module Marshal : S \ No newline at end of file diff --git a/index/index.ml b/index/index.ml index 188a68631c..32cb8b3b51 100644 --- a/index/index.ml +++ b/index/index.ml @@ -11,10 +11,13 @@ let of_filename f = let filenames () = List.map of_filename (Files.list odoc_directory) +module Load_doc = Load_doc.Make (Storage.Ancient) +module Db = Load_doc.Db + let () = let files = filenames () in let total = List.length files in - let h = Storage.open_out db_filename in + let h = Storage.Ancient.open_out db_filename in let flush () = Load_doc.clear () ; Db.export h @@ -30,4 +33,4 @@ let () = Load_doc.run ~odoc_directory file) files ; flush () ; - Storage.close_out h + Storage.Ancient.close_out h diff --git a/index/load_doc.ml b/index/load_doc.ml index e0c5c3f1c6..7b46fdae9a 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -1,252 +1,261 @@ -module Types = Db.Types -open Odoc_model -module ModuleName = Odoc_model.Names.ModuleName - -let copy str = String.init (String.length str) (String.get str) - -let deep_copy (type t) (x : t) : t = - let buf = Marshal.(to_bytes x [ No_sharing; Closures ]) in - Marshal.from_bytes buf 0 - -module Cache_doc = Cache.Make (struct - type t = Html_types.li_content_fun Tyxml.Html.elt - - let copy x = deep_copy x -end) - -module Cache_name = Cache.Make (struct - type t = string - - let copy = copy -end) - -module Cache = Cache.Make (struct - type t = string - - let copy = copy -end) - -let clear () = - Cache.clear () ; - Cache_name.clear () ; - Cache_doc.clear () - -let rec type_size = function - | Odoc_model.Lang.TypeExpr.Var _ -> 1 - | Any -> 1 - | Arrow (lbl, a, b) -> - (match lbl with - | None -> 0 - | Some _ -> 1) - + type_size a + type_size b - | Constr (_, args) -> List.fold_left (fun acc t -> acc + type_size t) 1 args - | Tuple args -> List.fold_left (fun acc t -> acc + type_size t) 1 args - | _ -> 100 - -let rev_concat lst = - List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst - -let rec tails = function - | [] -> [] - | _ :: xs as lst -> lst :: tails xs - -let fullname t = - Pretty.fmt_to_string (fun h -> Pretty.show_type_name_verbose h t) - -let all_type_names t = - let fullname = fullname t in - tails (String.split_on_char '.' fullname) - -let rec paths ~prefix ~sgn = function - | Odoc_model.Lang.TypeExpr.Var _ -> - let poly = Cache_name.memo "POLY" in - [ poly :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix ] - | Any -> - let poly = Cache_name.memo "POLY" in - [ poly :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix ] - | Arrow (_, a, b) -> - let prefix_left = Cache_name.memo "->0" :: prefix in - let prefix_right = Cache_name.memo "->1" :: prefix in - List.rev_append - (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) - (paths ~prefix:prefix_right ~sgn b) - | Constr (name, args) -> - let name = fullname name in - let prefix = - Cache_name.memo name - :: Cache_name.memo (Types.string_of_sgn sgn) - :: prefix - in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = Cache_name.memo (string_of_int i) :: prefix in - paths ~prefix ~sgn arg) - args - end - | Tuple args -> - rev_concat - @@ List.mapi (fun i arg -> - let prefix = Cache_name.memo (string_of_int i ^ "*") :: prefix in - paths ~prefix ~sgn arg) - @@ args - | _ -> [] - -let rec type_paths ~prefix ~sgn = function - | Odoc_model.Lang.TypeExpr.Var _ -> - [ "POLY" :: Types.string_of_sgn sgn :: prefix ] - | Any -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] - | Arrow (_lbl, a, b) -> +module Db_common =Db + +module Make (Storage : Db.Storage.S) = struct + module Types = Db.Types + module Db = Db.Make (Storage) + open Odoc_model + module ModuleName = Odoc_model.Names.ModuleName + + let copy str = String.init (String.length str) (String.get str) + + let deep_copy (type t) (x : t) : t = + let buf = Marshal.(to_bytes x [ No_sharing; Closures ]) in + Marshal.from_bytes buf 0 + + module Cache_doc = Cache.Make (struct + type t = Html_types.li_content_fun Tyxml.Html.elt + + let copy x = deep_copy x + end) + + module Cache_name = Cache.Make (struct + type t = string + + let copy = copy + end) + + module Cache = Cache.Make (struct + type t = string + + let copy = copy + end) + + let clear () = + Cache.clear () ; + Cache_name.clear () ; + Cache_doc.clear () + + let rec type_size = function + | Odoc_model.Lang.TypeExpr.Var _ -> 1 + | Any -> 1 + | Arrow (lbl, a, b) -> + (match lbl with + | None -> 0 + | Some _ -> 1) + + type_size a + type_size b + | Constr (_, args) -> List.fold_left (fun acc t -> acc + type_size t) 1 args + | Tuple args -> List.fold_left (fun acc t -> acc + type_size t) 1 args + | _ -> 100 + + let rev_concat lst = + List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst + + let rec tails = function + | [] -> [] + | _ :: xs as lst -> lst :: tails xs + + let fullname t = + Pretty.fmt_to_string (fun h -> Pretty.show_type_name_verbose h t) + + let all_type_names t = + let fullname = fullname t in + tails (String.split_on_char '.' fullname) + + let rec paths ~prefix ~sgn = function + | Odoc_model.Lang.TypeExpr.Var _ -> + let poly = Cache_name.memo "POLY" in + [ poly :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix ] + | Any -> + let poly = Cache_name.memo "POLY" in + [ poly :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix ] + | Arrow (_, a, b) -> + let prefix_left = Cache_name.memo "->0" :: prefix in + let prefix_right = Cache_name.memo "->1" :: prefix in + List.rev_append + (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) + (paths ~prefix:prefix_right ~sgn b) + | Constr (name, args) -> + let name = fullname name in + let prefix = + Cache_name.memo name + :: Cache_name.memo (Types.string_of_sgn sgn) + :: prefix + in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = Cache_name.memo (string_of_int i) :: prefix in + paths ~prefix ~sgn arg) + args + end + | Tuple args -> + rev_concat + @@ List.mapi (fun i arg -> + let prefix = Cache_name.memo (string_of_int i ^ "*") :: prefix in + paths ~prefix ~sgn arg) + @@ args + | _ -> [] + + let rec type_paths ~prefix ~sgn = function + | Odoc_model.Lang.TypeExpr.Var _ -> + [ "POLY" :: Types.string_of_sgn sgn :: prefix ] + | Any -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] + | Arrow (_lbl, a, b) -> + List.rev_append + (type_paths ~prefix ~sgn:(Types.sgn_not sgn) a) + (type_paths ~prefix ~sgn b) + | Constr (name, args) -> + rev_concat + @@ List.map (fun name -> + let name = String.concat "." name in + let prefix = name :: Types.string_of_sgn sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + type_paths ~prefix ~sgn arg) + args + end) + @@ all_type_names name + | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args + | _ -> [] + + let save_item ~pkg ~path_list ~path name type_ doc = + let b = Buffer.create 16 in + let to_b = Format.formatter_of_buffer b in + Format.fprintf to_b "%a%!" + (Pretty.show_type + ~path:(Pretty.fmt_to_string (fun h -> Pretty.pp_path h path)) + ~parens:false) + type_ ; + let str_type = Buffer.contents b in + Buffer.reset b ; + Format.fprintf to_b "%a%s%!" Pretty.pp_path path + (Odoc_model.Names.ValueName.to_string name) ; + let full_name = Buffer.contents b in + let doc = Option.map Cache_doc.memo (Pretty.string_of_docs doc) in + let cost = + String.length full_name + String.length str_type + + (5 * List.length path) + + type_size type_ + + (match doc with + | None -> 1000 + | _ -> 0) + + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 + in + let paths = paths ~prefix:[] ~sgn:Pos type_ in + let str_type = + { Db_common.Elt.name = full_name + ; cost + ; type_paths = paths + ; str_type = Cache.memo str_type + ; doc + ; pkg + } + in + let my_full_name = List.rev_append - (type_paths ~prefix ~sgn:(Types.sgn_not sgn) a) - (type_paths ~prefix ~sgn b) - | Constr (name, args) -> - rev_concat - @@ List.map (fun name -> - let name = String.concat "." name in - let prefix = name :: Types.string_of_sgn sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - type_paths ~prefix ~sgn arg) - args - end) - @@ all_type_names name - | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args - | _ -> [] - -let save_item ~pkg ~path_list ~path name type_ doc = - let b = Buffer.create 16 in - let to_b = Format.formatter_of_buffer b in - Format.fprintf to_b "%a%!" - (Pretty.show_type - ~path:(Pretty.fmt_to_string (fun h -> Pretty.pp_path h path)) - ~parens:false) - type_ ; - let str_type = Buffer.contents b in - Buffer.reset b ; - Format.fprintf to_b "%a%s%!" Pretty.pp_path path - (Odoc_model.Names.ValueName.to_string name) ; - let full_name = Buffer.contents b in - let doc = Option.map Cache_doc.memo (Pretty.string_of_docs doc) in - let cost = - String.length full_name + String.length str_type - + (5 * List.length path) - + type_size type_ - + (match doc with - | None -> 1000 - | _ -> 0) - + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 - in - let paths = paths ~prefix:[] ~sgn:Pos type_ in - let str_type = - { Db.Elt.name = full_name - ; cost - ; type_paths = paths - ; str_type = Cache.memo str_type - ; doc - ; pkg - } - in - let my_full_name = - List.rev_append - (Db.list_of_string (Odoc_model.Names.ValueName.to_string name)) - ('.' :: path_list) - in - let my_full_name = List.map Char.lowercase_ascii my_full_name in - Db.store_name my_full_name str_type ; - let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in - Db.store_all str_type (List.map (List.map Cache_name.memo) type_paths) - -let rec item ~pkg ~path_list ~path = - let open Odoc_model.Lang in - function - | Signature.Value { id = `Value (_, name); _ } - when Odoc_model.Names.ValueName.is_internal name -> - () - | Signature.Value { id = `Value (_, name); type_; doc; _ } -> - save_item ~pkg ~path_list ~path name type_ doc - | Module (_, mdl) -> - let name = Paths.Identifier.name mdl.id in - if name = "Stdlib" then () else module_items ~pkg ~path_list ~path mdl - | Type (_, _) -> () - | Include icl -> items ~pkg ~path_list ~path icl.expansion.content.items - | TypeSubstitution _ -> () (* type t = Foo.t = actual_definition *) - | TypExt _ -> () (* type t = .. *) - | Exception _ -> () - | Class _ -> () - | ClassType _ -> () - | Comment _ -> () - | Open _ -> () - | ModuleType _ -> () - | ModuleSubstitution _ -> () - | ModuleTypeSubstitution _ -> () - -and items ~pkg ~path_list ~path item_list = - List.iter (item ~pkg ~path_list ~path) item_list - -and module_items ~pkg ~path_list ~path mdl = - let open Odoc_model.Lang.Module in - let name = Paths.Identifier.name mdl.id in - let path = name :: path in - let path_list = List.rev_append (Db.list_of_string name) ('.' :: path_list) in - match mdl.type_ with - | ModuleType e -> module_type_expr ~pkg ~path_list ~path e - | Alias (_, Some mdl) -> module_items_ty ~pkg ~path_list ~path mdl - | Alias (_, None) -> () - -and module_type_expr ~pkg ~path_list ~path = function - | Signature sg -> items ~pkg ~path_list ~path sg.items - | Functor (_, sg) -> module_type_expr ~pkg ~path_list ~path sg - | With { w_expansion = Some sg; _ } - | TypeOf { t_expansion = Some sg; _ } - | Path { p_expansion = Some sg; _ } -> - simple_expansion ~pkg ~path_list ~path sg - | With _ -> () - | TypeOf _ -> () - | Path _ -> () - | _ -> . - -and simple_expansion ~pkg ~path_list ~path = function - | Signature sg -> items ~pkg ~path_list ~path sg.items - | Functor (_, sg) -> simple_expansion ~pkg ~path_list ~path sg - -and module_items_ty ~pkg ~path_list ~path = function - | Functor (_, mdl) -> module_items_ty ~pkg ~path_list ~path mdl - | Signature sg -> items ~pkg ~path_list ~path sg.items - -module Resolver = Odoc_odoc.Resolver - -let run ~odoc_directory (root_name, filename) = - let ((package, version) as pkg) = - match String.split_on_char '/' filename with - | "." :: package :: version :: _ -> package, version - | _ -> - invalid_arg (Printf.sprintf "not a valid package/version? %S" filename) - in - Format.printf "%s %s => %s@." package version root_name ; - let filename = Filename.concat odoc_directory filename in - let fpath = Result.get_ok @@ Fpath.of_string filename in - let t = - match Odoc_odoc.Odoc_file.load fpath with - | Ok { Odoc_odoc.Odoc_file.content = Unit_content t; _ } -> t - | Ok { Odoc_odoc.Odoc_file.content = Page_content _; _ } -> - failwith "page content" - | Error (`Msg m) -> failwith ("ERROR:" ^ m) - in - let open Odoc_model.Lang.Compilation_unit in - match t.content with - | Pack _ -> () - | Module t -> - let path = [ root_name ] in - let path_list = List.rev (Db.list_of_string root_name) in - items ~pkg ~path_list ~path t.Odoc_model.Lang.Signature.items + (Db_common.list_of_string (Odoc_model.Names.ValueName.to_string name)) + ('.' :: path_list) + in + let my_full_name = List.map Char.lowercase_ascii my_full_name in + Db.store_name my_full_name str_type ; + let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in + Db.store_all str_type + (List.map (List.map Cache_name.memo) type_paths) + + let rec item ~pkg ~path_list ~path = + let open Odoc_model.Lang in + function + | Signature.Value { id = `Value (_, name); _ } + when Odoc_model.Names.ValueName.is_internal name -> + () + | Signature.Value { id = `Value (_, name); type_; doc; _ } -> + save_item ~pkg ~path_list ~path name type_ doc + | Module (_, mdl) -> + let name = Paths.Identifier.name mdl.id in + if name = "Stdlib" then () else module_items ~pkg ~path_list ~path mdl + | Type (_, _) -> () + | Include icl -> items ~pkg ~path_list ~path icl.expansion.content.items + | TypeSubstitution _ -> () (* type t = Foo.t = actual_definition *) + | TypExt _ -> () (* type t = .. *) + | Exception _ -> () + | Class _ -> () + | ClassType _ -> () + | Comment _ -> () + | Open _ -> () + | ModuleType _ -> () + | ModuleSubstitution _ -> () + | ModuleTypeSubstitution _ -> () + + and items ~pkg ~path_list ~path item_list = + List.iter (item ~pkg ~path_list ~path) item_list + + and module_items ~pkg ~path_list ~path mdl = + let open Odoc_model.Lang.Module in + let name = Paths.Identifier.name mdl.id in + let path = name :: path in + let path_list = + List.rev_append (Db_common.list_of_string name) ('.' :: path_list) + in + match mdl.type_ with + | ModuleType e -> module_type_expr ~pkg ~path_list ~path e + | Alias (_, Some mdl) -> module_items_ty ~pkg ~path_list ~path mdl + | Alias (_, None) -> () + + and module_type_expr ~pkg ~path_list ~path = function + | Signature sg -> items ~pkg ~path_list ~path sg.items + | Functor (_, sg) -> module_type_expr ~pkg ~path_list ~path sg + | With { w_expansion = Some sg; _ } + | TypeOf { t_expansion = Some sg; _ } + | Path { p_expansion = Some sg; _ } -> + simple_expansion ~pkg ~path_list ~path sg + | With _ -> () + | TypeOf _ -> () + | Path _ -> () + | _ -> . + + and simple_expansion ~pkg ~path_list ~path = function + | Signature sg -> items ~pkg ~path_list ~path sg.items + | Functor (_, sg) -> simple_expansion ~pkg ~path_list ~path sg + + and module_items_ty ~pkg ~path_list ~path = function + | Functor (_, mdl) -> module_items_ty ~pkg ~path_list ~path mdl + | Signature sg -> items ~pkg ~path_list ~path sg.items + + module Resolver = Odoc_odoc.Resolver + + let run ~odoc_directory (root_name, filename) = + let ((package, version) as pkg) = + match String.split_on_char '/' filename with + | "." :: package :: version :: _ -> package, version + | _ -> + invalid_arg + (Printf.sprintf "not a valid package/version? %S" filename) + in + Format.printf "%s %s => %s@." package version root_name ; + let filename = Filename.concat odoc_directory filename in + let fpath = Result.get_ok @@ Fpath.of_string filename in + let t = + match Odoc_odoc.Odoc_file.load fpath with + | Ok { Odoc_odoc.Odoc_file.content = Unit_content t; _ } -> t + | Ok { Odoc_odoc.Odoc_file.content = Page_content _; _ } -> + failwith "page content" + | Error (`Msg m) -> failwith ("ERROR:" ^ m) + in + let open Odoc_model.Lang.Compilation_unit in + match t.content with + | Pack _ -> () + | Module t -> + let path = [ root_name ] in + let path_list = List.rev (Db_common.list_of_string root_name) in + items ~pkg ~path_list ~path t.Odoc_model.Lang.Signature.items +end diff --git a/index/load_doc.mli b/index/load_doc.mli index e33fcae500..dd66c0be8c 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -1,155 +1,6 @@ -module Types = Db.Types -module ModuleName = Odoc_model.Names.ModuleName +module Make (Storage : Db.Storage.S) : sig + module Db : Db.S with type writer = Storage.writer -val copy : string -> string -val deep_copy : 't -> 't - -module Cache_doc : sig - module H : Hashtbl.S with type key = Html_types.li_content_fun Tyxml_html.elt - - val cache : Html_types.li_content_fun Tyxml_html.elt H.t - val clear : unit -> unit - val memo : H.key -> Html_types.li_content_fun Tyxml_html.elt -end - -module Cache_name : sig - module H : sig - type key = string - type !'a t - - val create : int -> 'a t - val clear : 'a t -> unit - val reset : 'a t -> unit - val copy : 'a t -> 'a t - val add : 'a t -> key -> 'a -> unit - val remove : 'a t -> key -> unit - val find : 'a t -> key -> 'a - val find_opt : 'a t -> key -> 'a option - val find_all : 'a t -> key -> 'a list - val replace : 'a t -> key -> 'a -> unit - val mem : 'a t -> key -> bool - val iter : (key -> 'a -> unit) -> 'a t -> unit - val filter_map_inplace : (key -> 'a -> 'a option) -> 'a t -> unit - val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b - val length : 'a t -> int - val stats : 'a t -> Hashtbl.statistics - val to_seq : 'a t -> (key * 'a) Seq.t - val to_seq_keys : 'a t -> key Seq.t - val to_seq_values : 'a t -> 'a Seq.t - val add_seq : 'a t -> (key * 'a) Seq.t -> unit - val replace_seq : 'a t -> (key * 'a) Seq.t -> unit - val of_seq : (key * 'a) Seq.t -> 'a t - end - - val cache : string H.t - val clear : unit -> unit - val memo : H.key -> string -end - -module Cache : sig - module H : sig - type key = string - type !'a t - - val create : int -> 'a t - val clear : 'a t -> unit - val reset : 'a t -> unit - val copy : 'a t -> 'a t - val add : 'a t -> key -> 'a -> unit - val remove : 'a t -> key -> unit - val find : 'a t -> key -> 'a - val find_opt : 'a t -> key -> 'a option - val find_all : 'a t -> key -> 'a list - val replace : 'a t -> key -> 'a -> unit - val mem : 'a t -> key -> bool - val iter : (key -> 'a -> unit) -> 'a t -> unit - val filter_map_inplace : (key -> 'a -> 'a option) -> 'a t -> unit - val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b - val length : 'a t -> int - val stats : 'a t -> Hashtbl.statistics - val to_seq : 'a t -> (key * 'a) Seq.t - val to_seq_keys : 'a t -> key Seq.t - val to_seq_values : 'a t -> 'a Seq.t - val add_seq : 'a t -> (key * 'a) Seq.t -> unit - val replace_seq : 'a t -> (key * 'a) Seq.t -> unit - val of_seq : (key * 'a) Seq.t -> 'a t - end - - val cache : string H.t val clear : unit -> unit - val memo : H.key -> string + val run : odoc_directory:string -> string * string -> unit end - -val clear : unit -> unit -val type_size : Odoc_model.Lang.TypeExpr.t -> int -val rev_concat : 'a list list -> 'a list -val tails : 'a list -> 'a list list -val fullname : 'a -> 'b -val all_type_names : 'a -> string list list - -val paths : - prefix:string list - -> sgn:Types.sgn - -> Odoc_model.Lang.TypeExpr.t - -> string list list - -val type_paths : - prefix:string list - -> sgn:Types.sgn - -> Odoc_model.Lang.TypeExpr.t - -> string list list - -val save_item : - pkg:string * string - -> path_list:char list - -> path:'a list - -> Odoc_model.Names.ValueName.t - -> Odoc_model.Lang.TypeExpr.t - -> 'b - -> unit - -val item : - pkg:string * string - -> path_list:char list - -> path:string list - -> Odoc_model.Lang.Signature.item - -> unit - -val items : - pkg:string * string - -> path_list:char list - -> path:string list - -> Odoc_model.Lang.Signature.item list - -> unit - -val module_items : - pkg:string * string - -> path_list:char list - -> path:string list - -> Odoc_model.Lang.Module.t - -> unit - -val module_type_expr : - pkg:string * string - -> path_list:char list - -> path:string list - -> Odoc_model.Lang.ModuleType.expr - -> unit - -val simple_expansion : - pkg:string * string - -> path_list:char list - -> path:string list - -> Odoc_model.Lang.ModuleType.simple_expansion - -> unit - -val module_items_ty : - pkg:string * string - -> path_list:char list - -> path:string list - -> Odoc_model.Lang.ModuleType.simple_expansion - -> unit - -module Resolver = Odoc_odoc.Resolver - -val run : odoc_directory:string -> string * string -> unit diff --git a/www/www.ml b/www/www.ml index e934b521d9..fc54c0f971 100644 --- a/www/www.ml +++ b/www/www.ml @@ -8,10 +8,6 @@ type params = ; limit : int } -let load_shards db_filename = - let h = Storage.db_open_in db_filename in - Array.to_list h.Storage.shards - let search ~shards query_name query_typ = let open Lwt.Syntax in let* results_name = Query.find_names ~shards query_name in @@ -116,7 +112,7 @@ let cors_options = response) let main db_filename cache_max_age = - let shards = load_shards db_filename in + let shards = Storage.Ancient.load db_filename in Dream.run ~interface:"127.0.0.1" ~port:1234 @@ Dream.logger @@ cache_header cache_max_age @@ cors_header @@ Dream.router From 0c8619005affd4c0c205dcd1e8d6e5aae9a16d2c Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 18 Apr 2023 15:34:53 +0200 Subject: [PATCH 021/285] Reorganize source to remove ancient dep from db. --- db/dune | 3 - db/storage.ml | 74 ------------------------ {db => lib/db}/db.ml | 0 {db => lib/db}/db.mli | 0 lib/db/dune | 3 + lib/db/storage.ml | 13 +++++ {db => lib/db}/storage.mli | 11 +--- {db => lib/db}/trie.ml | 0 {db => lib/db}/types.ml | 0 {index => lib/index}/cache.ml | 0 {index => lib/index}/cache.mli | 0 {index => lib/index}/dune | 1 + {index => lib/index}/files.ml | 0 {index => lib/index}/files.mli | 0 {index => lib/index}/index.ml | 6 +- {index => lib/index}/load_doc.ml | 5 +- {index => lib/index}/load_doc.mli | 0 {index => lib/index}/pretty.ml | 0 {query => lib/query}/dune | 0 {query => lib/query}/lexer.mll | 0 {query => lib/query}/parser.mly | 0 {query => lib/query}/query.ml | 0 {query => lib/query}/query_ast.ml | 0 {query => lib/query}/query_parser.ml | 0 {query => lib/query}/sort.ml | 0 {query => lib/query}/succ.ml | 0 lib/storage_ancient/dune | 3 + lib/storage_ancient/storage_ancient.ml | 44 ++++++++++++++ lib/storage_ancient/storage_ancient.mli | 1 + lib/storage_marshal/dune | 3 + lib/storage_marshal/storage_marshal.ml | 11 ++++ lib/storage_marshal/storage_marshal.mli | 1 + odoc_output/mylib/1.0/main.odocl | Bin 0 -> 71757 bytes utils/dune | 2 + utils/utils.ml | 0 www/dune | 2 +- www/www.ml | 2 +- 37 files changed, 92 insertions(+), 93 deletions(-) delete mode 100644 db/dune delete mode 100644 db/storage.ml rename {db => lib/db}/db.ml (100%) rename {db => lib/db}/db.mli (100%) create mode 100644 lib/db/dune create mode 100644 lib/db/storage.ml rename {db => lib/db}/storage.mli (64%) rename {db => lib/db}/trie.ml (100%) rename {db => lib/db}/types.ml (100%) rename {index => lib/index}/cache.ml (100%) rename {index => lib/index}/cache.mli (100%) rename {index => lib/index}/dune (87%) rename {index => lib/index}/files.ml (100%) rename {index => lib/index}/files.mli (100%) rename {index => lib/index}/index.ml (85%) rename {index => lib/index}/load_doc.ml (98%) rename {index => lib/index}/load_doc.mli (100%) rename {index => lib/index}/pretty.ml (100%) rename {query => lib/query}/dune (100%) rename {query => lib/query}/lexer.mll (100%) rename {query => lib/query}/parser.mly (100%) rename {query => lib/query}/query.ml (100%) rename {query => lib/query}/query_ast.ml (100%) rename {query => lib/query}/query_parser.ml (100%) rename {query => lib/query}/sort.ml (100%) rename {query => lib/query}/succ.ml (100%) create mode 100644 lib/storage_ancient/dune create mode 100644 lib/storage_ancient/storage_ancient.ml create mode 100644 lib/storage_ancient/storage_ancient.mli create mode 100644 lib/storage_marshal/dune create mode 100644 lib/storage_marshal/storage_marshal.ml create mode 100644 lib/storage_marshal/storage_marshal.mli create mode 100644 odoc_output/mylib/1.0/main.odocl create mode 100644 utils/dune create mode 100644 utils/utils.ml diff --git a/db/dune b/db/dune deleted file mode 100644 index aade4fbf5e..0000000000 --- a/db/dune +++ /dev/null @@ -1,3 +0,0 @@ -(library - (name db) - (libraries unix ancient tyxml)) diff --git a/db/storage.ml b/db/storage.ml deleted file mode 100644 index 4ea9d43087..0000000000 --- a/db/storage.ml +++ /dev/null @@ -1,74 +0,0 @@ -type t = - { db : Types.db - ; db_names : Types.Elt_set.t Types.Tchar.t - } - -module type S = sig - type writer - - val open_out : string -> writer - val save : db:writer -> t -> unit - val close_out : writer -> unit - val load : string -> t list -end - -module Ancient = struct - let base_addr = 0x100000000000n - - type writer = - { mutable write_shard : int - ; ancient : Ancient.md - } - - let open_out filename = - let handle = - Unix.openfile filename Unix.[ O_RDWR; O_TRUNC; O_CREAT ] 0o640 - in - let ancient = Ancient.attach handle base_addr in - { write_shard = 0; ancient } - - let save ~db (t : t) = - ignore (Ancient.share db.ancient db.write_shard t) ; - db.write_shard <- db.write_shard + 1 - - let close_out db = Ancient.detach db.ancient - - type reader = { shards : t array } - - let load_shard md shard = - match Ancient.get md shard with - | t -> Some (Ancient.follow t) - | exception _ -> None - - let load_shards md = - let rec go i = - match load_shard md i with - | None -> [] - | Some t -> t :: go (i + 1) - in - Array.of_list (go 0) - - let db_open_in db : reader = - let filename = db in - let handle = Unix.openfile filename Unix.[ O_RDWR ] 0o640 in - let md = Ancient.attach handle base_addr in - { shards = load_shards md } - - let load db_filename = - let h = db_open_in db_filename in - Array.to_list h.shards -end - -module Marshal = struct - type writer = out_channel - - let open_out = open_out - let close_out = close_out - let save ~db t = Marshal.to_channel db t [] - - let load name = - let file = open_in name in - let t = Marshal.from_channel file in - close_in file ; - [ t ] -end diff --git a/db/db.ml b/lib/db/db.ml similarity index 100% rename from db/db.ml rename to lib/db/db.ml diff --git a/db/db.mli b/lib/db/db.mli similarity index 100% rename from db/db.mli rename to lib/db/db.mli diff --git a/lib/db/dune b/lib/db/dune new file mode 100644 index 0000000000..f77b6a27ea --- /dev/null +++ b/lib/db/dune @@ -0,0 +1,3 @@ +(library + (name db) + (libraries unix tyxml)) diff --git a/lib/db/storage.ml b/lib/db/storage.ml new file mode 100644 index 0000000000..0216d26914 --- /dev/null +++ b/lib/db/storage.ml @@ -0,0 +1,13 @@ +type t = + { db : Types.db + ; db_names : Types.Elt_set.t Types.Tchar.t + } + +module type S = sig + type writer + + val open_out : string -> writer + val save : db:writer -> t -> unit + val close_out : writer -> unit + val load : string -> t list +end diff --git a/db/storage.mli b/lib/db/storage.mli similarity index 64% rename from db/storage.mli rename to lib/db/storage.mli index 08d5f81642..0216d26914 100644 --- a/db/storage.mli +++ b/lib/db/storage.mli @@ -1,8 +1,7 @@ type t = -{ db : Types.db -; db_names : Types.Elt_set.t Types.Tchar.t -} - + { db : Types.db + ; db_names : Types.Elt_set.t Types.Tchar.t + } module type S = sig type writer @@ -12,7 +11,3 @@ module type S = sig val close_out : writer -> unit val load : string -> t list end - -module Ancient : S - -module Marshal : S \ No newline at end of file diff --git a/db/trie.ml b/lib/db/trie.ml similarity index 100% rename from db/trie.ml rename to lib/db/trie.ml diff --git a/db/types.ml b/lib/db/types.ml similarity index 100% rename from db/types.ml rename to lib/db/types.ml diff --git a/index/cache.ml b/lib/index/cache.ml similarity index 100% rename from index/cache.ml rename to lib/index/cache.ml diff --git a/index/cache.mli b/lib/index/cache.mli similarity index 100% rename from index/cache.mli rename to lib/index/cache.mli diff --git a/index/dune b/lib/index/dune similarity index 87% rename from index/dune rename to lib/index/dune index e75cb5365b..6dddb351a5 100644 --- a/index/dune +++ b/lib/index/dune @@ -1,6 +1,7 @@ (executable (name index) (libraries + storage_marshal db fpath tyxml diff --git a/index/files.ml b/lib/index/files.ml similarity index 100% rename from index/files.ml rename to lib/index/files.ml diff --git a/index/files.mli b/lib/index/files.mli similarity index 100% rename from index/files.mli rename to lib/index/files.mli diff --git a/index/index.ml b/lib/index/index.ml similarity index 85% rename from index/index.ml rename to lib/index/index.ml index 32cb8b3b51..7a32a15c75 100644 --- a/index/index.ml +++ b/lib/index/index.ml @@ -11,13 +11,13 @@ let of_filename f = let filenames () = List.map of_filename (Files.list odoc_directory) -module Load_doc = Load_doc.Make (Storage.Ancient) +module Load_doc = Load_doc.Make (Storage_marshal) module Db = Load_doc.Db let () = let files = filenames () in let total = List.length files in - let h = Storage.Ancient.open_out db_filename in + let h = Storage_marshal.open_out db_filename in let flush () = Load_doc.clear () ; Db.export h @@ -33,4 +33,4 @@ let () = Load_doc.run ~odoc_directory file) files ; flush () ; - Storage.Ancient.close_out h + Storage_marshal.close_out h diff --git a/index/load_doc.ml b/lib/index/load_doc.ml similarity index 98% rename from index/load_doc.ml rename to lib/index/load_doc.ml index 7b46fdae9a..39f453331b 100644 --- a/index/load_doc.ml +++ b/lib/index/load_doc.ml @@ -1,4 +1,4 @@ -module Db_common =Db +module Db_common = Db module Make (Storage : Db.Storage.S) = struct module Types = Db.Types @@ -169,8 +169,7 @@ module Make (Storage : Db.Storage.S) = struct let my_full_name = List.map Char.lowercase_ascii my_full_name in Db.store_name my_full_name str_type ; let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in - Db.store_all str_type - (List.map (List.map Cache_name.memo) type_paths) + Db.store_all str_type (List.map (List.map Cache_name.memo) type_paths) let rec item ~pkg ~path_list ~path = let open Odoc_model.Lang in diff --git a/index/load_doc.mli b/lib/index/load_doc.mli similarity index 100% rename from index/load_doc.mli rename to lib/index/load_doc.mli diff --git a/index/pretty.ml b/lib/index/pretty.ml similarity index 100% rename from index/pretty.ml rename to lib/index/pretty.ml diff --git a/query/dune b/lib/query/dune similarity index 100% rename from query/dune rename to lib/query/dune diff --git a/query/lexer.mll b/lib/query/lexer.mll similarity index 100% rename from query/lexer.mll rename to lib/query/lexer.mll diff --git a/query/parser.mly b/lib/query/parser.mly similarity index 100% rename from query/parser.mly rename to lib/query/parser.mly diff --git a/query/query.ml b/lib/query/query.ml similarity index 100% rename from query/query.ml rename to lib/query/query.ml diff --git a/query/query_ast.ml b/lib/query/query_ast.ml similarity index 100% rename from query/query_ast.ml rename to lib/query/query_ast.ml diff --git a/query/query_parser.ml b/lib/query/query_parser.ml similarity index 100% rename from query/query_parser.ml rename to lib/query/query_parser.ml diff --git a/query/sort.ml b/lib/query/sort.ml similarity index 100% rename from query/sort.ml rename to lib/query/sort.ml diff --git a/query/succ.ml b/lib/query/succ.ml similarity index 100% rename from query/succ.ml rename to lib/query/succ.ml diff --git a/lib/storage_ancient/dune b/lib/storage_ancient/dune new file mode 100644 index 0000000000..03a38c297e --- /dev/null +++ b/lib/storage_ancient/dune @@ -0,0 +1,3 @@ +(library + (name storage_ancien) + (libraries ancient db)) diff --git a/lib/storage_ancient/storage_ancient.ml b/lib/storage_ancient/storage_ancient.ml new file mode 100644 index 0000000000..cf2f8f6a81 --- /dev/null +++ b/lib/storage_ancient/storage_ancient.ml @@ -0,0 +1,44 @@ +open Db + +let base_addr = 0x100000000000n + +type writer = + { mutable write_shard : int + ; ancient : Ancient.md + } + +let open_out filename = + let handle = Unix.openfile filename Unix.[ O_RDWR; O_TRUNC; O_CREAT ] 0o640 in + let ancient = Ancient.attach handle base_addr in + { write_shard = 0; ancient } + +let save ~db (t : Storage.t) = + ignore (Ancient.share db.ancient db.write_shard t) ; + db.write_shard <- db.write_shard + 1 + +let close_out db = Ancient.detach db.ancient + +type reader = { shards : Storage.t array } + +let load_shard md shard = + match Ancient.get md shard with + | t -> Some (Ancient.follow t) + | exception _ -> None + +let load_shards md = + let rec go i = + match load_shard md i with + | None -> [] + | Some t -> t :: go (i + 1) + in + Array.of_list (go 0) + +let db_open_in db : reader = + let filename = db in + let handle = Unix.openfile filename Unix.[ O_RDWR ] 0o640 in + let md = Ancient.attach handle base_addr in + { shards = load_shards md } + +let load db_filename = + let h = db_open_in db_filename in + Array.to_list h.shards diff --git a/lib/storage_ancient/storage_ancient.mli b/lib/storage_ancient/storage_ancient.mli new file mode 100644 index 0000000000..bf1293dcd8 --- /dev/null +++ b/lib/storage_ancient/storage_ancient.mli @@ -0,0 +1 @@ +include Db.Storage.S diff --git a/lib/storage_marshal/dune b/lib/storage_marshal/dune new file mode 100644 index 0000000000..a11ca6debf --- /dev/null +++ b/lib/storage_marshal/dune @@ -0,0 +1,3 @@ +(library + (name storage_marshal) + (libraries db)) diff --git a/lib/storage_marshal/storage_marshal.ml b/lib/storage_marshal/storage_marshal.ml new file mode 100644 index 0000000000..6f913a0947 --- /dev/null +++ b/lib/storage_marshal/storage_marshal.ml @@ -0,0 +1,11 @@ +type writer = out_channel + +let open_out = open_out +let close_out = close_out +let save ~db t = Marshal.to_channel db t [] + +let load name = + let file = open_in name in + let t = Marshal.from_channel file in + close_in file ; + [ t ] diff --git a/lib/storage_marshal/storage_marshal.mli b/lib/storage_marshal/storage_marshal.mli new file mode 100644 index 0000000000..bf1293dcd8 --- /dev/null +++ b/lib/storage_marshal/storage_marshal.mli @@ -0,0 +1 @@ +include Db.Storage.S diff --git a/odoc_output/mylib/1.0/main.odocl b/odoc_output/mylib/1.0/main.odocl new file mode 100644 index 0000000000000000000000000000000000000000..2f5addd9776978dea7d5ad7beb292db998c9c934 GIT binary patch literal 71757 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 G`QLws@B^{{ literal 0 HcmV?d00001 diff --git a/utils/dune b/utils/dune new file mode 100644 index 0000000000..8d1d8a67cc --- /dev/null +++ b/utils/dune @@ -0,0 +1,2 @@ +(library + (name utils)) diff --git a/utils/utils.ml b/utils/utils.ml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/www/dune b/www/dune index 80cfd2bc17..6c3c567048 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,3 @@ (executable (name www) - (libraries cmdliner dream db query)) + (libraries cmdliner dream db query storage_marshal)) diff --git a/www/www.ml b/www/www.ml index fc54c0f971..5d8dff24f2 100644 --- a/www/www.ml +++ b/www/www.ml @@ -112,7 +112,7 @@ let cors_options = response) let main db_filename cache_max_age = - let shards = Storage.Ancient.load db_filename in + let shards = Storage_marshal.load db_filename in Dream.run ~interface:"127.0.0.1" ~port:1234 @@ Dream.logger @@ cache_header cache_max_age @@ cors_header @@ Dream.router From 1064f80642f5d6f711170fbfe42404666d918671 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 18 Apr 2023 17:31:24 +0200 Subject: [PATCH 022/285] sherlodoc jsoo demo --- jsoo/dune | 7 ++++++ jsoo/index.html | 13 +++++++++++ jsoo/main.ml | 33 +++++++++++++++++++++++++++ jsoo/result.db | Bin 0 -> 1718 bytes lib/query/query.ml | 54 +++++++++++++++++++++++++++++++------------- lib/query/query.mli | 16 +++++++++++++ www/www.ml | 39 +++----------------------------- 7 files changed, 110 insertions(+), 52 deletions(-) create mode 100644 jsoo/dune create mode 100644 jsoo/index.html create mode 100644 jsoo/main.ml create mode 100644 jsoo/result.db create mode 100644 lib/query/query.mli diff --git a/jsoo/dune b/jsoo/dune new file mode 100644 index 0000000000..165c0731c9 --- /dev/null +++ b/jsoo/dune @@ -0,0 +1,7 @@ +(executable + (name main) + (modes js) + (libraries brr query js_of_ocaml-lwt) + (preprocess (pps ppx_blob js_of_ocaml-ppx)) + (preprocessor_deps result.db) + ) \ No newline at end of file diff --git a/jsoo/index.html b/jsoo/index.html new file mode 100644 index 0000000000..a6f578f5fe --- /dev/null +++ b/jsoo/index.html @@ -0,0 +1,13 @@ + + + + + + + Brr minimal example + + + +
+ + \ No newline at end of file diff --git a/jsoo/main.ml b/jsoo/main.ml new file mode 100644 index 0000000000..97e01ec27e --- /dev/null +++ b/jsoo/main.ml @@ -0,0 +1,33 @@ +let test = [%blob "result.db"] +let shards = [ Marshal.from_string test 0 ] + +open Brr +open Lwt +open Syntax + +let search input _event = + let query = El.prop El.Prop.value input |> Jstr.to_string in + + let+ pretty_query, results = + Query.(api ~shards { query; packages = []; limit = 10 }) + in + let names = List.map (fun r -> r.Db.Elt.name) results in + let names = String.concat " ; " names in + let results_div = + Document.find_el_by_id G.document (Jstr.of_string "results") |> Option.get + in + El.set_children results_div El.[ txt' (pretty_query ^ " => " ^ names) ] + +let search input event = + Js_of_ocaml_lwt.Lwt_js_events.async (fun () -> search input event) + +let main () = + let search_input = + Document.find_el_by_id G.document (Jstr.of_string "search") |> Option.get + in + + Ev.( + listen input (search search_input) + (search_input |> El.document |> Document.as_target)) + +let _ = main () diff --git a/jsoo/result.db b/jsoo/result.db new file mode 100644 index 0000000000000000000000000000000000000000..5f0b025234f8df7e198bd16eff7b13e07eef4ee4 GIT binary patch literal 1718 zcmah}&x;&I6s~SwZCC>dh@xl+nd$ABolO{jBpbX)s&^A1!mgt$A=ldJ+OeRzd$ziJ zNG_iI1D1u{iyU&#VXt9M@gg`NUc^H{f_hLv)QdmxbyxN5uzSeBW2(Bo_r3SN_o}{l z@aPF4OAiV0KPTkO8m^z4$LwInqUn@9`>3}jzlv`B}d-XEtVa; zc$ZhhESw7Aekt>27IM^8IQ{2%oKYMXSMtfoopGt>owzc4b*ly(P3QP+}+oEtVs#&m`1x4^4_8Ftzm(^48>E+|A{4Vu=HimjXq5X*0nR-vD z_ch-4MbK61{Z@f~Mf;@&eMP-*PcU7h-d`2yPqaU3&^Ofk{sd^9djD3Sf6)G}LElmD z2NrE?-el2i#;Et7VbzO9{blMspF#`Xm@;?;?VLlgi26&&;V&^bGh_C>qy9?_&LRRI zL@bf|uOiI*9hcB&5v<~W8|^~PF~c8AjUlNa(hzP)!lrPZ`eX{{U>$L9q4iumjljeZ zVTd*)GejA5Tl8db8*^v*i*bVrhp+RC`0iA=@-z;vV_tVzRA+{H!#Z5UQZP4IuB(0z zYt@KJ&_-z7)qrKf4S2u8Dg)aHs)Xgx8Qk8@L3ovkfvar!=AdJ@nlC;D49pf9L=J literal 0 HcmV?d00001 diff --git a/lib/query/query.ml b/lib/query/query.ml index caefcda31f..dd8127eb22 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -8,15 +8,6 @@ let inter_list = function | [] -> Succ.all | x :: xs -> List.fold_left Succ.inter x xs -let merge a b = - Occ.merge - (fun _ ox oy -> - match ox, oy with - | Some x, Some y -> Some (Succ.union (Succ.of_set x) y) - | Some x, None -> Some (Succ.of_set x) - | None, opt -> opt) - a b - let collapse_trie t _acc = let open Db.Types.T in match t with @@ -96,10 +87,41 @@ let find_names ~shards names = Succ.union acc candidates) Succ.empty shards -let pp h set = - Int_map.iter - (fun cost values -> - Elt_set.iter - (fun value -> Format.fprintf h "(%i) %s\n%!" cost value.str_type) - values) - set +type t = + { query : string + ; packages : string list + ; limit : int + } + +let search ~shards query_name query_typ = + let open Lwt.Syntax in + let* results_name = find_names ~shards query_name in + let+ results = + match query_typ with + | None -> Lwt.return results_name + | Some query_typ -> + let+ results_typ = find_inter ~shards query_typ in + Succ.inter results_name results_typ + in + results + +open Lwt.Syntax + +let match_packages ~packages { Db.Elt.pkg = package, _version; _ } = + List.exists (String.equal package) packages + +let match_packages ~packages results = + match packages with + | [] -> results + | _ -> Lwt_stream.filter (match_packages ~packages) results + +let api ~shards params = + let query_name, query_typ, query_typ_arrow, pretty = + Parser.of_string params.query + in + let* results = search ~shards query_name query_typ in + let results = Succ.to_stream results in + let results = match_packages ~packages:params.packages results in + let+ results = Lwt_stream.nget params.limit results in + let results = Sort.list query_name query_typ_arrow results in + pretty, results diff --git a/lib/query/query.mli b/lib/query/query.mli new file mode 100644 index 0000000000..9904d0c045 --- /dev/null +++ b/lib/query/query.mli @@ -0,0 +1,16 @@ +module Parser = Query_parser +module Succ = Succ +module Sort = Sort + +val find_inter : + shards:Db.Storage.t list -> Db.String_list_map.key list -> Succ.t Lwt.t + +val find_names : shards:Db.Storage.t list -> string list -> Succ.t Lwt.t + +type t = + { query : string + ; packages : string list + ; limit : int + } + +val api : shards:Db.Storage.t list -> t -> (string * Db.Elt.t list) Lwt.t diff --git a/www/www.ml b/www/www.ml index 5d8dff24f2..ce3171e2cb 100644 --- a/www/www.ml +++ b/www/www.ml @@ -2,48 +2,15 @@ module Storage = Db.Storage module Succ = Query.Succ module Sort = Query.Sort -type params = - { query : string - ; packages : string list - ; limit : int - } - -let search ~shards query_name query_typ = - let open Lwt.Syntax in - let* results_name = Query.find_names ~shards query_name in - let+ results = - match query_typ with - | None -> Lwt.return results_name - | Some query_typ -> - let+ results_typ = Query.find_inter ~shards query_typ in - Succ.inter results_name results_typ - in - results - open Lwt.Syntax module H = Tyxml.Html -let match_packages ~packages { Db.Elt.pkg = package, _version; _ } = - List.exists (String.equal package) packages - -let match_packages ~packages results = - match packages with - | [] -> results - | _ -> Lwt_stream.filter (match_packages ~packages) results - let api ~shards params = - let query_name, query_typ, query_typ_arrow, pretty = - Query.Parser.of_string params.query - in - let* results = search ~shards query_name query_typ in - let results = Succ.to_stream results in - let results = match_packages ~packages:params.packages results in - let+ results = Lwt_stream.nget params.limit results in - let results = Sort.list query_name query_typ_arrow results in + let+ pretty, results = Query.api ~shards params in Ui.render ~pretty results let api ~shards params = - if String.trim params.query = "" + if String.trim params.Query.query = "" then Lwt.return Ui.explain else api ~shards params @@ -64,7 +31,7 @@ let get_limit params = try max 1 (min default (int_of_string str)) with _ -> default) let get_params params = - { query = get_query params + { Query.query = get_query params ; packages = get_packages params ; limit = get_limit params } From 8115bee24bf6f6b311d15314224c1e91fcc6bfc6 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 19 Apr 2023 15:05:03 +0200 Subject: [PATCH 023/285] rename and cleanup --- JSherlodoc/dune | 7 +++++++ JSherlodoc/index.html | 13 +++++++++++++ JSherlodoc/main.ml | 32 ++++++++++++++++++++++++++++++++ JSherlodoc/result.db | Bin 0 -> 1718 bytes 4 files changed, 52 insertions(+) create mode 100644 JSherlodoc/dune create mode 100644 JSherlodoc/index.html create mode 100644 JSherlodoc/main.ml create mode 100644 JSherlodoc/result.db diff --git a/JSherlodoc/dune b/JSherlodoc/dune new file mode 100644 index 0000000000..165c0731c9 --- /dev/null +++ b/JSherlodoc/dune @@ -0,0 +1,7 @@ +(executable + (name main) + (modes js) + (libraries brr query js_of_ocaml-lwt) + (preprocess (pps ppx_blob js_of_ocaml-ppx)) + (preprocessor_deps result.db) + ) \ No newline at end of file diff --git a/JSherlodoc/index.html b/JSherlodoc/index.html new file mode 100644 index 0000000000..b8a3604eb4 --- /dev/null +++ b/JSherlodoc/index.html @@ -0,0 +1,13 @@ + + + + + + + JSherlodoc + + + +
+ + \ No newline at end of file diff --git a/JSherlodoc/main.ml b/JSherlodoc/main.ml new file mode 100644 index 0000000000..2b664f6253 --- /dev/null +++ b/JSherlodoc/main.ml @@ -0,0 +1,32 @@ +let test = [%blob "odoc_result.db"] +let shards = [ Marshal.from_string test 0 ] + +open Brr +open Lwt +open Syntax + +let search input _event = + let query = El.prop El.Prop.value input |> Jstr.to_string in + + let+ pretty_query, results = + Query.(api ~shards { query; packages = []; limit = 10 }) + in + let names = List.map (fun r -> r.Db.Elt.name) results in + let names = String.concat " ; " names in + let results_div = + Document.find_el_by_id G.document (Jstr.of_string "results") |> Option.get + in + El.set_children results_div El.[ txt' (pretty_query ^ " => " ^ names) ] + +let search input event = + Js_of_ocaml_lwt.Lwt_js_events.async (fun () -> search input event) + +let main () = + let search_input = + Document.find_el_by_id G.document (Jstr.of_string "search") |> Option.get + in + Ev.( + listen input (search search_input) + (search_input |> El.document |> Document.as_target)) + +let _ = main () diff --git a/JSherlodoc/result.db b/JSherlodoc/result.db new file mode 100644 index 0000000000000000000000000000000000000000..5f0b025234f8df7e198bd16eff7b13e07eef4ee4 GIT binary patch literal 1718 zcmah}&x;&I6s~SwZCC>dh@xl+nd$ABolO{jBpbX)s&^A1!mgt$A=ldJ+OeRzd$ziJ zNG_iI1D1u{iyU&#VXt9M@gg`NUc^H{f_hLv)QdmxbyxN5uzSeBW2(Bo_r3SN_o}{l z@aPF4OAiV0KPTkO8m^z4$LwInqUn@9`>3}jzlv`B}d-XEtVa; zc$ZhhESw7Aekt>27IM^8IQ{2%oKYMXSMtfoopGt>owzc4b*ly(P3QP+}+oEtVs#&m`1x4^4_8Ftzm(^48>E+|A{4Vu=HimjXq5X*0nR-vD z_ch-4MbK61{Z@f~Mf;@&eMP-*PcU7h-d`2yPqaU3&^Ofk{sd^9djD3Sf6)G}LElmD z2NrE?-el2i#;Et7VbzO9{blMspF#`Xm@;?;?VLlgi26&&;V&^bGh_C>qy9?_&LRRI zL@bf|uOiI*9hcB&5v<~W8|^~PF~c8AjUlNa(hzP)!lrPZ`eX{{U>$L9q4iumjljeZ zVTd*)GejA5Tl8db8*^v*i*bVrhp+RC`0iA=@-z;vV_tVzRA+{H!#Z5UQZP4IuB(0z zYt@KJ&_-z7)qrKf4S2u8Dg)aHs)Xgx8Qk8@L3ovkfvar!=AdJ@nlC;D49pf9L=J literal 0 HcmV?d00001 From 83c9af17256ea364cf1d42e2d82af414141bea7e Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 19 Apr 2023 15:06:17 +0200 Subject: [PATCH 024/285] move index back to root --- {lib/index => index}/cache.ml | 0 {lib/index => index}/cache.mli | 0 {lib/index => index}/dune | 0 {lib/index => index}/files.ml | 0 {lib/index => index}/files.mli | 0 {lib/index => index}/index.ml | 0 {lib/index => index}/load_doc.ml | 0 {lib/index => index}/load_doc.mli | 0 {lib/index => index}/pretty.ml | 0 jsoo/dune | 7 ------- jsoo/index.html | 13 ------------ jsoo/main.ml | 33 ------------------------------ jsoo/result.db | Bin 1718 -> 0 bytes 13 files changed, 53 deletions(-) rename {lib/index => index}/cache.ml (100%) rename {lib/index => index}/cache.mli (100%) rename {lib/index => index}/dune (100%) rename {lib/index => index}/files.ml (100%) rename {lib/index => index}/files.mli (100%) rename {lib/index => index}/index.ml (100%) rename {lib/index => index}/load_doc.ml (100%) rename {lib/index => index}/load_doc.mli (100%) rename {lib/index => index}/pretty.ml (100%) delete mode 100644 jsoo/dune delete mode 100644 jsoo/index.html delete mode 100644 jsoo/main.ml delete mode 100644 jsoo/result.db diff --git a/lib/index/cache.ml b/index/cache.ml similarity index 100% rename from lib/index/cache.ml rename to index/cache.ml diff --git a/lib/index/cache.mli b/index/cache.mli similarity index 100% rename from lib/index/cache.mli rename to index/cache.mli diff --git a/lib/index/dune b/index/dune similarity index 100% rename from lib/index/dune rename to index/dune diff --git a/lib/index/files.ml b/index/files.ml similarity index 100% rename from lib/index/files.ml rename to index/files.ml diff --git a/lib/index/files.mli b/index/files.mli similarity index 100% rename from lib/index/files.mli rename to index/files.mli diff --git a/lib/index/index.ml b/index/index.ml similarity index 100% rename from lib/index/index.ml rename to index/index.ml diff --git a/lib/index/load_doc.ml b/index/load_doc.ml similarity index 100% rename from lib/index/load_doc.ml rename to index/load_doc.ml diff --git a/lib/index/load_doc.mli b/index/load_doc.mli similarity index 100% rename from lib/index/load_doc.mli rename to index/load_doc.mli diff --git a/lib/index/pretty.ml b/index/pretty.ml similarity index 100% rename from lib/index/pretty.ml rename to index/pretty.ml diff --git a/jsoo/dune b/jsoo/dune deleted file mode 100644 index 165c0731c9..0000000000 --- a/jsoo/dune +++ /dev/null @@ -1,7 +0,0 @@ -(executable - (name main) - (modes js) - (libraries brr query js_of_ocaml-lwt) - (preprocess (pps ppx_blob js_of_ocaml-ppx)) - (preprocessor_deps result.db) - ) \ No newline at end of file diff --git a/jsoo/index.html b/jsoo/index.html deleted file mode 100644 index a6f578f5fe..0000000000 --- a/jsoo/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Brr minimal example - - - -
- - \ No newline at end of file diff --git a/jsoo/main.ml b/jsoo/main.ml deleted file mode 100644 index 97e01ec27e..0000000000 --- a/jsoo/main.ml +++ /dev/null @@ -1,33 +0,0 @@ -let test = [%blob "result.db"] -let shards = [ Marshal.from_string test 0 ] - -open Brr -open Lwt -open Syntax - -let search input _event = - let query = El.prop El.Prop.value input |> Jstr.to_string in - - let+ pretty_query, results = - Query.(api ~shards { query; packages = []; limit = 10 }) - in - let names = List.map (fun r -> r.Db.Elt.name) results in - let names = String.concat " ; " names in - let results_div = - Document.find_el_by_id G.document (Jstr.of_string "results") |> Option.get - in - El.set_children results_div El.[ txt' (pretty_query ^ " => " ^ names) ] - -let search input event = - Js_of_ocaml_lwt.Lwt_js_events.async (fun () -> search input event) - -let main () = - let search_input = - Document.find_el_by_id G.document (Jstr.of_string "search") |> Option.get - in - - Ev.( - listen input (search search_input) - (search_input |> El.document |> Document.as_target)) - -let _ = main () diff --git a/jsoo/result.db b/jsoo/result.db deleted file mode 100644 index 5f0b025234f8df7e198bd16eff7b13e07eef4ee4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1718 zcmah}&x;&I6s~SwZCC>dh@xl+nd$ABolO{jBpbX)s&^A1!mgt$A=ldJ+OeRzd$ziJ zNG_iI1D1u{iyU&#VXt9M@gg`NUc^H{f_hLv)QdmxbyxN5uzSeBW2(Bo_r3SN_o}{l z@aPF4OAiV0KPTkO8m^z4$LwInqUn@9`>3}jzlv`B}d-XEtVa; zc$ZhhESw7Aekt>27IM^8IQ{2%oKYMXSMtfoopGt>owzc4b*ly(P3QP+}+oEtVs#&m`1x4^4_8Ftzm(^48>E+|A{4Vu=HimjXq5X*0nR-vD z_ch-4MbK61{Z@f~Mf;@&eMP-*PcU7h-d`2yPqaU3&^Ofk{sd^9djD3Sf6)G}LElmD z2NrE?-el2i#;Et7VbzO9{blMspF#`Xm@;?;?VLlgi26&&;V&^bGh_C>qy9?_&LRRI zL@bf|uOiI*9hcB&5v<~W8|^~PF~c8AjUlNa(hzP)!lrPZ`eX{{U>$L9q4iumjljeZ zVTd*)GejA5Tl8db8*^v*i*bVrhp+RC`0iA=@-z;vV_tVzRA+{H!#Z5UQZP4IuB(0z zYt@KJ&_-z7)qrKf4S2u8Dg)aHs)Xgx8Qk8@L3ovkfvar!=AdJ@nlC;D49pf9L=J From 9d7ca07d3ded04bf1c181d709fe576e18b4689e2 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 19 Apr 2023 15:23:36 +0200 Subject: [PATCH 025/285] add a lib for indexing --- index/dune | 12 +-------- index/index.ml | 37 +-------------------------- {index => lib/index_lib}/cache.ml | 0 {index => lib/index_lib}/cache.mli | 0 lib/index_lib/dune | 12 +++++++++ {index => lib/index_lib}/files.ml | 0 {index => lib/index_lib}/files.mli | 0 lib/index_lib/index_lib.ml | 36 ++++++++++++++++++++++++++ lib/index_lib/index_lib.mli | 1 + {index => lib/index_lib}/load_doc.ml | 0 {index => lib/index_lib}/load_doc.mli | 0 {index => lib/index_lib}/pretty.ml | 0 12 files changed, 51 insertions(+), 47 deletions(-) rename {index => lib/index_lib}/cache.ml (100%) rename {index => lib/index_lib}/cache.mli (100%) create mode 100644 lib/index_lib/dune rename {index => lib/index_lib}/files.ml (100%) rename {index => lib/index_lib}/files.mli (100%) create mode 100644 lib/index_lib/index_lib.ml create mode 100644 lib/index_lib/index_lib.mli rename {index => lib/index_lib}/load_doc.ml (100%) rename {index => lib/index_lib}/load_doc.mli (100%) rename {index => lib/index_lib}/pretty.ml (100%) diff --git a/index/dune b/index/dune index 6dddb351a5..38a402f2d5 100644 --- a/index/dune +++ b/index/dune @@ -1,13 +1,3 @@ (executable (name index) - (libraries - storage_marshal - db - fpath - tyxml - opam-core - odoc.loader - odoc.model - odoc.xref2 - odoc.odoc - str)) + (libraries index_lib storage_marshal)) \ No newline at end of file diff --git a/index/index.ml b/index/index.ml index 7a32a15c75..8b8f36ef52 100644 --- a/index/index.ml +++ b/index/index.ml @@ -1,36 +1 @@ -module Storage = Db.Storage - -let odoc_directory = Sys.argv.(1) -let db_filename = Sys.argv.(2) - -let of_filename f = - let module_name = - String.capitalize_ascii Filename.(chop_extension (basename f)) - in - module_name, f - -let filenames () = List.map of_filename (Files.list odoc_directory) - -module Load_doc = Load_doc.Make (Storage_marshal) -module Db = Load_doc.Db - -let () = - let files = filenames () in - let total = List.length files in - let h = Storage_marshal.open_out db_filename in - let flush () = - Load_doc.clear () ; - Db.export h - in - List.iteri - (fun i file -> - if !Db.load_counter > 10_000_000 - then begin - Printf.printf - "---------------- SHARD %i / %i -----------------------\n%!" i total ; - flush () - end ; - Load_doc.run ~odoc_directory file) - files ; - flush () ; - Storage_marshal.close_out h +let () = Index_lib.main (module Storage_marshal) () diff --git a/index/cache.ml b/lib/index_lib/cache.ml similarity index 100% rename from index/cache.ml rename to lib/index_lib/cache.ml diff --git a/index/cache.mli b/lib/index_lib/cache.mli similarity index 100% rename from index/cache.mli rename to lib/index_lib/cache.mli diff --git a/lib/index_lib/dune b/lib/index_lib/dune new file mode 100644 index 0000000000..c512fafd21 --- /dev/null +++ b/lib/index_lib/dune @@ -0,0 +1,12 @@ +(library + (name index_lib) + (libraries + db + fpath + tyxml + opam-core + odoc.loader + odoc.model + odoc.xref2 + odoc.odoc + str)) diff --git a/index/files.ml b/lib/index_lib/files.ml similarity index 100% rename from index/files.ml rename to lib/index_lib/files.ml diff --git a/index/files.mli b/lib/index_lib/files.mli similarity index 100% rename from index/files.mli rename to lib/index_lib/files.mli diff --git a/lib/index_lib/index_lib.ml b/lib/index_lib/index_lib.ml new file mode 100644 index 0000000000..d9e591dbc5 --- /dev/null +++ b/lib/index_lib/index_lib.ml @@ -0,0 +1,36 @@ +module Storage = Db.Storage + +let odoc_directory = Sys.argv.(1) +let db_filename = Sys.argv.(2) + +let of_filename f = + let module_name = + String.capitalize_ascii Filename.(chop_extension (basename f)) + in + module_name, f + +let filenames () = List.map of_filename (Files.list odoc_directory) + +let main storage () = + let module Storage = (val storage : Storage.S) in + let module Load_doc = Load_doc.Make (Storage) in + let module Db = Load_doc.Db in + let files = filenames () in + let total = List.length files in + let h = Storage.open_out db_filename in + let flush () = + Load_doc.clear () ; + Db.export h + in + List.iteri + (fun i file -> + if !Db.load_counter > 10_000_000 + then begin + Printf.printf + "---------------- SHARD %i / %i -----------------------\n%!" i total ; + flush () + end ; + Load_doc.run ~odoc_directory file) + files ; + flush () ; + Storage.close_out h diff --git a/lib/index_lib/index_lib.mli b/lib/index_lib/index_lib.mli new file mode 100644 index 0000000000..60d4c15568 --- /dev/null +++ b/lib/index_lib/index_lib.mli @@ -0,0 +1 @@ +val main : (module Db.Storage.S) -> unit -> unit diff --git a/index/load_doc.ml b/lib/index_lib/load_doc.ml similarity index 100% rename from index/load_doc.ml rename to lib/index_lib/load_doc.ml diff --git a/index/load_doc.mli b/lib/index_lib/load_doc.mli similarity index 100% rename from index/load_doc.mli rename to lib/index_lib/load_doc.mli diff --git a/index/pretty.ml b/lib/index_lib/pretty.ml similarity index 100% rename from index/pretty.ml rename to lib/index_lib/pretty.ml From 8182b12b39a4f19d05cefb90eeeaf0ab6dc4e970 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 19 Apr 2023 15:28:10 +0200 Subject: [PATCH 026/285] index lib has arguments --- index/index.ml | 4 +++- lib/index_lib/index_lib.ml | 9 +++------ lib/index_lib/index_lib.mli | 3 ++- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/index/index.ml b/index/index.ml index 8b8f36ef52..b350e23b73 100644 --- a/index/index.ml +++ b/index/index.ml @@ -1 +1,3 @@ -let () = Index_lib.main (module Storage_marshal) () +let () = + let odoc_directory = Sys.argv.(1) and db_filename = Sys.argv.(2) in + Index_lib.main ~odoc_directory ~db_filename (module Storage_marshal) diff --git a/lib/index_lib/index_lib.ml b/lib/index_lib/index_lib.ml index d9e591dbc5..6110176bdf 100644 --- a/lib/index_lib/index_lib.ml +++ b/lib/index_lib/index_lib.ml @@ -1,21 +1,18 @@ module Storage = Db.Storage -let odoc_directory = Sys.argv.(1) -let db_filename = Sys.argv.(2) - let of_filename f = let module_name = String.capitalize_ascii Filename.(chop_extension (basename f)) in module_name, f -let filenames () = List.map of_filename (Files.list odoc_directory) +let filenames odoc_directory = List.map of_filename (Files.list odoc_directory) -let main storage () = +let main ~odoc_directory ~db_filename storage = let module Storage = (val storage : Storage.S) in let module Load_doc = Load_doc.Make (Storage) in let module Db = Load_doc.Db in - let files = filenames () in + let files = filenames odoc_directory in let total = List.length files in let h = Storage.open_out db_filename in let flush () = diff --git a/lib/index_lib/index_lib.mli b/lib/index_lib/index_lib.mli index 60d4c15568..b2db9016d7 100644 --- a/lib/index_lib/index_lib.mli +++ b/lib/index_lib/index_lib.mli @@ -1 +1,2 @@ -val main : (module Db.Storage.S) -> unit -> unit +val main : + odoc_directory:string -> db_filename:string -> (module Db.Storage.S) -> unit From d4f8818bcaf5250f115c154372bba8ccedf7b6a5 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 19 Apr 2023 18:02:41 +0200 Subject: [PATCH 027/285] doc comments converted to html by www --- lib/db/dune | 2 +- lib/db/types.ml | 2 +- lib/html_of_odoc/dune | 3 + lib/html_of_odoc/html_of_odoc.ml | 35 ++++ lib/index_lib/dune | 1 + lib/index_lib/load_doc.ml | 32 ++-- lib/index_lib/pretty.ml | 249 ------------------------- lib/index_lib/strings.ml | 0 lib/strings_of_odoc/dune | 3 + lib/strings_of_odoc/strings_of_odoc.ml | 211 +++++++++++++++++++++ www/dune | 2 +- www/ui.ml | 5 +- 12 files changed, 273 insertions(+), 272 deletions(-) create mode 100644 lib/html_of_odoc/dune create mode 100644 lib/html_of_odoc/html_of_odoc.ml delete mode 100644 lib/index_lib/pretty.ml create mode 100644 lib/index_lib/strings.ml create mode 100644 lib/strings_of_odoc/dune create mode 100644 lib/strings_of_odoc/strings_of_odoc.ml diff --git a/lib/db/dune b/lib/db/dune index f77b6a27ea..4f986fe704 100644 --- a/lib/db/dune +++ b/lib/db/dune @@ -1,3 +1,3 @@ (library (name db) - (libraries unix tyxml)) + (libraries unix tyxml odoc.model odoc.xref2 odoc.odoc)) diff --git a/lib/db/types.ml b/lib/db/types.ml index 8f98e0deda..55f6e607a9 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -4,7 +4,7 @@ module Elt = struct ; name : string ; str_type : string ; type_paths : string list list - ; doc : Html_types.li_content_fun Tyxml.Html.elt option + ; doc : Odoc_model.Comment.docs ; pkg : string * string } diff --git a/lib/html_of_odoc/dune b/lib/html_of_odoc/dune new file mode 100644 index 0000000000..c80dc5d2db --- /dev/null +++ b/lib/html_of_odoc/dune @@ -0,0 +1,3 @@ +(library + (name html_of_odoc) + (libraries strings_of_odoc tyxml opam-core odoc.loader odoc.model odoc.xref2 odoc.odoc)) diff --git a/lib/html_of_odoc/html_of_odoc.ml b/lib/html_of_odoc/html_of_odoc.ml new file mode 100644 index 0000000000..79021bca09 --- /dev/null +++ b/lib/html_of_odoc/html_of_odoc.ml @@ -0,0 +1,35 @@ +module ModuleName = Odoc_model.Names.ModuleName +module H = Tyxml.Html +open Strings_of_odoc + +let rec string_of_non_link = function + | `Space -> H.txt " " + | `Word w -> H.txt w + | `Code_span s -> H.code [ H.txt s ] + | `Raw_markup (_, s) -> H.txt s + | `Styled (_, lst) -> string_of_link_content lst + +and string_of_element = function + | `Styled (_, lst) -> string_of_paragraph lst + | `Reference (r, _) -> H.code [ H.txt (string_of_reference r) ] + | `Link (_, r) -> string_of_link_content r + | `Space -> H.txt " " + | `Word w -> H.txt w + | `Code_span s -> H.code [ H.txt s ] + | `Raw_markup (_, s) -> H.txt s + +and string_of_link_content lst = + H.span + (List.map (fun r -> string_of_non_link r.Odoc_model.Location_.value) lst) + +and string_of_paragraph lst = + H.span + (List.map (fun elt -> string_of_element elt.Odoc_model.Location_.value) lst) + +let string_of_doc = function + | `Paragraph p -> Some (H.p [ string_of_paragraph p ]) + | `Heading (_, _, p) -> Some (H.p [ string_of_link_content p ]) + | _ -> None + +let string_of_docs lst = + List.find_map (fun elt -> string_of_doc elt.Odoc_model.Location_.value) lst diff --git a/lib/index_lib/dune b/lib/index_lib/dune index c512fafd21..a53e6dd619 100644 --- a/lib/index_lib/dune +++ b/lib/index_lib/dune @@ -1,6 +1,7 @@ (library (name index_lib) (libraries + strings_of_odoc db fpath tyxml diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 39f453331b..a1430fdd14 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -1,5 +1,7 @@ module Db_common = Db +open Strings_of_odoc + module Make (Storage : Db.Storage.S) = struct module Types = Db.Types module Db = Db.Make (Storage) @@ -54,8 +56,7 @@ module Make (Storage : Db.Storage.S) = struct | [] -> [] | _ :: xs as lst -> lst :: tails xs - let fullname t = - Pretty.fmt_to_string (fun h -> Pretty.show_type_name_verbose h t) + let fullname t = Format.asprintf "%a" Strings_of_odoc.show_type_name_verbose t let all_type_names t = let fullname = fullname t in @@ -77,9 +78,7 @@ module Make (Storage : Db.Storage.S) = struct | Constr (name, args) -> let name = fullname name in let prefix = - Cache_name.memo name - :: Cache_name.memo (Types.string_of_sgn sgn) - :: prefix + name :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix in begin match args with @@ -129,26 +128,21 @@ module Make (Storage : Db.Storage.S) = struct | _ -> [] let save_item ~pkg ~path_list ~path name type_ doc = - let b = Buffer.create 16 in - let to_b = Format.formatter_of_buffer b in - Format.fprintf to_b "%a%!" - (Pretty.show_type - ~path:(Pretty.fmt_to_string (fun h -> Pretty.pp_path h path)) + let str_type = Format.asprintf "%a%!" + (show_type + ~path:( Format.asprintf "%a" pp_path path) ~parens:false) - type_ ; - let str_type = Buffer.contents b in - Buffer.reset b ; - Format.fprintf to_b "%a%s%!" Pretty.pp_path path - (Odoc_model.Names.ValueName.to_string name) ; - let full_name = Buffer.contents b in - let doc = Option.map Cache_doc.memo (Pretty.string_of_docs doc) in + type_ in + let full_name = Format.asprintf "%a%s%!" pp_path path + (Odoc_model.Names.ValueName.to_string name) in + (* let doc = Option.map Cache_doc.memo (Pretty.string_of_docs doc) in *) let cost = String.length full_name + String.length str_type + (5 * List.length path) + type_size type_ - + (match doc with + + (*(match doc with | None -> 1000 - | _ -> 0) + | _ -> 0) TODO UNDERSTAND *) + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 in let paths = paths ~prefix:[] ~sgn:Pos type_ in diff --git a/lib/index_lib/pretty.ml b/lib/index_lib/pretty.ml deleted file mode 100644 index 14353570b3..0000000000 --- a/lib/index_lib/pretty.ml +++ /dev/null @@ -1,249 +0,0 @@ -open Odoc_model -open Odoc_model.Root -module ModuleName = Odoc_model.Names.ModuleName -module H = Tyxml.Html - -let fmt_to_string f = - let b = Buffer.create 16 in - let to_b = Format.formatter_of_buffer b in - f to_b ; - Format.fprintf to_b "%!" ; - Buffer.contents b - -let string_of_identifier = function - | `Class (_, n) -> Names.ClassName.to_string n - | `ClassType (_, n) -> Names.ClassTypeName.to_string n - | `Constructor (_, n) -> Names.ConstructorName.to_string n - | `Exception (_, n) -> Names.ExceptionName.to_string n - | `Extension (_, n) -> Names.ExtensionName.to_string n - | `Field (_, n) -> Names.FieldName.to_string n - | `InstanceVariable (_, n) -> Names.InstanceVariableName.to_string n - | `Label (_, n) -> Names.LabelName.to_string n - | `Method (_, n) -> Names.MethodName.to_string n - | `Module (_, n) -> ModuleName.to_string n - | `ModuleType (_, n) -> Names.ModuleTypeName.to_string n - | `Type (_, n) -> Names.TypeName.to_string n - | `Value (_, n) -> Names.ValueName.to_string n - | _ -> "" - -let string_of_resolved = function - | `Identifier v -> string_of_identifier v - | r -> string_of_identifier r - -let string_of_reference = function - | `Root (r, _) -> r - | `Dot (_, n) -> n - | `Resolved r -> string_of_resolved r - | r -> string_of_identifier r - -let rec string_of_non_link = function - | `Space -> H.txt " " - | `Word w -> H.txt w - | `Code_span s -> H.code [ H.txt s ] - | `Raw_markup (_, s) -> H.txt s - | `Styled (_, lst) -> string_of_link_content lst - -and string_of_element = function - | `Styled (_, lst) -> string_of_paragraph lst - | `Reference (r, _) -> H.code [ H.txt (string_of_reference r) ] - | `Link (_, r) -> string_of_link_content r - | `Space -> H.txt " " - | `Word w -> H.txt w - | `Code_span s -> H.code [ H.txt s ] - | `Raw_markup (_, s) -> H.txt s - -and string_of_link_content lst = - H.span - (List.map (fun r -> string_of_non_link r.Odoc_model.Location_.value) lst) - -and string_of_paragraph lst = - H.span - (List.map (fun elt -> string_of_element elt.Odoc_model.Location_.value) lst) - -let string_of_doc = function - | `Paragraph p -> Some (H.p [ string_of_paragraph p ]) - | `Heading (_, _, p) -> Some (H.p [ string_of_link_content p ]) - | _ -> None - -let string_of_docs lst = - List.find_map (fun elt -> string_of_doc elt.Odoc_model.Location_.value) lst - -let make_root ~module_name ~digest = - let file = Odoc_file.create_unit ~force_hidden:false module_name in - Ok { id = `Root (None, ModuleName.make_std module_name); file; digest } - -let show_module_name h md = - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) - -let show_module_ident h = function - | `Module (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) - | `Root (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) - | _ -> Format.fprintf h "!!module!!" - -let rec show_module_t h = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_module_ident (Resolved.Module.identifier t) - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x - | `Root x -> Format.fprintf h "%s" x - | `Apply (m, _) -> Format.fprintf h "%a(_)" show_module_t m - | `Forward str -> Format.fprintf h "%s" str - | `Result _ -> () - | `Identifier _ -> () - -and show_module_path h = function - | `Identifier (`Module (_, md)) -> - Format.fprintf h "" show_module_name md - | `Identifier (`Root (_, md)) -> - Format.fprintf h "" show_module_name md - | `Identifier _ -> Format.fprintf h "" - | `Subst _ -> Format.fprintf h "" - | `Hidden _ -> Format.fprintf h "" - | `Module (pt, md) -> - Format.fprintf h "" show_module_path pt show_module_name - md - | `Canonical (pt, md) -> - Format.fprintf h "" show_module_path pt show_module_t md - | `Apply _ -> Format.fprintf h "" - | `Alias (pt, md) -> - Format.fprintf h "" show_module_path pt show_module_path md - | `OpaqueModule _ -> Format.fprintf h "" - -and show_signature h = function - | `Root (_, name) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) - | `Module (pt, mdl) -> - Format.fprintf h "%a.%a" show_signature pt show_module_name mdl - | `Parameter (_, p) -> - Format.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string p) - | `Result t -> Format.fprintf h "%a" show_signature t - | `ModuleType (_, p) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) - -let show_ident_verbose h = function - | `Type (md, n) -> - Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) - | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) - | _ -> Format.fprintf h "show_ident?" - -let show_ident_short h = function - | `Type (_, n) -> Format.fprintf h "%s" (Names.TypeName.to_string n) - | `CoreType n -> Format.fprintf h "%s" (Names.TypeName.to_string n) - | _ -> Format.fprintf h "show_ident?" - -let show_type_name_verbose h = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_ident_verbose (Resolved.Type.identifier t) - | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x - -let show_type_name_short h = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_ident_short (Resolved.Type.identifier t) - | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b - | `Dot (_mdl, x) -> Format.fprintf h "%s" x - -let strip ~prefix str = - if String.starts_with ~prefix str - then - String.sub str (String.length prefix) - (String.length str - String.length prefix) - else str - -let show_type_name ~path h t = - let blah = fmt_to_string (fun h -> show_type_name_verbose h t) in - let blah = strip ~prefix:path blah in - let blah = strip ~prefix:"Stdlib." blah in - Format.fprintf h "%s" blah - -let show_moduletype_ident h = function - | `ModuleType (_, _) -> Format.fprintf h "ident" - | _ -> Format.fprintf h "moduletype" - -let show_moduletype_name h = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_moduletype_ident - (Resolved.ModuleType.identifier t) - | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x - -let show_label h = function - | None -> () - | Some (Odoc_model.Lang.TypeExpr.Label lbl) -> Format.fprintf h "%s:" lbl - | Some (Optional lbl) -> Format.fprintf h "?%s:" lbl - -let show_type_id h = function - | `Type (_, name) -> Printf.fprintf h "%s" (Names.TypeName.to_string name) - | `CoreType name -> - Printf.fprintf h "(core)%s" (Names.TypeName.to_string name) - -let show_type_repr h = function - | None -> Printf.fprintf h "no repr" - | Some _ -> Printf.fprintf h "has repr" - -let show_functor_param h = function - | Lang.FunctorParameter.Unit -> Printf.fprintf h "UNIT" - | Named { id = `Parameter (_, md); expr = _ } -> - Printf.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string md) - -let type_no_parens = function - | Odoc_model.Lang.TypeExpr.Var _ | Any | Constr _ | Tuple _ -> true - | _ -> false - -let rec show_type ~path ~parens h = function - | Odoc_model.Lang.TypeExpr.Var x -> Format.fprintf h "'%s" x - | Any -> Format.fprintf h "_" - | Arrow (lbl, a, b) -> - if parens then Format.fprintf h "(" ; - Format.fprintf h "%a%a -> %a" show_label lbl - (show_type ~path ~parens:true) - a - (show_type ~path ~parens:false) - b ; - if parens then Format.fprintf h ")" - | Constr (name, []) -> Format.fprintf h "%a" (show_type_name ~path) name - | Constr (name, ([ x ] as args)) when type_no_parens x -> - Format.fprintf h "%a %a" (show_type_list ~path) args - (show_type_name ~path) name - | Constr (name, args) -> - Format.fprintf h "(%a) %a" (show_type_list ~path) args - (show_type_name ~path) name - | Tuple args -> - Format.fprintf h "(" ; - show_tuple_list ~path h args ; - Format.fprintf h ")" - | Poly (polys, t) -> - if parens then Format.fprintf h "(" ; - Format.fprintf h "%a. %a" show_polys polys - (show_type ~path ~parens:false) - t ; - if parens then Format.fprintf h ")" - | _ -> Format.fprintf h "!!todo!!" - -and show_polys h = function - | [] -> failwith "show_polys: empty list" - | [ x ] -> Format.fprintf h "'%s" x - | x :: xs -> Format.fprintf h "'%s %a" x show_polys xs - -and show_type_list ~path h = function - | [] -> failwith "empty list" - | [ x ] -> show_type ~path ~parens:false h x - | x :: xs -> - Format.fprintf h "%a, %a" - (show_type ~path ~parens:true) - x (show_type_list ~path) xs - -and show_tuple_list ~path h = function - | [] -> failwith "empty list" - | [ x ] -> show_type ~path ~parens:true h x - | x :: xs -> - Format.fprintf h "%a * %a" - (show_type ~path ~parens:true) - x (show_tuple_list ~path) xs - -let rec pp_path h = function - | [] -> Format.fprintf h "" - | x :: xs -> Format.fprintf h "%a%s." pp_path xs x diff --git a/lib/index_lib/strings.ml b/lib/index_lib/strings.ml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/strings_of_odoc/dune b/lib/strings_of_odoc/dune new file mode 100644 index 0000000000..d0a17345cf --- /dev/null +++ b/lib/strings_of_odoc/dune @@ -0,0 +1,3 @@ +(library + (name strings_of_odoc) + (libraries tyxml opam-core odoc.loader odoc.model odoc.xref2 odoc.odoc)) diff --git a/lib/strings_of_odoc/strings_of_odoc.ml b/lib/strings_of_odoc/strings_of_odoc.ml new file mode 100644 index 0000000000..092295652b --- /dev/null +++ b/lib/strings_of_odoc/strings_of_odoc.ml @@ -0,0 +1,211 @@ +open Odoc_model +open Odoc_model.Root +module ModuleName = Odoc_model.Names.ModuleName + +let string_of_identifier = function + | `Class (_, n) -> Names.ClassName.to_string n + | `ClassType (_, n) -> Names.ClassTypeName.to_string n + | `Constructor (_, n) -> Names.ConstructorName.to_string n + | `Exception (_, n) -> Names.ExceptionName.to_string n + | `Extension (_, n) -> Names.ExtensionName.to_string n + | `Field (_, n) -> Names.FieldName.to_string n + | `InstanceVariable (_, n) -> Names.InstanceVariableName.to_string n + | `Label (_, n) -> Names.LabelName.to_string n + | `Method (_, n) -> Names.MethodName.to_string n + | `Module (_, n) -> ModuleName.to_string n + | `ModuleType (_, n) -> Names.ModuleTypeName.to_string n + | `Type (_, n) -> Names.TypeName.to_string n + | `Value (_, n) -> Names.ValueName.to_string n + | _ -> "" + +let string_of_resolved = function + | `Identifier v -> string_of_identifier v + | r -> string_of_identifier r + +let string_of_reference = function + | `Root (r, _) -> r + | `Dot (_, n) -> n + | `Resolved r -> string_of_resolved r + | r -> string_of_identifier r + + + let make_root ~module_name ~digest = + let file = Odoc_file.create_unit ~force_hidden:false module_name in + Ok { id = `Root (None, ModuleName.make_std module_name); file; digest } + + let show_module_name h md = + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) + + let show_module_ident h = function + | `Module (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) + | `Root (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) + | _ -> Format.fprintf h "!!module!!" + + let rec show_module_t h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_module_ident (Resolved.Module.identifier t) + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + | `Root x -> Format.fprintf h "%s" x + | `Apply (m, _) -> Format.fprintf h "%a(_)" show_module_t m + | `Forward str -> Format.fprintf h "%s" str + | `Result _ -> () + | `Identifier _ -> () + + and show_module_path h = function + | `Identifier (`Module (_, md)) -> + Format.fprintf h "" show_module_name md + | `Identifier (`Root (_, md)) -> + Format.fprintf h "" show_module_name md + | `Identifier _ -> Format.fprintf h "" + | `Subst _ -> Format.fprintf h "" + | `Hidden _ -> Format.fprintf h "" + | `Module (pt, md) -> + Format.fprintf h "" show_module_path pt show_module_name + md + | `Canonical (pt, md) -> + Format.fprintf h "" show_module_path pt show_module_t md + | `Apply _ -> Format.fprintf h "" + | `Alias (pt, md) -> + Format.fprintf h "" show_module_path pt show_module_path md + | `OpaqueModule _ -> Format.fprintf h "" + + and show_signature h = function + | `Root (_, name) -> + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) + | `Module (pt, mdl) -> + Format.fprintf h "%a.%a" show_signature pt show_module_name mdl + | `Parameter (_, p) -> + Format.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string p) + | `Result t -> Format.fprintf h "%a" show_signature t + | `ModuleType (_, p) -> + Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) + + let show_ident_verbose h = function + | `Type (md, n) -> + Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) + | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) + | _ -> Format.fprintf h "show_ident?" + + let show_ident_short h = function + | `Type (_, n) -> Format.fprintf h "%s" (Names.TypeName.to_string n) + | `CoreType n -> Format.fprintf h "%s" (Names.TypeName.to_string n) + | _ -> Format.fprintf h "show_ident?" + + let show_type_name_verbose h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_ident_verbose (Resolved.Type.identifier t) + | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + + let show_type_name_short h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_ident_short (Resolved.Type.identifier t) + | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Dot (_mdl, x) -> Format.fprintf h "%s" x + + let strip ~prefix str = + if String.starts_with ~prefix str + then + String.sub str (String.length prefix) + (String.length str - String.length prefix) + else str + + let show_type_name ~path h t = + let blah = Format.asprintf "%a" show_type_name_verbose t in + let blah = strip ~prefix:path blah in + let blah = strip ~prefix:"Stdlib." blah in + Format.fprintf h "%s" blah + + let show_moduletype_ident h = function + | `ModuleType (_, _) -> Format.fprintf h "ident" + | _ -> Format.fprintf h "moduletype" + + let show_moduletype_name h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_moduletype_ident + (Resolved.ModuleType.identifier t) + | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + + let show_label h = function + | None -> () + | Some (Odoc_model.Lang.TypeExpr.Label lbl) -> Format.fprintf h "%s:" lbl + | Some (Optional lbl) -> Format.fprintf h "?%s:" lbl + + let show_type_id h = function + | `Type (_, name) -> Printf.fprintf h "%s" (Names.TypeName.to_string name) + | `CoreType name -> + Printf.fprintf h "(core)%s" (Names.TypeName.to_string name) + + let show_type_repr h = function + | None -> Printf.fprintf h "no repr" + | Some _ -> Printf.fprintf h "has repr" + + let show_functor_param h = function + | Lang.FunctorParameter.Unit -> Printf.fprintf h "UNIT" + | Named { id = `Parameter (_, md); expr = _ } -> + Printf.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string md) + + let type_no_parens = function + | Odoc_model.Lang.TypeExpr.Var _ | Any | Constr _ | Tuple _ -> true + | _ -> false + + let rec show_type ~path ~parens h = function + | Odoc_model.Lang.TypeExpr.Var x -> Format.fprintf h "'%s" x + | Any -> Format.fprintf h "_" + | Arrow (lbl, a, b) -> + if parens then Format.fprintf h "(" ; + Format.fprintf h "%a%a -> %a" show_label lbl + (show_type ~path ~parens:true) + a + (show_type ~path ~parens:false) + b ; + if parens then Format.fprintf h ")" + | Constr (name, []) -> Format.fprintf h "%a" (show_type_name ~path) name + | Constr (name, ([ x ] as args)) when type_no_parens x -> + Format.fprintf h "%a %a" (show_type_list ~path) args + (show_type_name ~path) name + | Constr (name, args) -> + Format.fprintf h "(%a) %a" (show_type_list ~path) args + (show_type_name ~path) name + | Tuple args -> + Format.fprintf h "(" ; + show_tuple_list ~path h args ; + Format.fprintf h ")" + | Poly (polys, t) -> + if parens then Format.fprintf h "(" ; + Format.fprintf h "%a. %a" show_polys polys + (show_type ~path ~parens:false) + t ; + if parens then Format.fprintf h ")" + | _ -> Format.fprintf h "!!todo!!" + + and show_polys h = function + | [] -> failwith "show_polys: empty list" + | [ x ] -> Format.fprintf h "'%s" x + | x :: xs -> Format.fprintf h "'%s %a" x show_polys xs + + and show_type_list ~path h = function + | [] -> failwith "empty list" + | [ x ] -> show_type ~path ~parens:false h x + | x :: xs -> + Format.fprintf h "%a, %a" + (show_type ~path ~parens:true) + x (show_type_list ~path) xs + + and show_tuple_list ~path h = function + | [] -> failwith "empty list" + | [ x ] -> show_type ~path ~parens:true h x + | x :: xs -> + Format.fprintf h "%a * %a" + (show_type ~path ~parens:true) + x (show_tuple_list ~path) xs + + let rec pp_path h = function + | [] -> Format.fprintf h "" + | x :: xs -> Format.fprintf h "%a%s." pp_path xs x + \ No newline at end of file diff --git a/www/dune b/www/dune index 6c3c567048..86912933f0 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,3 @@ (executable (name www) - (libraries cmdliner dream db query storage_marshal)) + (libraries cmdliner dream db query storage_marshal html_of_odoc)) diff --git a/www/ui.ml b/www/ui.ml index 4e6cbd4bdb..f8eccd10d6 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -6,6 +6,9 @@ let list_of_option = function let render_result r = let open Db.Types.Elt in + let doc = + (*Option.map Cache_doc.memo TODO RESTORE*) Html_of_odoc.string_of_docs r.doc + in div ~a:[ a_class [ "pkg" ] ] [ a @@ -21,7 +24,7 @@ let render_result r = ; txt " : " ; txt r.str_type ] - :: list_of_option r.doc + :: list_of_option doc let render ~pretty results = match results with From 8b99b69fa7eb9cb308bf43ab39cfbc25590deea5 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 20 Apr 2023 16:18:53 +0200 Subject: [PATCH 028/285] add cmdliner option to select database format --- index/dune | 2 +- index/index.ml | 33 ++++++++++++++++++++++++++++++--- lib/storage_ancient/dune | 2 +- www/dune | 2 +- www/www.ml | 18 ++++++++++++++---- 5 files changed, 47 insertions(+), 10 deletions(-) diff --git a/index/dune b/index/dune index 38a402f2d5..7c67dbf4ef 100644 --- a/index/dune +++ b/index/dune @@ -1,3 +1,3 @@ (executable (name index) - (libraries index_lib storage_marshal)) \ No newline at end of file + (libraries cmdliner index_lib storage_ancient storage_marshal)) diff --git a/index/index.ml b/index/index.ml index b350e23b73..7c037a2f41 100644 --- a/index/index.ml +++ b/index/index.ml @@ -1,3 +1,30 @@ -let () = - let odoc_directory = Sys.argv.(1) and db_filename = Sys.argv.(2) in - Index_lib.main ~odoc_directory ~db_filename (module Storage_marshal) +let main odoc_directory db_filename db_format = + let storage = match db_format with + | `ancient -> (module Storage_ancient : Db.Storage.S) + | `marshal -> (module Storage_marshal : Db.Storage.S) + in + Index_lib.main ~odoc_directory ~db_filename storage + +open Cmdliner + +let db_format = + let doc = "Databse format" in + let kind = Arg.enum ["ancient", `ancient; "marshal", `marshal] in + Arg.(required & opt (some kind) None & info ["format"] ~docv:"DB_FORMAT" ~doc) + +let db_filename = + let doc = "Database filename" in + Arg.(required & opt (some string) None & info ["db"] ~docv:"DB" ~doc) + +let odoc_path = + let doc = "Path to a directory containing odocl files" in + Arg.(required & opt (some dir) None & info ["odoc"] ~docv:"ODOC_FILES" ~doc) + +let index = Term.(const main $ odoc_path $ db_filename $ db_format) + +let cmd = + let doc = "Index odocl files" in + let info = Cmd.info "index" ~doc in + Cmd.v info index + +let () = exit (Cmd.eval cmd) diff --git a/lib/storage_ancient/dune b/lib/storage_ancient/dune index 03a38c297e..ecf5dc277b 100644 --- a/lib/storage_ancient/dune +++ b/lib/storage_ancient/dune @@ -1,3 +1,3 @@ (library - (name storage_ancien) + (name storage_ancient) (libraries ancient db)) diff --git a/www/dune b/www/dune index 86912933f0..31d5fbcd44 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,3 @@ (executable (name www) - (libraries cmdliner dream db query storage_marshal html_of_odoc)) + (libraries cmdliner dream db query storage_ancient storage_marshal html_of_odoc)) diff --git a/www/www.ml b/www/www.ml index ce3171e2cb..b99b06d07a 100644 --- a/www/www.ml +++ b/www/www.ml @@ -78,8 +78,13 @@ let cors_options = Dream.add_header response "Access-Control-Allow-Headers" "*" ; response) -let main db_filename cache_max_age = - let shards = Storage_marshal.load db_filename in +let main db_format db_filename cache_max_age = + let storage = match db_format with + | `ancient -> (module Storage_ancient : Db.Storage.S) + | `marshal -> (module Storage_marshal : Db.Storage.S) + in + let module Storage = (val storage) in + let shards = Storage.load db_filename in Dream.run ~interface:"127.0.0.1" ~port:1234 @@ Dream.logger @@ cache_header cache_max_age @@ cors_header @@ Dream.router @@ -100,7 +105,12 @@ let main db_filename cache_max_age = open Cmdliner -let path = +let db_format = + let doc = "Databse format" in + let kind = Arg.enum ["ancient", `ancient; "marshal", `marshal] in + Arg.(required & opt (some kind) None & info ["format"] ~docv:"DB_FORMAT" ~doc) + +let db_path = let doc = "Database filename" in Arg.(required & pos 0 (some file) None & info [] ~docv:"DB" ~doc) @@ -108,7 +118,7 @@ let cache_max_age = let doc = "HTTP cache max age (in seconds)" in Arg.(value & opt (some int) None & info [ "c"; "cache" ] ~docv:"MAX_AGE" ~doc) -let www = Term.(const main $ path $ cache_max_age) +let www = Term.(const main $ db_format $ db_path $ cache_max_age) let cmd = let doc = "Webserver for sherlodoc" in From 6198e9fc446e431dc74e809f3a71d73f397e3bb4 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 21 Apr 2023 01:39:30 +0200 Subject: [PATCH 029/285] Revert "doc comments converted to html by www" This reverts commit 9159abcbd3185945d79a2772cbc389750561cee5. --- lib/db/dune | 2 +- lib/db/types.ml | 2 +- lib/html_of_odoc/dune | 3 - lib/html_of_odoc/html_of_odoc.ml | 35 ---- lib/index_lib/dune | 1 - lib/index_lib/load_doc.ml | 32 ++-- lib/index_lib/pretty.ml | 249 +++++++++++++++++++++++++ lib/index_lib/strings.ml | 0 lib/strings_of_odoc/dune | 3 - lib/strings_of_odoc/strings_of_odoc.ml | 211 --------------------- www/dune | 2 +- www/ui.ml | 5 +- 12 files changed, 272 insertions(+), 273 deletions(-) delete mode 100644 lib/html_of_odoc/dune delete mode 100644 lib/html_of_odoc/html_of_odoc.ml create mode 100644 lib/index_lib/pretty.ml delete mode 100644 lib/index_lib/strings.ml delete mode 100644 lib/strings_of_odoc/dune delete mode 100644 lib/strings_of_odoc/strings_of_odoc.ml diff --git a/lib/db/dune b/lib/db/dune index 4f986fe704..f77b6a27ea 100644 --- a/lib/db/dune +++ b/lib/db/dune @@ -1,3 +1,3 @@ (library (name db) - (libraries unix tyxml odoc.model odoc.xref2 odoc.odoc)) + (libraries unix tyxml)) diff --git a/lib/db/types.ml b/lib/db/types.ml index 55f6e607a9..8f98e0deda 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -4,7 +4,7 @@ module Elt = struct ; name : string ; str_type : string ; type_paths : string list list - ; doc : Odoc_model.Comment.docs + ; doc : Html_types.li_content_fun Tyxml.Html.elt option ; pkg : string * string } diff --git a/lib/html_of_odoc/dune b/lib/html_of_odoc/dune deleted file mode 100644 index c80dc5d2db..0000000000 --- a/lib/html_of_odoc/dune +++ /dev/null @@ -1,3 +0,0 @@ -(library - (name html_of_odoc) - (libraries strings_of_odoc tyxml opam-core odoc.loader odoc.model odoc.xref2 odoc.odoc)) diff --git a/lib/html_of_odoc/html_of_odoc.ml b/lib/html_of_odoc/html_of_odoc.ml deleted file mode 100644 index 79021bca09..0000000000 --- a/lib/html_of_odoc/html_of_odoc.ml +++ /dev/null @@ -1,35 +0,0 @@ -module ModuleName = Odoc_model.Names.ModuleName -module H = Tyxml.Html -open Strings_of_odoc - -let rec string_of_non_link = function - | `Space -> H.txt " " - | `Word w -> H.txt w - | `Code_span s -> H.code [ H.txt s ] - | `Raw_markup (_, s) -> H.txt s - | `Styled (_, lst) -> string_of_link_content lst - -and string_of_element = function - | `Styled (_, lst) -> string_of_paragraph lst - | `Reference (r, _) -> H.code [ H.txt (string_of_reference r) ] - | `Link (_, r) -> string_of_link_content r - | `Space -> H.txt " " - | `Word w -> H.txt w - | `Code_span s -> H.code [ H.txt s ] - | `Raw_markup (_, s) -> H.txt s - -and string_of_link_content lst = - H.span - (List.map (fun r -> string_of_non_link r.Odoc_model.Location_.value) lst) - -and string_of_paragraph lst = - H.span - (List.map (fun elt -> string_of_element elt.Odoc_model.Location_.value) lst) - -let string_of_doc = function - | `Paragraph p -> Some (H.p [ string_of_paragraph p ]) - | `Heading (_, _, p) -> Some (H.p [ string_of_link_content p ]) - | _ -> None - -let string_of_docs lst = - List.find_map (fun elt -> string_of_doc elt.Odoc_model.Location_.value) lst diff --git a/lib/index_lib/dune b/lib/index_lib/dune index a53e6dd619..c512fafd21 100644 --- a/lib/index_lib/dune +++ b/lib/index_lib/dune @@ -1,7 +1,6 @@ (library (name index_lib) (libraries - strings_of_odoc db fpath tyxml diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index a1430fdd14..39f453331b 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -1,7 +1,5 @@ module Db_common = Db -open Strings_of_odoc - module Make (Storage : Db.Storage.S) = struct module Types = Db.Types module Db = Db.Make (Storage) @@ -56,7 +54,8 @@ module Make (Storage : Db.Storage.S) = struct | [] -> [] | _ :: xs as lst -> lst :: tails xs - let fullname t = Format.asprintf "%a" Strings_of_odoc.show_type_name_verbose t + let fullname t = + Pretty.fmt_to_string (fun h -> Pretty.show_type_name_verbose h t) let all_type_names t = let fullname = fullname t in @@ -78,7 +77,9 @@ module Make (Storage : Db.Storage.S) = struct | Constr (name, args) -> let name = fullname name in let prefix = - name :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix + Cache_name.memo name + :: Cache_name.memo (Types.string_of_sgn sgn) + :: prefix in begin match args with @@ -128,21 +129,26 @@ module Make (Storage : Db.Storage.S) = struct | _ -> [] let save_item ~pkg ~path_list ~path name type_ doc = - let str_type = Format.asprintf "%a%!" - (show_type - ~path:( Format.asprintf "%a" pp_path path) + let b = Buffer.create 16 in + let to_b = Format.formatter_of_buffer b in + Format.fprintf to_b "%a%!" + (Pretty.show_type + ~path:(Pretty.fmt_to_string (fun h -> Pretty.pp_path h path)) ~parens:false) - type_ in - let full_name = Format.asprintf "%a%s%!" pp_path path - (Odoc_model.Names.ValueName.to_string name) in - (* let doc = Option.map Cache_doc.memo (Pretty.string_of_docs doc) in *) + type_ ; + let str_type = Buffer.contents b in + Buffer.reset b ; + Format.fprintf to_b "%a%s%!" Pretty.pp_path path + (Odoc_model.Names.ValueName.to_string name) ; + let full_name = Buffer.contents b in + let doc = Option.map Cache_doc.memo (Pretty.string_of_docs doc) in let cost = String.length full_name + String.length str_type + (5 * List.length path) + type_size type_ - + (*(match doc with + + (match doc with | None -> 1000 - | _ -> 0) TODO UNDERSTAND *) + | _ -> 0) + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 in let paths = paths ~prefix:[] ~sgn:Pos type_ in diff --git a/lib/index_lib/pretty.ml b/lib/index_lib/pretty.ml new file mode 100644 index 0000000000..14353570b3 --- /dev/null +++ b/lib/index_lib/pretty.ml @@ -0,0 +1,249 @@ +open Odoc_model +open Odoc_model.Root +module ModuleName = Odoc_model.Names.ModuleName +module H = Tyxml.Html + +let fmt_to_string f = + let b = Buffer.create 16 in + let to_b = Format.formatter_of_buffer b in + f to_b ; + Format.fprintf to_b "%!" ; + Buffer.contents b + +let string_of_identifier = function + | `Class (_, n) -> Names.ClassName.to_string n + | `ClassType (_, n) -> Names.ClassTypeName.to_string n + | `Constructor (_, n) -> Names.ConstructorName.to_string n + | `Exception (_, n) -> Names.ExceptionName.to_string n + | `Extension (_, n) -> Names.ExtensionName.to_string n + | `Field (_, n) -> Names.FieldName.to_string n + | `InstanceVariable (_, n) -> Names.InstanceVariableName.to_string n + | `Label (_, n) -> Names.LabelName.to_string n + | `Method (_, n) -> Names.MethodName.to_string n + | `Module (_, n) -> ModuleName.to_string n + | `ModuleType (_, n) -> Names.ModuleTypeName.to_string n + | `Type (_, n) -> Names.TypeName.to_string n + | `Value (_, n) -> Names.ValueName.to_string n + | _ -> "" + +let string_of_resolved = function + | `Identifier v -> string_of_identifier v + | r -> string_of_identifier r + +let string_of_reference = function + | `Root (r, _) -> r + | `Dot (_, n) -> n + | `Resolved r -> string_of_resolved r + | r -> string_of_identifier r + +let rec string_of_non_link = function + | `Space -> H.txt " " + | `Word w -> H.txt w + | `Code_span s -> H.code [ H.txt s ] + | `Raw_markup (_, s) -> H.txt s + | `Styled (_, lst) -> string_of_link_content lst + +and string_of_element = function + | `Styled (_, lst) -> string_of_paragraph lst + | `Reference (r, _) -> H.code [ H.txt (string_of_reference r) ] + | `Link (_, r) -> string_of_link_content r + | `Space -> H.txt " " + | `Word w -> H.txt w + | `Code_span s -> H.code [ H.txt s ] + | `Raw_markup (_, s) -> H.txt s + +and string_of_link_content lst = + H.span + (List.map (fun r -> string_of_non_link r.Odoc_model.Location_.value) lst) + +and string_of_paragraph lst = + H.span + (List.map (fun elt -> string_of_element elt.Odoc_model.Location_.value) lst) + +let string_of_doc = function + | `Paragraph p -> Some (H.p [ string_of_paragraph p ]) + | `Heading (_, _, p) -> Some (H.p [ string_of_link_content p ]) + | _ -> None + +let string_of_docs lst = + List.find_map (fun elt -> string_of_doc elt.Odoc_model.Location_.value) lst + +let make_root ~module_name ~digest = + let file = Odoc_file.create_unit ~force_hidden:false module_name in + Ok { id = `Root (None, ModuleName.make_std module_name); file; digest } + +let show_module_name h md = + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) + +let show_module_ident h = function + | `Module (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) + | `Root (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) + | _ -> Format.fprintf h "!!module!!" + +let rec show_module_t h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_module_ident (Resolved.Module.identifier t) + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + | `Root x -> Format.fprintf h "%s" x + | `Apply (m, _) -> Format.fprintf h "%a(_)" show_module_t m + | `Forward str -> Format.fprintf h "%s" str + | `Result _ -> () + | `Identifier _ -> () + +and show_module_path h = function + | `Identifier (`Module (_, md)) -> + Format.fprintf h "" show_module_name md + | `Identifier (`Root (_, md)) -> + Format.fprintf h "" show_module_name md + | `Identifier _ -> Format.fprintf h "" + | `Subst _ -> Format.fprintf h "" + | `Hidden _ -> Format.fprintf h "" + | `Module (pt, md) -> + Format.fprintf h "" show_module_path pt show_module_name + md + | `Canonical (pt, md) -> + Format.fprintf h "" show_module_path pt show_module_t md + | `Apply _ -> Format.fprintf h "" + | `Alias (pt, md) -> + Format.fprintf h "" show_module_path pt show_module_path md + | `OpaqueModule _ -> Format.fprintf h "" + +and show_signature h = function + | `Root (_, name) -> + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) + | `Module (pt, mdl) -> + Format.fprintf h "%a.%a" show_signature pt show_module_name mdl + | `Parameter (_, p) -> + Format.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string p) + | `Result t -> Format.fprintf h "%a" show_signature t + | `ModuleType (_, p) -> + Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) + +let show_ident_verbose h = function + | `Type (md, n) -> + Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) + | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) + | _ -> Format.fprintf h "show_ident?" + +let show_ident_short h = function + | `Type (_, n) -> Format.fprintf h "%s" (Names.TypeName.to_string n) + | `CoreType n -> Format.fprintf h "%s" (Names.TypeName.to_string n) + | _ -> Format.fprintf h "show_ident?" + +let show_type_name_verbose h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_ident_verbose (Resolved.Type.identifier t) + | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + +let show_type_name_short h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_ident_short (Resolved.Type.identifier t) + | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Dot (_mdl, x) -> Format.fprintf h "%s" x + +let strip ~prefix str = + if String.starts_with ~prefix str + then + String.sub str (String.length prefix) + (String.length str - String.length prefix) + else str + +let show_type_name ~path h t = + let blah = fmt_to_string (fun h -> show_type_name_verbose h t) in + let blah = strip ~prefix:path blah in + let blah = strip ~prefix:"Stdlib." blah in + Format.fprintf h "%s" blah + +let show_moduletype_ident h = function + | `ModuleType (_, _) -> Format.fprintf h "ident" + | _ -> Format.fprintf h "moduletype" + +let show_moduletype_name h = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_moduletype_ident + (Resolved.ModuleType.identifier t) + | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + +let show_label h = function + | None -> () + | Some (Odoc_model.Lang.TypeExpr.Label lbl) -> Format.fprintf h "%s:" lbl + | Some (Optional lbl) -> Format.fprintf h "?%s:" lbl + +let show_type_id h = function + | `Type (_, name) -> Printf.fprintf h "%s" (Names.TypeName.to_string name) + | `CoreType name -> + Printf.fprintf h "(core)%s" (Names.TypeName.to_string name) + +let show_type_repr h = function + | None -> Printf.fprintf h "no repr" + | Some _ -> Printf.fprintf h "has repr" + +let show_functor_param h = function + | Lang.FunctorParameter.Unit -> Printf.fprintf h "UNIT" + | Named { id = `Parameter (_, md); expr = _ } -> + Printf.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string md) + +let type_no_parens = function + | Odoc_model.Lang.TypeExpr.Var _ | Any | Constr _ | Tuple _ -> true + | _ -> false + +let rec show_type ~path ~parens h = function + | Odoc_model.Lang.TypeExpr.Var x -> Format.fprintf h "'%s" x + | Any -> Format.fprintf h "_" + | Arrow (lbl, a, b) -> + if parens then Format.fprintf h "(" ; + Format.fprintf h "%a%a -> %a" show_label lbl + (show_type ~path ~parens:true) + a + (show_type ~path ~parens:false) + b ; + if parens then Format.fprintf h ")" + | Constr (name, []) -> Format.fprintf h "%a" (show_type_name ~path) name + | Constr (name, ([ x ] as args)) when type_no_parens x -> + Format.fprintf h "%a %a" (show_type_list ~path) args + (show_type_name ~path) name + | Constr (name, args) -> + Format.fprintf h "(%a) %a" (show_type_list ~path) args + (show_type_name ~path) name + | Tuple args -> + Format.fprintf h "(" ; + show_tuple_list ~path h args ; + Format.fprintf h ")" + | Poly (polys, t) -> + if parens then Format.fprintf h "(" ; + Format.fprintf h "%a. %a" show_polys polys + (show_type ~path ~parens:false) + t ; + if parens then Format.fprintf h ")" + | _ -> Format.fprintf h "!!todo!!" + +and show_polys h = function + | [] -> failwith "show_polys: empty list" + | [ x ] -> Format.fprintf h "'%s" x + | x :: xs -> Format.fprintf h "'%s %a" x show_polys xs + +and show_type_list ~path h = function + | [] -> failwith "empty list" + | [ x ] -> show_type ~path ~parens:false h x + | x :: xs -> + Format.fprintf h "%a, %a" + (show_type ~path ~parens:true) + x (show_type_list ~path) xs + +and show_tuple_list ~path h = function + | [] -> failwith "empty list" + | [ x ] -> show_type ~path ~parens:true h x + | x :: xs -> + Format.fprintf h "%a * %a" + (show_type ~path ~parens:true) + x (show_tuple_list ~path) xs + +let rec pp_path h = function + | [] -> Format.fprintf h "" + | x :: xs -> Format.fprintf h "%a%s." pp_path xs x diff --git a/lib/index_lib/strings.ml b/lib/index_lib/strings.ml deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lib/strings_of_odoc/dune b/lib/strings_of_odoc/dune deleted file mode 100644 index d0a17345cf..0000000000 --- a/lib/strings_of_odoc/dune +++ /dev/null @@ -1,3 +0,0 @@ -(library - (name strings_of_odoc) - (libraries tyxml opam-core odoc.loader odoc.model odoc.xref2 odoc.odoc)) diff --git a/lib/strings_of_odoc/strings_of_odoc.ml b/lib/strings_of_odoc/strings_of_odoc.ml deleted file mode 100644 index 092295652b..0000000000 --- a/lib/strings_of_odoc/strings_of_odoc.ml +++ /dev/null @@ -1,211 +0,0 @@ -open Odoc_model -open Odoc_model.Root -module ModuleName = Odoc_model.Names.ModuleName - -let string_of_identifier = function - | `Class (_, n) -> Names.ClassName.to_string n - | `ClassType (_, n) -> Names.ClassTypeName.to_string n - | `Constructor (_, n) -> Names.ConstructorName.to_string n - | `Exception (_, n) -> Names.ExceptionName.to_string n - | `Extension (_, n) -> Names.ExtensionName.to_string n - | `Field (_, n) -> Names.FieldName.to_string n - | `InstanceVariable (_, n) -> Names.InstanceVariableName.to_string n - | `Label (_, n) -> Names.LabelName.to_string n - | `Method (_, n) -> Names.MethodName.to_string n - | `Module (_, n) -> ModuleName.to_string n - | `ModuleType (_, n) -> Names.ModuleTypeName.to_string n - | `Type (_, n) -> Names.TypeName.to_string n - | `Value (_, n) -> Names.ValueName.to_string n - | _ -> "" - -let string_of_resolved = function - | `Identifier v -> string_of_identifier v - | r -> string_of_identifier r - -let string_of_reference = function - | `Root (r, _) -> r - | `Dot (_, n) -> n - | `Resolved r -> string_of_resolved r - | r -> string_of_identifier r - - - let make_root ~module_name ~digest = - let file = Odoc_file.create_unit ~force_hidden:false module_name in - Ok { id = `Root (None, ModuleName.make_std module_name); file; digest } - - let show_module_name h md = - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) - - let show_module_ident h = function - | `Module (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) - | `Root (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) - | _ -> Format.fprintf h "!!module!!" - - let rec show_module_t h = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_module_ident (Resolved.Module.identifier t) - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x - | `Root x -> Format.fprintf h "%s" x - | `Apply (m, _) -> Format.fprintf h "%a(_)" show_module_t m - | `Forward str -> Format.fprintf h "%s" str - | `Result _ -> () - | `Identifier _ -> () - - and show_module_path h = function - | `Identifier (`Module (_, md)) -> - Format.fprintf h "" show_module_name md - | `Identifier (`Root (_, md)) -> - Format.fprintf h "" show_module_name md - | `Identifier _ -> Format.fprintf h "" - | `Subst _ -> Format.fprintf h "" - | `Hidden _ -> Format.fprintf h "" - | `Module (pt, md) -> - Format.fprintf h "" show_module_path pt show_module_name - md - | `Canonical (pt, md) -> - Format.fprintf h "" show_module_path pt show_module_t md - | `Apply _ -> Format.fprintf h "" - | `Alias (pt, md) -> - Format.fprintf h "" show_module_path pt show_module_path md - | `OpaqueModule _ -> Format.fprintf h "" - - and show_signature h = function - | `Root (_, name) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) - | `Module (pt, mdl) -> - Format.fprintf h "%a.%a" show_signature pt show_module_name mdl - | `Parameter (_, p) -> - Format.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string p) - | `Result t -> Format.fprintf h "%a" show_signature t - | `ModuleType (_, p) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) - - let show_ident_verbose h = function - | `Type (md, n) -> - Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) - | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) - | _ -> Format.fprintf h "show_ident?" - - let show_ident_short h = function - | `Type (_, n) -> Format.fprintf h "%s" (Names.TypeName.to_string n) - | `CoreType n -> Format.fprintf h "%s" (Names.TypeName.to_string n) - | _ -> Format.fprintf h "show_ident?" - - let show_type_name_verbose h = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_ident_verbose (Resolved.Type.identifier t) - | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x - - let show_type_name_short h = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_ident_short (Resolved.Type.identifier t) - | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b - | `Dot (_mdl, x) -> Format.fprintf h "%s" x - - let strip ~prefix str = - if String.starts_with ~prefix str - then - String.sub str (String.length prefix) - (String.length str - String.length prefix) - else str - - let show_type_name ~path h t = - let blah = Format.asprintf "%a" show_type_name_verbose t in - let blah = strip ~prefix:path blah in - let blah = strip ~prefix:"Stdlib." blah in - Format.fprintf h "%s" blah - - let show_moduletype_ident h = function - | `ModuleType (_, _) -> Format.fprintf h "ident" - | _ -> Format.fprintf h "moduletype" - - let show_moduletype_name h = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_moduletype_ident - (Resolved.ModuleType.identifier t) - | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x - - let show_label h = function - | None -> () - | Some (Odoc_model.Lang.TypeExpr.Label lbl) -> Format.fprintf h "%s:" lbl - | Some (Optional lbl) -> Format.fprintf h "?%s:" lbl - - let show_type_id h = function - | `Type (_, name) -> Printf.fprintf h "%s" (Names.TypeName.to_string name) - | `CoreType name -> - Printf.fprintf h "(core)%s" (Names.TypeName.to_string name) - - let show_type_repr h = function - | None -> Printf.fprintf h "no repr" - | Some _ -> Printf.fprintf h "has repr" - - let show_functor_param h = function - | Lang.FunctorParameter.Unit -> Printf.fprintf h "UNIT" - | Named { id = `Parameter (_, md); expr = _ } -> - Printf.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string md) - - let type_no_parens = function - | Odoc_model.Lang.TypeExpr.Var _ | Any | Constr _ | Tuple _ -> true - | _ -> false - - let rec show_type ~path ~parens h = function - | Odoc_model.Lang.TypeExpr.Var x -> Format.fprintf h "'%s" x - | Any -> Format.fprintf h "_" - | Arrow (lbl, a, b) -> - if parens then Format.fprintf h "(" ; - Format.fprintf h "%a%a -> %a" show_label lbl - (show_type ~path ~parens:true) - a - (show_type ~path ~parens:false) - b ; - if parens then Format.fprintf h ")" - | Constr (name, []) -> Format.fprintf h "%a" (show_type_name ~path) name - | Constr (name, ([ x ] as args)) when type_no_parens x -> - Format.fprintf h "%a %a" (show_type_list ~path) args - (show_type_name ~path) name - | Constr (name, args) -> - Format.fprintf h "(%a) %a" (show_type_list ~path) args - (show_type_name ~path) name - | Tuple args -> - Format.fprintf h "(" ; - show_tuple_list ~path h args ; - Format.fprintf h ")" - | Poly (polys, t) -> - if parens then Format.fprintf h "(" ; - Format.fprintf h "%a. %a" show_polys polys - (show_type ~path ~parens:false) - t ; - if parens then Format.fprintf h ")" - | _ -> Format.fprintf h "!!todo!!" - - and show_polys h = function - | [] -> failwith "show_polys: empty list" - | [ x ] -> Format.fprintf h "'%s" x - | x :: xs -> Format.fprintf h "'%s %a" x show_polys xs - - and show_type_list ~path h = function - | [] -> failwith "empty list" - | [ x ] -> show_type ~path ~parens:false h x - | x :: xs -> - Format.fprintf h "%a, %a" - (show_type ~path ~parens:true) - x (show_type_list ~path) xs - - and show_tuple_list ~path h = function - | [] -> failwith "empty list" - | [ x ] -> show_type ~path ~parens:true h x - | x :: xs -> - Format.fprintf h "%a * %a" - (show_type ~path ~parens:true) - x (show_tuple_list ~path) xs - - let rec pp_path h = function - | [] -> Format.fprintf h "" - | x :: xs -> Format.fprintf h "%a%s." pp_path xs x - \ No newline at end of file diff --git a/www/dune b/www/dune index 31d5fbcd44..cc56b73a47 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,3 @@ (executable (name www) - (libraries cmdliner dream db query storage_ancient storage_marshal html_of_odoc)) + (libraries cmdliner dream db query storage_ancient storage_marshal)) diff --git a/www/ui.ml b/www/ui.ml index f8eccd10d6..4e6cbd4bdb 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -6,9 +6,6 @@ let list_of_option = function let render_result r = let open Db.Types.Elt in - let doc = - (*Option.map Cache_doc.memo TODO RESTORE*) Html_of_odoc.string_of_docs r.doc - in div ~a:[ a_class [ "pkg" ] ] [ a @@ -24,7 +21,7 @@ let render_result r = ; txt " : " ; txt r.str_type ] - :: list_of_option doc + :: list_of_option r.doc let render ~pretty results = match results with From 8310f36e57513f794e8cbfa5b4706d2870a31323 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 21 Apr 2023 01:46:09 +0200 Subject: [PATCH 030/285] load js db from external file --- JSherlodoc/dune | 7 +++---- JSherlodoc/index.html | 5 +++-- JSherlodoc/main.ml | 6 ++---- index/dune | 2 +- index/index.ml | 3 ++- lib/storage_js/dune | 3 +++ lib/storage_js/storage_js.ml | 12 ++++++++++++ lib/storage_js/storage_js.mli | 1 + 8 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 lib/storage_js/dune create mode 100644 lib/storage_js/storage_js.ml create mode 100644 lib/storage_js/storage_js.mli diff --git a/JSherlodoc/dune b/JSherlodoc/dune index 165c0731c9..9c7459a93b 100644 --- a/JSherlodoc/dune +++ b/JSherlodoc/dune @@ -1,7 +1,6 @@ (executable (name main) (modes js) - (libraries brr query js_of_ocaml-lwt) - (preprocess (pps ppx_blob js_of_ocaml-ppx)) - (preprocessor_deps result.db) - ) \ No newline at end of file + (libraries query storage_js brr js_of_ocaml-lwt) + (preprocess (pps js_of_ocaml-ppx))) + diff --git a/JSherlodoc/index.html b/JSherlodoc/index.html index b8a3604eb4..dc2763e938 100644 --- a/JSherlodoc/index.html +++ b/JSherlodoc/index.html @@ -3,11 +3,12 @@ - + + JSherlodoc
- \ No newline at end of file + diff --git a/JSherlodoc/main.ml b/JSherlodoc/main.ml index 2b664f6253..2d7f56e0b8 100644 --- a/JSherlodoc/main.ml +++ b/JSherlodoc/main.ml @@ -1,5 +1,4 @@ -let test = [%blob "odoc_result.db"] -let shards = [ Marshal.from_string test 0 ] +let db = Storage_js.load Jv.(to_string @@ get global "sherlodb") open Brr open Lwt @@ -7,9 +6,8 @@ open Syntax let search input _event = let query = El.prop El.Prop.value input |> Jstr.to_string in - let+ pretty_query, results = - Query.(api ~shards { query; packages = []; limit = 10 }) + Query.(api ~shards:db { query; packages = []; limit = 10 }) in let names = List.map (fun r -> r.Db.Elt.name) results in let names = String.concat " ; " names in diff --git a/index/dune b/index/dune index 7c67dbf4ef..a507d75d07 100644 --- a/index/dune +++ b/index/dune @@ -1,3 +1,3 @@ (executable (name index) - (libraries cmdliner index_lib storage_ancient storage_marshal)) + (libraries cmdliner index_lib storage_ancient storage_marshal storage_js)) diff --git a/index/index.ml b/index/index.ml index 7c037a2f41..135dc235bf 100644 --- a/index/index.ml +++ b/index/index.ml @@ -2,6 +2,7 @@ let main odoc_directory db_filename db_format = let storage = match db_format with | `ancient -> (module Storage_ancient : Db.Storage.S) | `marshal -> (module Storage_marshal : Db.Storage.S) + | `js -> (module Storage_js : Db.Storage.S) in Index_lib.main ~odoc_directory ~db_filename storage @@ -9,7 +10,7 @@ open Cmdliner let db_format = let doc = "Databse format" in - let kind = Arg.enum ["ancient", `ancient; "marshal", `marshal] in + let kind = Arg.enum ["ancient", `ancient; "marshal", `marshal; "js", `js] in Arg.(required & opt (some kind) None & info ["format"] ~docv:"DB_FORMAT" ~doc) let db_filename = diff --git a/lib/storage_js/dune b/lib/storage_js/dune new file mode 100644 index 0000000000..0a445d85c9 --- /dev/null +++ b/lib/storage_js/dune @@ -0,0 +1,3 @@ +(library + (name storage_js) + (libraries db base64)) diff --git a/lib/storage_js/storage_js.ml b/lib/storage_js/storage_js.ml new file mode 100644 index 0000000000..56df60efcc --- /dev/null +++ b/lib/storage_js/storage_js.ml @@ -0,0 +1,12 @@ +type writer = out_channel + +let open_out = open_out +let close_out = close_out +let save ~db t = + let str = Marshal.to_string t [] in + let str = Base64.encode_string str in + Printf.fprintf db "sherlodb=%S;\n%!" str + +let load str = + let str = Base64.decode_exn str in + [Marshal.from_string str 0] diff --git a/lib/storage_js/storage_js.mli b/lib/storage_js/storage_js.mli new file mode 100644 index 0000000000..bf1293dcd8 --- /dev/null +++ b/lib/storage_js/storage_js.mli @@ -0,0 +1 @@ +include Db.Storage.S From 19138e829aaaf345993117e0da6966da467cd7e9 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 21 Apr 2023 15:24:06 +0200 Subject: [PATCH 031/285] api webserver --- api/dune | 4 +++ api/main.ml | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 api/dune create mode 100644 api/main.ml diff --git a/api/dune b/api/dune new file mode 100644 index 0000000000..722c31f078 --- /dev/null +++ b/api/dune @@ -0,0 +1,4 @@ +(executable + (name main) + (public_name sherlodoc_api) + (libraries cmdliner dream db query storage_marshal html_of_odoc)) \ No newline at end of file diff --git a/api/main.ml b/api/main.ml new file mode 100644 index 0000000000..cb8419c85b --- /dev/null +++ b/api/main.ml @@ -0,0 +1,93 @@ +module Storage = Db.Storage +module Succ = Query.Succ +module Sort = Query.Sort +open Lwt.Syntax +module H = Tyxml.Html + +let api ~shards params = + let+ r = Query.api ~shards params in + Marshal.to_string r [] + +open Lwt.Syntax + +let get_query params = Option.value ~default:"" (Dream.query params "q") + +let get_packages params = + match Dream.query params "packages" with + | None -> [] + | Some str -> String.split_on_char ',' str + +let get_limit params = + let default = 100 in + match Dream.query params "limit" with + | None -> default + | Some str -> ( + try max 1 (min default (int_of_string str)) with _ -> default) + +let get_params params = + { Query.query = get_query params + ; packages = get_packages params + ; limit = get_limit params + } + +let root fn params = + let params = get_params params in + let* result = fn params in + Dream.respond result + +let string_of_tyxml html = Format.asprintf "%a" (Tyxml.Html.pp ()) html +let string_of_tyxml' html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) html + +let cache_header : int option -> Dream.middleware = + fun max_age f req -> + let+ response = f req in + begin + match max_age with + | None -> () + | Some max_age -> + Dream.add_header response "Cache-Control" + ("public, max-age=" ^ string_of_int max_age) + end ; + response + +let cors_header f req = + let+ response = f req in + Dream.add_header response "Access-Control-Allow-Origin" "*" ; + response + +let cors_options = + Dream.options "**" (fun _ -> + let+ response = Dream.empty `No_Content in + Dream.add_header response "Access-Control-Allow-Methods" "GET, OPTIONS" ; + Dream.add_header response "Access-Control-Allow-Headers" "*" ; + response) + +let main port db_filename cache_max_age = + let shards = Storage_marshal.load db_filename in + Dream.run ~interface:"127.0.0.1" ~port + @@ Dream.logger @@ cache_header cache_max_age @@ cors_header + @@ Dream.router + [ Dream.get "/" (root (fun params -> api ~shards params)); cors_options ] + +open Cmdliner + +let path = + let doc = "Database filename" in + Arg.(required & pos 0 (some file) None & info [] ~docv:"DB" ~doc) + +let port = + let doc = "Port" in + Arg.(value & opt int 1234 & info [] ~docv:"PORT" ~doc) + +let cache_max_age = + let doc = "HTTP cache max age (in seconds)" in + Arg.(value & opt (some int) None & info [ "c"; "cache" ] ~docv:"MAX_AGE" ~doc) + +let www = Term.(const main $ port $ path $ cache_max_age) + +let cmd = + let doc = "API for sherlodoc" in + let info = Cmd.info "shelodoc_api" ~doc in + Cmd.v info www + +let () = exit (Cmd.eval cmd) From d0078cd08e6e14afae3140655c695213efee6328 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 21 Apr 2023 15:29:53 +0200 Subject: [PATCH 032/285] move executables in bin folder --- {JSherlodoc => bin/JSherlodoc}/dune | 0 {JSherlodoc => bin/JSherlodoc}/index.html | 0 {JSherlodoc => bin/JSherlodoc}/main.ml | 0 {JSherlodoc => bin/JSherlodoc}/result.db | Bin {api => bin/api}/dune | 0 {api => bin/api}/main.ml | 0 {index => bin/index}/dune | 0 {index => bin/index}/index.ml | 0 {www => bin/www}/dune | 0 {www => bin/www}/packages.ml | 0 {www => bin/www}/ui.ml | 0 {www => bin/www}/www.ml | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename {JSherlodoc => bin/JSherlodoc}/dune (100%) rename {JSherlodoc => bin/JSherlodoc}/index.html (100%) rename {JSherlodoc => bin/JSherlodoc}/main.ml (100%) rename {JSherlodoc => bin/JSherlodoc}/result.db (100%) rename {api => bin/api}/dune (100%) rename {api => bin/api}/main.ml (100%) rename {index => bin/index}/dune (100%) rename {index => bin/index}/index.ml (100%) rename {www => bin/www}/dune (100%) rename {www => bin/www}/packages.ml (100%) rename {www => bin/www}/ui.ml (100%) rename {www => bin/www}/www.ml (100%) diff --git a/JSherlodoc/dune b/bin/JSherlodoc/dune similarity index 100% rename from JSherlodoc/dune rename to bin/JSherlodoc/dune diff --git a/JSherlodoc/index.html b/bin/JSherlodoc/index.html similarity index 100% rename from JSherlodoc/index.html rename to bin/JSherlodoc/index.html diff --git a/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml similarity index 100% rename from JSherlodoc/main.ml rename to bin/JSherlodoc/main.ml diff --git a/JSherlodoc/result.db b/bin/JSherlodoc/result.db similarity index 100% rename from JSherlodoc/result.db rename to bin/JSherlodoc/result.db diff --git a/api/dune b/bin/api/dune similarity index 100% rename from api/dune rename to bin/api/dune diff --git a/api/main.ml b/bin/api/main.ml similarity index 100% rename from api/main.ml rename to bin/api/main.ml diff --git a/index/dune b/bin/index/dune similarity index 100% rename from index/dune rename to bin/index/dune diff --git a/index/index.ml b/bin/index/index.ml similarity index 100% rename from index/index.ml rename to bin/index/index.ml diff --git a/www/dune b/bin/www/dune similarity index 100% rename from www/dune rename to bin/www/dune diff --git a/www/packages.ml b/bin/www/packages.ml similarity index 100% rename from www/packages.ml rename to bin/www/packages.ml diff --git a/www/ui.ml b/bin/www/ui.ml similarity index 100% rename from www/ui.ml rename to bin/www/ui.ml diff --git a/www/www.ml b/bin/www/www.ml similarity index 100% rename from www/www.ml rename to bin/www/www.ml From 30a89cf0f5a5a8aa03c4c9e788e1cbe17cbd86ce Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 21 Apr 2023 15:59:50 +0200 Subject: [PATCH 033/285] fix dune --- bin/api/dune | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/api/dune b/bin/api/dune index 722c31f078..f630c01b88 100644 --- a/bin/api/dune +++ b/bin/api/dune @@ -1,4 +1,4 @@ (executable (name main) (public_name sherlodoc_api) - (libraries cmdliner dream db query storage_marshal html_of_odoc)) \ No newline at end of file + (libraries cmdliner dream db query storage_marshal)) From 67c9034c650d80410a96e891c4a068ab24e9d501 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 21 Apr 2023 17:26:50 +0200 Subject: [PATCH 034/285] docstring in results --- bin/JSherlodoc/dune | 2 +- bin/JSherlodoc/index.html | 4 +-- bin/JSherlodoc/main.ml | 27 +++++++++++++--- lib/index_lib/docstring.ml | 61 +++++++++++++++++++++++++++++++++++++ lib/index_lib/docstring.mli | 1 + lib/index_lib/load_doc.ml | 9 ++++++ lib/query/sort.ml | 4 ++- 7 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 lib/index_lib/docstring.ml create mode 100644 lib/index_lib/docstring.mli diff --git a/bin/JSherlodoc/dune b/bin/JSherlodoc/dune index 9c7459a93b..ea5ccb9143 100644 --- a/bin/JSherlodoc/dune +++ b/bin/JSherlodoc/dune @@ -1,6 +1,6 @@ (executable (name main) (modes js) - (libraries query storage_js brr js_of_ocaml-lwt) + (libraries tyxml query storage_js brr js_of_ocaml-lwt) (preprocess (pps js_of_ocaml-ppx))) diff --git a/bin/JSherlodoc/index.html b/bin/JSherlodoc/index.html index dc2763e938..5f4906f96f 100644 --- a/bin/JSherlodoc/index.html +++ b/bin/JSherlodoc/index.html @@ -3,8 +3,8 @@ - - + + JSherlodoc diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 2d7f56e0b8..f23f8b4123 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -6,15 +6,32 @@ open Syntax let search input _event = let query = El.prop El.Prop.value input |> Jstr.to_string in - let+ pretty_query, results = - Query.(api ~shards:db { query; packages = []; limit = 10 }) + let+ _pretty_query, results = + Query.(api ~shards:db { query; packages = []; limit = 50 }) in - let names = List.map (fun r -> r.Db.Elt.name) results in - let names = String.concat " ; " names in + let results = + results + |> List.map (fun elt -> + El.( + div + ([ p + ~at:At.[ style (Jstr.of_string "color:red") ] + [ txt' elt.Db.Elt.name ] + ] + @ + match elt.Db.Elt.doc with + | None -> [] + | Some doc -> + [ p + [ txt' @@ Format.asprintf "%a" (Tyxml.Html.pp_elt ()) doc + ] + ]))) + in + let results_div = Document.find_el_by_id G.document (Jstr.of_string "results") |> Option.get in - El.set_children results_div El.[ txt' (pretty_query ^ " => " ^ names) ] + El.set_children results_div results let search input event = Js_of_ocaml_lwt.Lwt_js_events.async (fun () -> search input event) diff --git a/lib/index_lib/docstring.ml b/lib/index_lib/docstring.ml new file mode 100644 index 0000000000..6839742d07 --- /dev/null +++ b/lib/index_lib/docstring.ml @@ -0,0 +1,61 @@ +open Odoc_model + +let words_of_string s = String.split_on_char ' ' s + +let words_of_identifier = function + | `Class (_, n) -> [ Names.ClassName.to_string n ] + | `ClassType (_, n) -> [ Names.ClassTypeName.to_string n ] + | `Constructor (_, n) -> [ Names.ConstructorName.to_string n ] + | `Exception (_, n) -> [ Names.ExceptionName.to_string n ] + | `Extension (_, n) -> [ Names.ExtensionName.to_string n ] + | `Field (_, n) -> [ Names.FieldName.to_string n ] + | `InstanceVariable (_, n) -> [ Names.InstanceVariableName.to_string n ] + | `Label (_, n) -> [ Names.LabelName.to_string n ] + | `Method (_, n) -> [ Names.MethodName.to_string n ] + | `Module (_, n) -> [ Names.ModuleName.to_string n ] + | `ModuleType (_, n) -> [ Names.ModuleTypeName.to_string n ] + | `Type (_, n) -> [ Names.TypeName.to_string n ] + | `Value (_, n) -> [ Names.ValueName.to_string n ] + | _ -> [] + +let words_of_resolved = function + | `Identifier v -> words_of_identifier v + | r -> words_of_identifier r + +let words_of_reference = function + | `Root (r, _) -> [r] + | `Dot (_, n) -> [n] + | `Resolved r -> words_of_resolved r + | r -> words_of_identifier r + +let rec words_of_non_link = function + | `Space -> [] + | `Word w -> [ w ] + | `Code_span s -> words_of_string s + | `Raw_markup (_, _s) -> [] + | `Styled (_, lst) -> words_of_link_content lst + +and words_of_element = function + | `Styled (_, lst) -> words_of_paragraph lst + | `Reference (r, _) -> words_of_reference r + | `Link (_, r) -> words_of_link_content r + | `Space -> [] + | `Word w -> [ w ] + | `Code_span s -> words_of_string s + | `Raw_markup (_, _s) -> [] + +and words_of_link_content lst = + List.concat_map (fun r -> words_of_non_link r.Odoc_model.Location_.value) lst + +and words_of_paragraph lst = + List.concat_map + (fun elt -> words_of_element elt.Odoc_model.Location_.value) + lst + +let words_of_doc = function + | `Paragraph p -> words_of_paragraph p + | `Heading (_, _, p) -> words_of_link_content p + | _ -> [] + +let words_of_docs lst = + List.concat_map (fun elt -> words_of_doc elt.Odoc_model.Location_.value) lst diff --git a/lib/index_lib/docstring.mli b/lib/index_lib/docstring.mli new file mode 100644 index 0000000000..1cdfaaffea --- /dev/null +++ b/lib/index_lib/docstring.mli @@ -0,0 +1 @@ +val words_of_docs : Odoc_model.Comment.docs -> string list diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 39f453331b..7e44f707c2 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -141,6 +141,9 @@ module Make (Storage : Db.Storage.S) = struct Format.fprintf to_b "%a%s%!" Pretty.pp_path path (Odoc_model.Names.ValueName.to_string name) ; let full_name = Buffer.contents b in + let doc_words = + doc |> Docstring.words_of_docs |> List.sort_uniq String.compare + in let doc = Option.map Cache_doc.memo (Pretty.string_of_docs doc) in let cost = String.length full_name + String.length str_type @@ -161,6 +164,11 @@ module Make (Storage : Db.Storage.S) = struct ; pkg } in + List.iter + (fun word -> + let word = word |> Db_common.list_of_string |> List.rev in + Db.store_name word str_type) + doc_words ; let my_full_name = List.rev_append (Db_common.list_of_string (Odoc_model.Names.ValueName.to_string name)) @@ -168,6 +176,7 @@ module Make (Storage : Db.Storage.S) = struct in let my_full_name = List.map Char.lowercase_ascii my_full_name in Db.store_name my_full_name str_type ; + let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in Db.store_all str_type (List.map (List.map Cache_name.memo) type_paths) diff --git a/lib/query/sort.ml b/lib/query/sort.ml index 2256d81d30..4ca6f14105 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -17,7 +17,9 @@ let score_name query_name name = else if is_substring ~sub:("_" ^ query_name) name || is_substring ~sub:(query_name ^ "_") name then 3 - else 4 + else if is_substring ~sub:query_name name + then 4 + else (* Matches only in the docstring are always worse *) 2000 let score_name query_name name = match score_name query_name name with From a02abfeb6f48ec31a76f4f8002fc69d49994e928 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 21 Apr 2023 17:34:06 +0200 Subject: [PATCH 035/285] lower case docstrings --- lib/index_lib/load_doc.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 7e44f707c2..5446861bab 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -166,7 +166,9 @@ module Make (Storage : Db.Storage.S) = struct in List.iter (fun word -> - let word = word |> Db_common.list_of_string |> List.rev in + let word = + word |> Db_common.list_of_string |> List.rev_map Char.lowercase_ascii + in Db.store_name word str_type) doc_words ; let my_full_name = From b00c19407a143c35567719b99177d8a1cf28f3a0 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 21 Apr 2023 17:47:52 +0200 Subject: [PATCH 036/285] print pretty query --- bin/JSherlodoc/main.ml | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index f23f8b4123..9b4f5fe7fc 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -6,26 +6,28 @@ open Syntax let search input _event = let query = El.prop El.Prop.value input |> Jstr.to_string in - let+ _pretty_query, results = + let+ pretty_query, results = Query.(api ~shards:db { query; packages = []; limit = 50 }) in let results = - results - |> List.map (fun elt -> - El.( - div - ([ p - ~at:At.[ style (Jstr.of_string "color:red") ] - [ txt' elt.Db.Elt.name ] - ] - @ - match elt.Db.Elt.doc with - | None -> [] - | Some doc -> - [ p - [ txt' @@ Format.asprintf "%a" (Tyxml.Html.pp_elt ()) doc - ] - ]))) + El.[ p [ txt' pretty_query ] ] + @ List.map + (fun elt -> + El.( + div + ([ p + ~at:At.[ style (Jstr.of_string "color:red") ] + [ txt' elt.Db.Elt.name ] + ] + @ + match elt.Db.Elt.doc with + | None -> [] + | Some doc -> + [ p + [ txt' @@ Format.asprintf "%a" (Tyxml.Html.pp_elt ()) doc + ] + ]))) + results in let results_div = From 0777152ca6a480f3da4d4f71de5f1535349b1cca Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 21 Apr 2023 17:52:36 +0200 Subject: [PATCH 037/285] adds todo --- lib/query/query.mli | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/query/query.mli b/lib/query/query.mli index 9904d0c045..9cb196e6ee 100644 --- a/lib/query/query.mli +++ b/lib/query/query.mli @@ -14,3 +14,4 @@ type t = } val api : shards:Db.Storage.t list -> t -> (string * Db.Elt.t list) Lwt.t +(* TODO : drop the Lwt thing *) \ No newline at end of file From ba5b38144ae8b7cb77a911bf443fd1c1c463cfe6 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 22 Apr 2023 06:23:20 +0200 Subject: [PATCH 038/285] fix docstring raw html rendering in brr --- bin/JSherlodoc/main.ml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 9b4f5fe7fc..4390e3ace2 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -4,6 +4,13 @@ open Brr open Lwt open Syntax +let inner_html = El.Prop.jstr (Jstr.v "innerHTML") + +let raw_html str = + let elt = El.div [] in + El.set_prop inner_html (Jstr.v str) elt ; + elt + let search input _event = let query = El.prop El.Prop.value input |> Jstr.to_string in let+ pretty_query, results = @@ -23,9 +30,7 @@ let search input _event = match elt.Db.Elt.doc with | None -> [] | Some doc -> - [ p - [ txt' @@ Format.asprintf "%a" (Tyxml.Html.pp_elt ()) doc - ] + [ raw_html @@ Format.asprintf "%a" (Tyxml.Html.pp_elt ()) doc ]))) results in From 11a587d7fb109a89724f09303548af208ab1197e Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 22 Apr 2023 07:25:15 +0200 Subject: [PATCH 039/285] fix js async refresh --- bin/JSherlodoc/main.ml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 4390e3ace2..15ba39d1b5 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -11,7 +11,10 @@ let raw_html str = El.set_prop inner_html (Jstr.v str) elt ; elt -let search input _event = +let latest = ref 0 +let count = ref 0 + +let search ~id input _event = let query = El.prop El.Prop.value input |> Jstr.to_string in let+ pretty_query, results = Query.(api ~shards:db { query; packages = []; limit = 50 }) @@ -34,14 +37,19 @@ let search input _event = ]))) results in - let results_div = Document.find_el_by_id G.document (Jstr.of_string "results") |> Option.get in - El.set_children results_div results + if !latest < id + then begin + latest := id ; + El.set_children results_div results + end let search input event = - Js_of_ocaml_lwt.Lwt_js_events.async (fun () -> search input event) + let id = !count in + count := id + 1 ; + Js_of_ocaml_lwt.Lwt_js_events.async (fun () -> search ~id input event) let main () = let search_input = From b750849f3fa151921208866d6201c8ff633ed743 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 22 Apr 2023 07:25:41 +0200 Subject: [PATCH 040/285] experiment with partial type matching --- lib/db/db.ml | 1 + lib/db/trie.ml | 8 ++++---- lib/db/types.ml | 2 +- lib/query/query.ml | 7 ++++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/db/db.ml b/lib/db/db.ml index 8284a6eeda..01c93c7af9 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -114,6 +114,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct r let store ~ho ~hs name typ ~count = + let name = List.concat_map list_of_string name in let rec go db = function | [] -> db | _ :: next as name -> diff --git a/lib/db/trie.ml b/lib/db/trie.ml index 1e9ba24f82..00fc38a569 100644 --- a/lib/db/trie.ml +++ b/lib/db/trie.ml @@ -59,14 +59,14 @@ module Make (E : ELEMENT) = struct let rec find path t = match t, path with | _, [] -> t - | Node t, p :: path -> begin - match M.find p t.children with + | Node node, p :: path -> begin + match M.find p node.children with | child -> find path child - | exception Not_found -> empty () + | exception Not_found -> t end | Leaf (x :: xs, outcome), y :: ys when E.compare x y = 0 -> find ys (Leaf (xs, outcome)) - | _ -> empty () + | _ -> t let rec summarize fn z t = match t with diff --git a/lib/db/types.ml b/lib/db/types.ml index 8f98e0deda..734a5e1b95 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -51,7 +51,7 @@ let regroup lst = module Int_map = Map.Make (Int) module Elt_set = Set.Make (Elt) -module T = Trie.Make (String) +module T = Trie.Make (Char) module Tchar = Trie.Make (Char) module Occ = Int_map diff --git a/lib/query/query.ml b/lib/query/query.ml index dd8127eb22..9c31bcebe7 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -8,7 +8,7 @@ let inter_list = function | [] -> Succ.all | x :: xs -> List.fold_left Succ.inter x xs -let collapse_trie t _acc = +let collapse_trie t = let open Db.Types.T in match t with | Leaf (_, outcome) -> outcome @@ -16,7 +16,7 @@ let collapse_trie t _acc = | _ -> Occ.empty let collapse_trie t = - let r = collapse_trie t Occ.empty in + let r = collapse_trie t in let r = Occ.map Succ.of_set r in r @@ -55,9 +55,10 @@ let find_inter ~shards names = sort @@ inter_list @@ List.map (fun (name, count) -> + let name' = List.concat_map Db.list_of_string name in collapse_count ~count @@ collapse_trie_with_poly name - @@ T.find name db) + @@ T.find name' db) (regroup names) in let open Lwt.Syntax in From d0de5e6c7e982e3ddbb9fff95290e97b50df52d9 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 22 Apr 2023 12:53:51 +0200 Subject: [PATCH 041/285] trie optims --- lib/db/db.ml | 6 +++--- lib/db/trie.ml | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/db/db.ml b/lib/db/db.ml index 01c93c7af9..a869b2245f 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -66,9 +66,9 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let t = { Storage_toplevel.db = !db; db_names = !db_names } in let ho = Hocc2.create 16 in let hs = Hset2.create 16 in - let (_ : Elt_set.t Occ.t) = T.summarize (occ_merge ~ho ~hs) Occ.empty !db in - let (_ : Elt_set.t) = - Tchar.summarize (elt_set_union ~hs) Elt_set.empty !db_names + let (_ : Elt_set.t Occ.t option) = T.summarize (occ_merge ~ho ~hs) !db in + let (_ : Elt_set.t option) = + Tchar.summarize (elt_set_union ~hs) !db_names in Storage.save ~db:h t ; db := T.empty () ; diff --git a/lib/db/trie.ml b/lib/db/trie.ml index 00fc38a569..2b6dbb5271 100644 --- a/lib/db/trie.ml +++ b/lib/db/trie.ml @@ -68,18 +68,19 @@ module Make (E : ELEMENT) = struct find ys (Leaf (xs, outcome)) | _ -> t - let rec summarize fn z t = + let rec summarize fn t = match t with - | Leaf (_, outcome) -> outcome + | Leaf (_, outcome) -> Some outcome | Node ({ leaf; children; _ } as it) -> - let acc = - match leaf with - | None -> z - | Some z -> z - in let sum = - M.fold (fun _ c acc -> fn acc (summarize fn z c)) children acc + M.fold + (fun _ c acc -> + let res = summarize fn c in + match acc, res with + | None, opt | opt, None -> opt + | Some acc, Some res -> Some (fn acc res)) + children leaf in - it.summary <- Some sum ; + it.summary <- sum ; sum end From 5e43ecd1735833169ca614e93d8389c9ea44a58f Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 22 Apr 2023 17:21:47 +0200 Subject: [PATCH 042/285] remove lwt from query --- bin/JSherlodoc/dune | 3 +-- bin/JSherlodoc/main.ml | 6 ++---- lib/db/types.ml | 2 ++ lib/query/query.ml | 27 ++++++++++----------------- lib/query/query.mli | 8 +------- lib/query/succ.ml | 16 +++++++--------- 6 files changed, 23 insertions(+), 39 deletions(-) diff --git a/bin/JSherlodoc/dune b/bin/JSherlodoc/dune index ea5ccb9143..44b8f165dc 100644 --- a/bin/JSherlodoc/dune +++ b/bin/JSherlodoc/dune @@ -1,6 +1,5 @@ (executable (name main) (modes js) - (libraries tyxml query storage_js brr js_of_ocaml-lwt) - (preprocess (pps js_of_ocaml-ppx))) + (libraries tyxml query storage_js brr)) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 15ba39d1b5..14af498471 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -1,8 +1,6 @@ let db = Storage_js.load Jv.(to_string @@ get global "sherlodb") open Brr -open Lwt -open Syntax let inner_html = El.Prop.jstr (Jstr.v "innerHTML") @@ -16,7 +14,7 @@ let count = ref 0 let search ~id input _event = let query = El.prop El.Prop.value input |> Jstr.to_string in - let+ pretty_query, results = + let pretty_query, results = Query.(api ~shards:db { query; packages = []; limit = 50 }) in let results = @@ -49,7 +47,7 @@ let search ~id input _event = let search input event = let id = !count in count := id + 1 ; - Js_of_ocaml_lwt.Lwt_js_events.async (fun () -> search ~id input event) + search ~id input event let main () = let search_input = diff --git a/lib/db/types.ml b/lib/db/types.ml index 734a5e1b95..4050da1924 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -23,6 +23,8 @@ module Elt = struct end | c -> c + let compare a b = if a == b then 0 else compare a b + let pkg_link { pkg = pkg, v; _ } = Printf.sprintf "https://ocaml.org/p/%s/%s" pkg v diff --git a/lib/query/query.ml b/lib/query/query.ml index 9c31bcebe7..e6df812da6 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -48,7 +48,7 @@ let collapse_trie_with_poly name t = let sort x = x let find_inter ~shards names = - Lwt_list.fold_left_s + List.fold_left (fun acc shard -> let db = shard.Storage.db in let r = @@ -61,8 +61,6 @@ let find_inter ~shards names = @@ T.find name' db) (regroup names) in - let open Lwt.Syntax in - let+ () = Lwt.pause () in Succ.union acc r) Succ.empty shards @@ -72,11 +70,9 @@ let find_names ~shards names = (fun n -> List.rev (Db.list_of_string (String.lowercase_ascii n))) names in - Lwt_list.fold_left_s + List.fold_left (fun acc shard -> let db_names = shard.Storage.db_names in - let open Lwt.Syntax in - let+ () = Lwt.pause () in let candidates = List.map (fun name -> @@ -95,34 +91,31 @@ type t = } let search ~shards query_name query_typ = - let open Lwt.Syntax in - let* results_name = find_names ~shards query_name in - let+ results = + let results_name = find_names ~shards query_name in + let results = match query_typ with - | None -> Lwt.return results_name + | None -> results_name | Some query_typ -> - let+ results_typ = find_inter ~shards query_typ in + let results_typ = find_inter ~shards query_typ in Succ.inter results_name results_typ in results -open Lwt.Syntax - let match_packages ~packages { Db.Elt.pkg = package, _version; _ } = List.exists (String.equal package) packages let match_packages ~packages results = match packages with | [] -> results - | _ -> Lwt_stream.filter (match_packages ~packages) results + | _ -> Seq.filter (match_packages ~packages) results let api ~shards params = let query_name, query_typ, query_typ_arrow, pretty = Parser.of_string params.query in - let* results = search ~shards query_name query_typ in - let results = Succ.to_stream results in + let results = search ~shards query_name query_typ in + let results = Succ.to_seq results in let results = match_packages ~packages:params.packages results in - let+ results = Lwt_stream.nget params.limit results in + let results = List.of_seq @@ Seq.take params.limit results in let results = Sort.list query_name query_typ_arrow results in pretty, results diff --git a/lib/query/query.mli b/lib/query/query.mli index 9cb196e6ee..4419273552 100644 --- a/lib/query/query.mli +++ b/lib/query/query.mli @@ -2,16 +2,10 @@ module Parser = Query_parser module Succ = Succ module Sort = Sort -val find_inter : - shards:Db.Storage.t list -> Db.String_list_map.key list -> Succ.t Lwt.t - -val find_names : shards:Db.Storage.t list -> string list -> Succ.t Lwt.t - type t = { query : string ; packages : string list ; limit : int } -val api : shards:Db.Storage.t list -> t -> (string * Db.Elt.t list) Lwt.t -(* TODO : drop the Lwt thing *) \ No newline at end of file +val api : shards:Db.Storage.t list -> t -> string * Db.Elt.t list diff --git a/lib/query/succ.ml b/lib/query/succ.ml index 9d07a5167a..2b3b0bc749 100644 --- a/lib/query/succ.ml +++ b/lib/query/succ.ml @@ -110,18 +110,16 @@ let rec first = function and first_opt t = try Some (first t) with Not_found -> None -let to_stream t = +let to_seq t = let state = ref None in let rec go elt = - let open Lwt.Syntax in - let* () = Lwt.pause () in match succ_ge elt t with | elt' -> assert (Elt.compare elt elt' = 0) ; state := Some elt ; - Lwt.return (Some elt) + Some elt | exception Gt elt -> go elt - | exception Not_found -> Lwt.return None + | exception Not_found -> None in let go_gt () = match !state with @@ -129,9 +127,9 @@ let to_stream t = | Some previous_elt -> ( match succ_gt previous_elt t with | elt -> go elt - | exception Not_found -> Lwt.return None) + | exception Not_found -> None) in - let next () = Lwt.catch (fun () -> go_gt ()) (fun _ -> Lwt.return None) in - Lwt_stream.from next + let next () = try go_gt () with _ -> None in + Seq.of_dispenser next -let to_stream t = to_stream t.s +let to_seq t = to_seq t.s From 8a84955c0e950b1a21357bdb3101473d66d91f1f Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 22 Apr 2023 17:55:15 +0200 Subject: [PATCH 043/285] remove dependency to format in js code --- bin/JSherlodoc/main.ml | 4 +--- bin/api/main.ml | 5 ++-- bin/www/ui.ml | 2 +- bin/www/www.ml | 18 +++++++------- lib/db/types.ml | 2 +- lib/index_lib/load_doc.ml | 49 +++++++++++---------------------------- lib/index_lib/pretty.ml | 6 ++++- 7 files changed, 32 insertions(+), 54 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 14af498471..01c6ec2cb2 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -30,9 +30,7 @@ let search ~id input _event = @ match elt.Db.Elt.doc with | None -> [] - | Some doc -> - [ raw_html @@ Format.asprintf "%a" (Tyxml.Html.pp_elt ()) doc - ]))) + | Some doc -> [ raw_html doc ]))) results in let results_div = diff --git a/bin/api/main.ml b/bin/api/main.ml index cb8419c85b..51b959414a 100644 --- a/bin/api/main.ml +++ b/bin/api/main.ml @@ -1,12 +1,11 @@ module Storage = Db.Storage module Succ = Query.Succ module Sort = Query.Sort -open Lwt.Syntax module H = Tyxml.Html let api ~shards params = - let+ r = Query.api ~shards params in - Marshal.to_string r [] + let r = Query.api ~shards params in + Lwt.return (Marshal.to_string r []) open Lwt.Syntax diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 4e6cbd4bdb..49d6516d79 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -21,7 +21,7 @@ let render_result r = ; txt " : " ; txt r.str_type ] - :: list_of_option r.doc + :: list_of_option (Option.map Unsafe.data r.doc) let render ~pretty results = match results with diff --git a/bin/www/www.ml b/bin/www/www.ml index b99b06d07a..290494ae3b 100644 --- a/bin/www/www.ml +++ b/bin/www/www.ml @@ -1,13 +1,11 @@ module Storage = Db.Storage module Succ = Query.Succ module Sort = Query.Sort - -open Lwt.Syntax module H = Tyxml.Html let api ~shards params = - let+ pretty, results = Query.api ~shards params in - Ui.render ~pretty results + let pretty, results = Query.api ~shards params in + Lwt.return (Ui.render ~pretty results) let api ~shards params = if String.trim params.Query.query = "" @@ -79,9 +77,10 @@ let cors_options = response) let main db_format db_filename cache_max_age = - let storage = match db_format with - | `ancient -> (module Storage_ancient : Db.Storage.S) - | `marshal -> (module Storage_marshal : Db.Storage.S) + let storage = + match db_format with + | `ancient -> (module Storage_ancient : Db.Storage.S) + | `marshal -> (module Storage_marshal : Db.Storage.S) in let module Storage = (val storage) in let shards = Storage.load db_filename in @@ -107,8 +106,9 @@ open Cmdliner let db_format = let doc = "Databse format" in - let kind = Arg.enum ["ancient", `ancient; "marshal", `marshal] in - Arg.(required & opt (some kind) None & info ["format"] ~docv:"DB_FORMAT" ~doc) + let kind = Arg.enum [ "ancient", `ancient; "marshal", `marshal ] in + Arg.( + required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) let db_path = let doc = "Database filename" in diff --git a/lib/db/types.ml b/lib/db/types.ml index 4050da1924..6039658b9d 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -4,7 +4,7 @@ module Elt = struct ; name : string ; str_type : string ; type_paths : string list list - ; doc : Html_types.li_content_fun Tyxml.Html.elt option + ; doc : string option ; pkg : string * string } diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 5446861bab..e903262e91 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -6,34 +6,13 @@ module Make (Storage : Db.Storage.S) = struct open Odoc_model module ModuleName = Odoc_model.Names.ModuleName - let copy str = String.init (String.length str) (String.get str) - - let deep_copy (type t) (x : t) : t = - let buf = Marshal.(to_bytes x [ No_sharing; Closures ]) in - Marshal.from_bytes buf 0 - - module Cache_doc = Cache.Make (struct - type t = Html_types.li_content_fun Tyxml.Html.elt - - let copy x = deep_copy x - end) - - module Cache_name = Cache.Make (struct - type t = string - - let copy = copy - end) - module Cache = Cache.Make (struct type t = string - let copy = copy + let copy str = String.init (String.length str) (String.get str) end) - let clear () = - Cache.clear () ; - Cache_name.clear () ; - Cache_doc.clear () + let clear () = Cache.clear () let rec type_size = function | Odoc_model.Lang.TypeExpr.Var _ -> 1 @@ -63,23 +42,21 @@ module Make (Storage : Db.Storage.S) = struct let rec paths ~prefix ~sgn = function | Odoc_model.Lang.TypeExpr.Var _ -> - let poly = Cache_name.memo "POLY" in - [ poly :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix ] + let poly = Cache.memo "POLY" in + [ poly :: Cache.memo (Types.string_of_sgn sgn) :: prefix ] | Any -> - let poly = Cache_name.memo "POLY" in - [ poly :: Cache_name.memo (Types.string_of_sgn sgn) :: prefix ] + let poly = Cache.memo "POLY" in + [ poly :: Cache.memo (Types.string_of_sgn sgn) :: prefix ] | Arrow (_, a, b) -> - let prefix_left = Cache_name.memo "->0" :: prefix in - let prefix_right = Cache_name.memo "->1" :: prefix in + let prefix_left = Cache.memo "->0" :: prefix in + let prefix_right = Cache.memo "->1" :: prefix in List.rev_append (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) (paths ~prefix:prefix_right ~sgn b) | Constr (name, args) -> let name = fullname name in let prefix = - Cache_name.memo name - :: Cache_name.memo (Types.string_of_sgn sgn) - :: prefix + Cache.memo name :: Cache.memo (Types.string_of_sgn sgn) :: prefix in begin match args with @@ -88,14 +65,14 @@ module Make (Storage : Db.Storage.S) = struct rev_concat @@ List.mapi (fun i arg -> - let prefix = Cache_name.memo (string_of_int i) :: prefix in + let prefix = Cache.memo (string_of_int i) :: prefix in paths ~prefix ~sgn arg) args end | Tuple args -> rev_concat @@ List.mapi (fun i arg -> - let prefix = Cache_name.memo (string_of_int i ^ "*") :: prefix in + let prefix = Cache.memo (string_of_int i ^ "*") :: prefix in paths ~prefix ~sgn arg) @@ args | _ -> [] @@ -144,7 +121,7 @@ module Make (Storage : Db.Storage.S) = struct let doc_words = doc |> Docstring.words_of_docs |> List.sort_uniq String.compare in - let doc = Option.map Cache_doc.memo (Pretty.string_of_docs doc) in + let doc = Option.map Cache.memo (Pretty.string_of_docs doc) in let cost = String.length full_name + String.length str_type + (5 * List.length path) @@ -180,7 +157,7 @@ module Make (Storage : Db.Storage.S) = struct Db.store_name my_full_name str_type ; let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in - Db.store_all str_type (List.map (List.map Cache_name.memo) type_paths) + Db.store_all str_type (List.map (List.map Cache.memo) type_paths) let rec item ~pkg ~path_list ~path = let open Odoc_model.Lang in diff --git a/lib/index_lib/pretty.ml b/lib/index_lib/pretty.ml index 14353570b3..83533d7759 100644 --- a/lib/index_lib/pretty.ml +++ b/lib/index_lib/pretty.ml @@ -65,9 +65,13 @@ let string_of_doc = function | `Heading (_, _, p) -> Some (H.p [ string_of_link_content p ]) | _ -> None -let string_of_docs lst = +let html_of_docs lst = List.find_map (fun elt -> string_of_doc elt.Odoc_model.Location_.value) lst +let string_of_docs doc = + let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) in + Option.map string_of_html (html_of_docs doc) + let make_root ~module_name ~digest = let file = Odoc_file.create_unit ~force_hidden:false module_name in Ok { id = `Root (None, ModuleName.make_std module_name); file; digest } From 246b6f0f2b098702698f29c03f3a5f122b2d70db Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 23 Apr 2023 13:57:45 +0200 Subject: [PATCH 044/285] style js results --- bin/JSherlodoc/index.html | 7 +++-- bin/JSherlodoc/main.ml | 54 ++++++++++++++++++++---------------- bin/JSherlodoc/style.css | 58 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 25 deletions(-) create mode 100644 bin/JSherlodoc/style.css diff --git a/bin/JSherlodoc/index.html b/bin/JSherlodoc/index.html index 5f4906f96f..ca72ff23a2 100644 --- a/bin/JSherlodoc/index.html +++ b/bin/JSherlodoc/index.html @@ -5,10 +5,13 @@ + JSherlodoc - -
+ diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 01c6ec2cb2..a56b34e5e1 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -5,33 +5,37 @@ open Brr let inner_html = El.Prop.jstr (Jstr.v "innerHTML") let raw_html str = - let elt = El.div [] in + let elt = El.div ~at:At.[ class' (Jstr.of_string "docstring") ] [] in El.set_prop inner_html (Jstr.v str) elt ; elt let latest = ref 0 -let count = ref 0 +let count = ref 1 -let search ~id input _event = +let search ~id input = let query = El.prop El.Prop.value input |> Jstr.to_string in - let pretty_query, results = + let _pretty_query, results = Query.(api ~shards:db { query; packages = []; limit = 50 }) in + let results = List.of_seq @@ Seq.take 10 @@ List.to_seq results in let results = - El.[ p [ txt' pretty_query ] ] - @ List.map - (fun elt -> - El.( - div - ([ p - ~at:At.[ style (Jstr.of_string "color:red") ] - [ txt' elt.Db.Elt.name ] - ] - @ - match elt.Db.Elt.doc with - | None -> [] - | Some doc -> [ raw_html doc ]))) - results + List.map + (fun elt -> + El.( + div + ~at:At.[ class' (Jstr.of_string "result") ] + ([ code + [ txt' "val " + ; em [ txt' elt.Db.Elt.name ] + ; txt' " : " + ; txt' elt.Db.Elt.str_type + ] + ] + @ + match elt.Db.Elt.doc with + | None -> [] + | Some doc -> [ raw_html doc ]))) + results in let results_div = Document.find_el_by_id G.document (Jstr.of_string "results") |> Option.get @@ -42,17 +46,21 @@ let search ~id input _event = El.set_children results_div results end -let search input event = +let search input = let id = !count in count := id + 1 ; - search ~id input event + search ~id input let main () = let search_input = Document.find_el_by_id G.document (Jstr.of_string "search") |> Option.get in - Ev.( - listen input (search search_input) - (search_input |> El.document |> Document.as_target)) + let _ = + Ev.( + listen input + (fun _ -> search search_input) + (search_input |> El.document |> Document.as_target)) + in + search search_input let _ = main () diff --git a/bin/JSherlodoc/style.css b/bin/JSherlodoc/style.css new file mode 100644 index 0000000000..0a6c2aaf31 --- /dev/null +++ b/bin/JSherlodoc/style.css @@ -0,0 +1,58 @@ +body { + margin: 2em; +} + +#search-bar { + border: 1px solid black; +} + +#search-bar input#search { + margin: 0.5em 1em; + font-family: monospace; + width: 40%; +} + +.result { + max-height: 2rem; + overflow: hidden; + padding: 0 1em; +} + +.result > code { + margin: 0; + padding: 0 0; + font-size: 1.2em; + line-height: 2rem; + vertical-align: center; + display: inline-block; + width: 40%; + float: left; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.result > code em { + font-weight: bold; + font-style: normal; +} + +.result .docstring { + display: inline-block; + line-height: 2rem; + width: 60%; + font-style: italic; +} + +.result .docstring p { + margin: 0; + padding: 0; + padding-left: 2em; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.result:nth-child(odd) { + background: #eee; +} From b5f1aa948d2390626aec8c40777e6ae2c113008f Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 23 Apr 2023 18:02:32 +0200 Subject: [PATCH 045/285] reduce js database size --- bin/index/index.ml | 20 ++++++++------ lib/db/db.ml | 15 ++++++---- lib/db/db.mli | 1 + lib/db/trie.ml | 18 ++++++++++++ lib/index_lib/index_lib.ml | 3 +- lib/index_lib/index_lib.mli | 6 +++- lib/query/query.ml | 55 +++++++++++++------------------------ lib/query/succ.ml | 4 ++- 8 files changed, 69 insertions(+), 53 deletions(-) diff --git a/bin/index/index.ml b/bin/index/index.ml index 135dc235bf..0d4564ed09 100644 --- a/bin/index/index.ml +++ b/bin/index/index.ml @@ -1,25 +1,27 @@ let main odoc_directory db_filename db_format = - let storage = match db_format with - | `ancient -> (module Storage_ancient : Db.Storage.S) - | `marshal -> (module Storage_marshal : Db.Storage.S) - | `js -> (module Storage_js : Db.Storage.S) + let optimize, storage = + match db_format with + | `ancient -> true, (module Storage_ancient : Db.Storage.S) + | `marshal -> false, (module Storage_marshal : Db.Storage.S) + | `js -> false, (module Storage_js : Db.Storage.S) in - Index_lib.main ~odoc_directory ~db_filename storage + Index_lib.main ~odoc_directory ~db_filename ~optimize storage open Cmdliner let db_format = let doc = "Databse format" in - let kind = Arg.enum ["ancient", `ancient; "marshal", `marshal; "js", `js] in - Arg.(required & opt (some kind) None & info ["format"] ~docv:"DB_FORMAT" ~doc) + let kind = Arg.enum [ "ancient", `ancient; "marshal", `marshal; "js", `js ] in + Arg.( + required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) let db_filename = let doc = "Database filename" in - Arg.(required & opt (some string) None & info ["db"] ~docv:"DB" ~doc) + Arg.(required & opt (some string) None & info [ "db" ] ~docv:"DB" ~doc) let odoc_path = let doc = "Path to a directory containing odocl files" in - Arg.(required & opt (some dir) None & info ["odoc"] ~docv:"ODOC_FILES" ~doc) + Arg.(required & opt (some dir) None & info [ "odoc" ] ~docv:"ODOC_FILES" ~doc) let index = Term.(const main $ odoc_path $ db_filename $ db_format) diff --git a/lib/db/db.ml b/lib/db/db.ml index a869b2245f..18e62ec200 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -7,6 +7,7 @@ let list_of_string s = List.init (String.length s) (String.get s) module type S = sig type writer + val optimize : unit -> unit val export : writer -> unit val store_all : Elt_set.elt -> String_list_map.key list -> unit val store_name : Tchar.M.key list -> Elt_set.elt -> unit @@ -61,15 +62,18 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct Hocc2.add ho (b, a) r ; r - let export h = - load_counter := 0 ; - let t = { Storage_toplevel.db = !db; db_names = !db_names } in + let optimize () = let ho = Hocc2.create 16 in let hs = Hset2.create 16 in let (_ : Elt_set.t Occ.t option) = T.summarize (occ_merge ~ho ~hs) !db in let (_ : Elt_set.t option) = Tchar.summarize (elt_set_union ~hs) !db_names in + () + + let export h = + load_counter := 0 ; + let t = { Storage_toplevel.db = !db; db_names = !db_names } in Storage.save ~db:h t ; db := T.empty () ; db_names := Tchar.empty () @@ -115,9 +119,10 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let store ~ho ~hs name typ ~count = let name = List.concat_map list_of_string name in - let rec go db = function + let rec go db name = + match name with | [] -> db - | _ :: next as name -> + | _ :: next -> incr load_counter ; let db = T.add name (candidates_add ~ho ~hs typ ~count) db in go db next diff --git a/lib/db/db.mli b/lib/db/db.mli index c693da2dcf..ecee3b6adf 100644 --- a/lib/db/db.mli +++ b/lib/db/db.mli @@ -10,6 +10,7 @@ val list_of_string : string -> char list module type S = sig type writer + val optimize : unit -> unit val export : writer -> unit val store_all : Elt_set.elt -> String_list_map.key list -> unit val store_name : Tchar.M.key list -> Elt_set.elt -> unit diff --git a/lib/db/trie.ml b/lib/db/trie.ml index 2b6dbb5271..e161868935 100644 --- a/lib/db/trie.ml +++ b/lib/db/trie.ml @@ -83,4 +83,22 @@ module Make (E : ELEMENT) = struct in it.summary <- sum ; sum + + let rec fold_map merge transform t = + match t with + | Leaf (_, outcome) | Node { summary = Some outcome; _ } -> + Some (transform outcome) + | Node { leaf; children; _ } -> + let leaf = + match leaf with + | None -> None + | Some leaf -> Some (transform leaf) + in + M.fold + (fun _ c acc -> + let res = fold_map merge transform c in + match acc, res with + | None, opt | opt, None -> opt + | Some acc, Some res -> Some (merge acc res)) + children leaf end diff --git a/lib/index_lib/index_lib.ml b/lib/index_lib/index_lib.ml index 6110176bdf..06f8c429c8 100644 --- a/lib/index_lib/index_lib.ml +++ b/lib/index_lib/index_lib.ml @@ -8,7 +8,7 @@ let of_filename f = let filenames odoc_directory = List.map of_filename (Files.list odoc_directory) -let main ~odoc_directory ~db_filename storage = +let main ~odoc_directory ~db_filename ~optimize storage = let module Storage = (val storage : Storage.S) in let module Load_doc = Load_doc.Make (Storage) in let module Db = Load_doc.Db in @@ -16,6 +16,7 @@ let main ~odoc_directory ~db_filename storage = let total = List.length files in let h = Storage.open_out db_filename in let flush () = + if optimize then Db.optimize () ; Load_doc.clear () ; Db.export h in diff --git a/lib/index_lib/index_lib.mli b/lib/index_lib/index_lib.mli index b2db9016d7..52aee6577d 100644 --- a/lib/index_lib/index_lib.mli +++ b/lib/index_lib/index_lib.mli @@ -1,2 +1,6 @@ val main : - odoc_directory:string -> db_filename:string -> (module Db.Storage.S) -> unit + odoc_directory:string + -> db_filename:string + -> optimize:bool + -> (module Db.Storage.S) + -> unit diff --git a/lib/query/query.ml b/lib/query/query.ml index e6df812da6..6d90edbfb6 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -4,61 +4,44 @@ module Sort = Sort module Storage = Db.Storage open Db.Types -let inter_list = function - | [] -> Succ.all - | x :: xs -> List.fold_left Succ.inter x xs +let inter_list xs = List.fold_left Succ.inter Succ.all xs -let collapse_trie t = - let open Db.Types.T in - match t with - | Leaf (_, outcome) -> outcome - | Node { summary = Some s; _ } -> s - | _ -> Occ.empty - -let collapse_trie t = - let r = collapse_trie t in - let r = Occ.map Succ.of_set r in - r +let collapse_count ~count occs = + Occ.fold + (fun k x acc -> if k < count then acc else Succ.union (Succ.of_set x) acc) + occs Succ.empty -let collapse_triechar t _acc = - let open Tchar in - match t with - | Leaf (_, outcome) -> outcome - | Node { summary = Some s; _ } -> s - | _ -> Elt_set.empty +let collapse_trie ~count t = + match Db.Types.T.fold_map Succ.union (collapse_count ~count) t with + | None -> Succ.empty + | Some occ -> occ -let collapse_triechar t = Succ.of_set (collapse_triechar t Elt_set.empty) +let collapse_triechar t = + match Db.Types.Tchar.fold_map Succ.union Succ.of_set t with + | None -> Succ.empty + | Some s -> s -let collapse_count ~count (t : Succ.t Occ.t) = - Occ.fold - (fun k x acc -> if k < count then acc else Succ.union x acc) - t Succ.empty - -let collapse_trie_with_poly name t = +let collapse_trie_with_poly ~count name t = match name with | [ "POLY"; _ ] -> let open T in begin match t with - | Leaf ([], s) | Node { leaf = Some s; _ } -> Occ.map Succ.of_set s - | _ -> Occ.empty + | Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_count ~count s + | _ -> Succ.empty end - | _ -> collapse_trie t - -let sort x = x + | _ -> collapse_trie ~count t let find_inter ~shards names = List.fold_left (fun acc shard -> let db = shard.Storage.db in let r = - sort @@ inter_list + inter_list @@ List.map (fun (name, count) -> let name' = List.concat_map Db.list_of_string name in - collapse_count ~count - @@ collapse_trie_with_poly name - @@ T.find name' db) + collapse_trie_with_poly ~count name @@ T.find name' db) (regroup names) in Succ.union acc r) diff --git a/lib/query/succ.ml b/lib/query/succ.ml index 2b3b0bc749..636eaf31a8 100644 --- a/lib/query/succ.ml +++ b/lib/query/succ.ml @@ -34,7 +34,9 @@ let union a b = | Empty, _ -> b | _, Empty -> a | All, _ | _, All -> all - | x, y -> { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } + | x, y -> + let x, y = if a.cardinal < b.cardinal then x, y else y, x in + { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } let succ_ge' elt set = Elt_set.find_first (fun e -> Elt.compare e elt >= 0) set let succ_gt' elt set = Elt_set.find_first (fun e -> Elt.compare e elt > 0) set From 601520a966c684cd51ee2156d1b4fa0b4e464224 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 23 Apr 2023 18:22:50 +0200 Subject: [PATCH 046/285] specialize trie for string keys --- lib/db/db.ml | 21 +++--- lib/db/db.mli | 4 +- lib/db/storage.ml | 2 +- lib/db/storage.mli | 2 +- lib/db/trie.ml | 173 +++++++++++++++++++++------------------------ lib/db/types.ml | 4 +- lib/query/query.ml | 21 +++--- 7 files changed, 107 insertions(+), 120 deletions(-) diff --git a/lib/db/db.ml b/lib/db/db.ml index 18e62ec200..644c1efc50 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -1,5 +1,6 @@ module Types = Types module Storage_toplevel = Storage +module Trie = Trie include Types let list_of_string s = List.init (String.length s) (String.get s) @@ -10,7 +11,7 @@ module type S = sig val optimize : unit -> unit val export : writer -> unit val store_all : Elt_set.elt -> String_list_map.key list -> unit - val store_name : Tchar.M.key list -> Elt_set.elt -> unit + val store_name : char list -> Elt_set.elt -> unit val load_counter : int ref end @@ -18,8 +19,8 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct type writer = Storage.writer let load_counter = ref 0 - let db = ref (T.empty ()) - let db_names = ref (Tchar.empty ()) + let db = ref (Trie.empty ()) + let db_names = ref (Trie.empty ()) module Hset2 = Hashtbl.Make (struct type t = Elt_set.t * Elt_set.t @@ -65,18 +66,16 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let optimize () = let ho = Hocc2.create 16 in let hs = Hset2.create 16 in - let (_ : Elt_set.t Occ.t option) = T.summarize (occ_merge ~ho ~hs) !db in - let (_ : Elt_set.t option) = - Tchar.summarize (elt_set_union ~hs) !db_names - in + let (_ : Elt_set.t Occ.t option) = Trie.summarize (occ_merge ~ho ~hs) !db in + let (_ : Elt_set.t option) = Trie.summarize (elt_set_union ~hs) !db_names in () let export h = load_counter := 0 ; let t = { Storage_toplevel.db = !db; db_names = !db_names } in Storage.save ~db:h t ; - db := T.empty () ; - db_names := Tchar.empty () + db := Trie.empty () ; + db_names := Trie.empty () module Hset = Hashtbl.Make (struct type t = Elt_set.t option @@ -124,7 +123,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct | [] -> db | _ :: next -> incr load_counter ; - let db = T.add name (candidates_add ~ho ~hs typ ~count) db in + let db = Trie.add name (candidates_add ~ho ~hs typ ~count) db in go db next in db := go !db name @@ -142,7 +141,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct | [] -> db | _ :: next as name -> incr load_counter ; - let db = Tchar.add name (set_add ~hs typ) db in + let db = Trie.add name (set_add ~hs typ) db in go db next in db_names := go !db_names name diff --git a/lib/db/db.mli b/lib/db/db.mli index ecee3b6adf..ba3f4df18c 100644 --- a/lib/db/db.mli +++ b/lib/db/db.mli @@ -1,7 +1,7 @@ module Elt = Types.Elt module Types = Types module Storage = Storage -module Tchar = Types.Tchar +module Trie = Trie module Elt_set = Types.Elt_set module String_list_map = Types.String_list_map @@ -13,7 +13,7 @@ module type S = sig val optimize : unit -> unit val export : writer -> unit val store_all : Elt_set.elt -> String_list_map.key list -> unit - val store_name : Tchar.M.key list -> Elt_set.elt -> unit + val store_name : char list -> Elt_set.elt -> unit val load_counter : int ref end diff --git a/lib/db/storage.ml b/lib/db/storage.ml index 0216d26914..7da033af26 100644 --- a/lib/db/storage.ml +++ b/lib/db/storage.ml @@ -1,6 +1,6 @@ type t = { db : Types.db - ; db_names : Types.Elt_set.t Types.Tchar.t + ; db_names : Types.Elt_set.t Trie.t } module type S = sig diff --git a/lib/db/storage.mli b/lib/db/storage.mli index 0216d26914..7da033af26 100644 --- a/lib/db/storage.mli +++ b/lib/db/storage.mli @@ -1,6 +1,6 @@ type t = { db : Types.db - ; db_names : Types.Elt_set.t Types.Tchar.t + ; db_names : Types.Elt_set.t Trie.t } module type S = sig diff --git a/lib/db/trie.ml b/lib/db/trie.ml index e161868935..96fae376fa 100644 --- a/lib/db/trie.ml +++ b/lib/db/trie.ml @@ -1,104 +1,95 @@ -module type ELEMENT = sig - type t +module M = Map.Make (Char) - val compare : t -> t -> int -end +type 'a t = + | Leaf of char list * 'a + | Node of + { leaf : 'a option + ; mutable summary : 'a option + ; children : 'a t M.t + } -module Make (E : ELEMENT) = struct - module M = Map.Make (E) +let empty () = Node { leaf = None; summary = None; children = M.empty } - type 'a t = - | Leaf of E.t list * 'a - | Node of - { leaf : 'a option - ; mutable summary : 'a option - ; children : 'a t M.t - } - - let empty () = Node { leaf = None; summary = None; children = M.empty } - - let rec add path leaf t = - match t, path with - | Node t, [] -> Node { t with leaf = Some (leaf t.leaf) } - | Node t, p :: path -> - let child = - match M.find p t.children with - | child -> add path leaf child - | exception Not_found -> Leaf (path, leaf None) - in - Node { t with children = M.add p child t.children } - | Leaf (x :: xs, outcome), y :: ys when E.compare x y = 0 -> - if xs = ys - then Leaf (path, leaf (Some outcome)) - else - Node - { leaf = None - ; summary = None - ; children = M.singleton x (add ys leaf (Leaf (xs, outcome))) - } - | Leaf (x :: xs, outcome), y :: ys -> - assert (E.compare x y <> 0) ; - let children = - M.add y (Leaf (ys, leaf None)) @@ M.singleton x (Leaf (xs, outcome)) - in - Node { leaf = None; summary = None; children } - | Leaf ([], outcome), [] -> Leaf ([], leaf (Some outcome)) - | Leaf ([], outcome), y :: ys -> - Node - { leaf = Some outcome - ; summary = None - ; children = M.singleton y (Leaf (ys, leaf None)) - } - | Leaf (y :: ys, outcome), [] -> +let rec add path leaf t = + match t, path with + | Node t, [] -> Node { t with leaf = Some (leaf t.leaf) } + | Node t, p :: path -> + let child = + match M.find p t.children with + | child -> add path leaf child + | exception Not_found -> Leaf (path, leaf None) + in + Node { t with children = M.add p child t.children } + | Leaf (x :: xs, outcome), y :: ys when x = y -> + if xs = ys + then Leaf (path, leaf (Some outcome)) + else Node - { leaf = Some (leaf None) + { leaf = None ; summary = None - ; children = M.singleton y (Leaf (ys, outcome)) + ; children = M.singleton x (add ys leaf (Leaf (xs, outcome))) } + | Leaf (x :: xs, outcome), y :: ys -> + assert (x <> y) ; + let children = + M.add y (Leaf (ys, leaf None)) @@ M.singleton x (Leaf (xs, outcome)) + in + Node { leaf = None; summary = None; children } + | Leaf ([], outcome), [] -> Leaf ([], leaf (Some outcome)) + | Leaf ([], outcome), y :: ys -> + Node + { leaf = Some outcome + ; summary = None + ; children = M.singleton y (Leaf (ys, leaf None)) + } + | Leaf (y :: ys, outcome), [] -> + Node + { leaf = Some (leaf None) + ; summary = None + ; children = M.singleton y (Leaf (ys, outcome)) + } - let rec find path t = - match t, path with - | _, [] -> t - | Node node, p :: path -> begin - match M.find p node.children with - | child -> find path child - | exception Not_found -> t - end - | Leaf (x :: xs, outcome), y :: ys when E.compare x y = 0 -> - find ys (Leaf (xs, outcome)) - | _ -> t - - let rec summarize fn t = - match t with - | Leaf (_, outcome) -> Some outcome - | Node ({ leaf; children; _ } as it) -> - let sum = - M.fold - (fun _ c acc -> - let res = summarize fn c in - match acc, res with - | None, opt | opt, None -> opt - | Some acc, Some res -> Some (fn acc res)) - children leaf - in - it.summary <- sum ; - sum +let rec find path t = + match t, path with + | _, [] -> t + | Node node, p :: path -> begin + match M.find p node.children with + | child -> find path child + | exception Not_found -> t + end + | Leaf (x :: xs, outcome), y :: ys when x = y -> find ys (Leaf (xs, outcome)) + | _ -> t - let rec fold_map merge transform t = - match t with - | Leaf (_, outcome) | Node { summary = Some outcome; _ } -> - Some (transform outcome) - | Node { leaf; children; _ } -> - let leaf = - match leaf with - | None -> None - | Some leaf -> Some (transform leaf) - in +let rec summarize fn t = + match t with + | Leaf (_, outcome) -> Some outcome + | Node ({ leaf; children; _ } as it) -> + let sum = M.fold (fun _ c acc -> - let res = fold_map merge transform c in + let res = summarize fn c in match acc, res with | None, opt | opt, None -> opt - | Some acc, Some res -> Some (merge acc res)) + | Some acc, Some res -> Some (fn acc res)) children leaf -end + in + it.summary <- sum ; + sum + +let rec fold_map merge transform t = + match t with + | Leaf (_, outcome) | Node { summary = Some outcome; _ } -> + Some (transform outcome) + | Node { leaf; children; _ } -> + let leaf = + match leaf with + | None -> None + | Some leaf -> Some (transform leaf) + in + M.fold + (fun _ c acc -> + let res = fold_map merge transform c in + match acc, res with + | None, opt | opt, None -> opt + | Some acc, Some res -> Some (merge acc res)) + children leaf diff --git a/lib/db/types.ml b/lib/db/types.ml index 6039658b9d..0d5aff6ca0 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -53,12 +53,10 @@ let regroup lst = module Int_map = Map.Make (Int) module Elt_set = Set.Make (Elt) -module T = Trie.Make (Char) -module Tchar = Trie.Make (Char) module Occ = Int_map type candidates = Elt_set.t Occ.t -type db = candidates T.t +type db = candidates Trie.t type sgn = | Pos diff --git a/lib/query/query.ml b/lib/query/query.ml index 6d90edbfb6..94089cca99 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -2,6 +2,7 @@ module Parser = Query_parser module Succ = Succ module Sort = Sort module Storage = Db.Storage +module Trie = Db.Trie open Db.Types let inter_list xs = List.fold_left Succ.inter Succ.all xs @@ -12,24 +13,22 @@ let collapse_count ~count occs = occs Succ.empty let collapse_trie ~count t = - match Db.Types.T.fold_map Succ.union (collapse_count ~count) t with + match Trie.fold_map Succ.union (collapse_count ~count) t with | None -> Succ.empty | Some occ -> occ let collapse_triechar t = - match Db.Types.Tchar.fold_map Succ.union Succ.of_set t with + match Trie.fold_map Succ.union Succ.of_set t with | None -> Succ.empty | Some s -> s let collapse_trie_with_poly ~count name t = match name with - | [ "POLY"; _ ] -> - let open T in - begin - match t with - | Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_count ~count s - | _ -> Succ.empty - end + | [ "POLY"; _ ] -> begin + match t with + | Trie.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_count ~count s + | _ -> Succ.empty + end | _ -> collapse_trie ~count t let find_inter ~shards names = @@ -41,7 +40,7 @@ let find_inter ~shards names = @@ List.map (fun (name, count) -> let name' = List.concat_map Db.list_of_string name in - collapse_trie_with_poly ~count name @@ T.find name' db) + collapse_trie_with_poly ~count name @@ Trie.find name' db) (regroup names) in Succ.union acc r) @@ -59,7 +58,7 @@ let find_names ~shards names = let candidates = List.map (fun name -> - let t = Tchar.find name db_names in + let t = Trie.find name db_names in collapse_triechar t) names in From c1a2dda444c3643e352dd1bde02fdf3f142aec59 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Mon, 24 Apr 2023 04:25:14 +0200 Subject: [PATCH 047/285] small size optim to js file --- bin/JSherlodoc/dune | 7 +++--- lib/db/db.ml | 5 ++-- lib/db/db.mli | 2 +- lib/db/types.ml | 16 ++++++++++++- lib/index_lib/docstring.ml | 18 ++++++++++++--- lib/index_lib/docstring.mli | 2 +- lib/index_lib/load_doc.ml | 45 +++++++++++++++++++++++++++--------- lib/storage_js/storage_js.ml | 3 ++- 8 files changed, 73 insertions(+), 25 deletions(-) diff --git a/bin/JSherlodoc/dune b/bin/JSherlodoc/dune index 44b8f165dc..7a2c3c89c8 100644 --- a/bin/JSherlodoc/dune +++ b/bin/JSherlodoc/dune @@ -1,5 +1,4 @@ (executable - (name main) - (modes js) - (libraries tyxml query storage_js brr)) - + (name main) + (modes js) + (libraries tyxml query storage_js brr)) diff --git a/lib/db/db.ml b/lib/db/db.ml index 644c1efc50..a492de6204 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -10,7 +10,7 @@ module type S = sig val optimize : unit -> unit val export : writer -> unit - val store_all : Elt_set.elt -> String_list_map.key list -> unit + val store_all : Elt_set.elt -> char list list -> unit val store_name : char list -> Elt_set.elt -> unit val load_counter : int ref end @@ -117,7 +117,6 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct r let store ~ho ~hs name typ ~count = - let name = List.concat_map list_of_string name in let rec go db name = match name with | [] -> db @@ -133,7 +132,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let hs = Hset.create 16 in List.iter (fun (path, count) -> store ~ho ~hs ~count path typ) - (regroup paths) + (regroup_chars paths) let store_name name typ = let hs = Hset.create 16 in diff --git a/lib/db/db.mli b/lib/db/db.mli index ba3f4df18c..c431d921ca 100644 --- a/lib/db/db.mli +++ b/lib/db/db.mli @@ -12,7 +12,7 @@ module type S = sig val optimize : unit -> unit val export : writer -> unit - val store_all : Elt_set.elt -> String_list_map.key list -> unit + val store_all : Elt_set.elt -> char list list -> unit val store_name : char list -> Elt_set.elt -> unit val load_counter : int ref end diff --git a/lib/db/types.ml b/lib/db/types.ml index 0d5aff6ca0..d769bc4949 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -40,7 +40,7 @@ end module String_list_map = Map.Make (struct type t = string list - let compare = Stdlib.compare + let compare = List.compare String.compare end) let regroup lst = @@ -51,6 +51,20 @@ let regroup lst = String_list_map.add s (count + 1) acc) String_list_map.empty lst +module Char_list_map = Map.Make (struct + type t = char list + + let compare = List.compare Char.compare +end) + +let regroup_chars lst = + Char_list_map.bindings + @@ List.fold_left + (fun acc s -> + let count = try Char_list_map.find s acc with Not_found -> 0 in + Char_list_map.add s (count + 1) acc) + Char_list_map.empty lst + module Int_map = Map.Make (Int) module Elt_set = Set.Make (Elt) module Occ = Int_map diff --git a/lib/index_lib/docstring.ml b/lib/index_lib/docstring.ml index 6839742d07..b2a3b29517 100644 --- a/lib/index_lib/docstring.ml +++ b/lib/index_lib/docstring.ml @@ -23,8 +23,8 @@ let words_of_resolved = function | r -> words_of_identifier r let words_of_reference = function - | `Root (r, _) -> [r] - | `Dot (_, n) -> [n] + | `Root (r, _) -> [ r ] + | `Dot (_, n) -> [ n ] | `Resolved r -> words_of_resolved r | r -> words_of_identifier r @@ -53,9 +53,21 @@ and words_of_paragraph lst = lst let words_of_doc = function - | `Paragraph p -> words_of_paragraph p + | `Paragraph p -> words_of_paragraph p | `Heading (_, _, p) -> words_of_link_content p | _ -> [] let words_of_docs lst = List.concat_map (fun elt -> words_of_doc elt.Odoc_model.Location_.value) lst + |> List.filter_map (fun word -> + let word = + word |> Db.list_of_string |> List.rev_map Char.lowercase_ascii + in + let word = + List.filter + (fun chr -> + (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9')) + word + in + if word = [] then None else Some word) + |> List.sort_uniq (List.compare Char.compare) diff --git a/lib/index_lib/docstring.mli b/lib/index_lib/docstring.mli index 1cdfaaffea..08683c37bf 100644 --- a/lib/index_lib/docstring.mli +++ b/lib/index_lib/docstring.mli @@ -1 +1 @@ -val words_of_docs : Odoc_model.Comment.docs -> string list +val words_of_docs : Odoc_model.Comment.docs -> char list list diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index e903262e91..3770e18a3f 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -12,6 +12,31 @@ module Make (Storage : Db.Storage.S) = struct let copy str = String.init (String.length str) (String.get str) end) + module Cache_list = struct + module H = Hashtbl.Make (struct + type t = char list + + let equal = List.equal Char.equal + let hash = Hashtbl.hash + end) + + let cache = H.create 128 + + let memo lst = + let rec go lst = + try H.find cache lst + with Not_found -> + let lst = + match lst with + | [] -> [] + | x :: xs -> x :: go xs + in + H.add cache lst lst ; + lst + in + go lst + end + let clear () = Cache.clear () let rec type_size = function @@ -118,9 +143,7 @@ module Make (Storage : Db.Storage.S) = struct Format.fprintf to_b "%a%s%!" Pretty.pp_path path (Odoc_model.Names.ValueName.to_string name) ; let full_name = Buffer.contents b in - let doc_words = - doc |> Docstring.words_of_docs |> List.sort_uniq String.compare - in + let doc_words = Docstring.words_of_docs doc in let doc = Option.map Cache.memo (Pretty.string_of_docs doc) in let cost = String.length full_name + String.length str_type @@ -142,11 +165,7 @@ module Make (Storage : Db.Storage.S) = struct } in List.iter - (fun word -> - let word = - word |> Db_common.list_of_string |> List.rev_map Char.lowercase_ascii - in - Db.store_name word str_type) + (fun word -> Db.store_name (Cache_list.memo word) str_type) doc_words ; let my_full_name = List.rev_append @@ -154,10 +173,14 @@ module Make (Storage : Db.Storage.S) = struct ('.' :: path_list) in let my_full_name = List.map Char.lowercase_ascii my_full_name in - Db.store_name my_full_name str_type ; - + Db.store_name (Cache_list.memo my_full_name) str_type ; let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in - Db.store_all str_type (List.map (List.map Cache.memo) type_paths) + Db.store_all str_type + (List.map + (fun xs -> + let xs = List.concat_map Db_common.list_of_string xs in + Cache_list.memo xs) + type_paths) let rec item ~pkg ~path_list ~path = let open Odoc_model.Lang in diff --git a/lib/storage_js/storage_js.ml b/lib/storage_js/storage_js.ml index 56df60efcc..d8cc423b66 100644 --- a/lib/storage_js/storage_js.ml +++ b/lib/storage_js/storage_js.ml @@ -2,6 +2,7 @@ type writer = out_channel let open_out = open_out let close_out = close_out + let save ~db t = let str = Marshal.to_string t [] in let str = Base64.encode_string str in @@ -9,4 +10,4 @@ let save ~db t = let load str = let str = Base64.decode_exn str in - [Marshal.from_string str 0] + [ Marshal.from_string str 0 ] From dd8de37040db452d876562abac1230be9cb8e018 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 24 Apr 2023 16:15:42 +0200 Subject: [PATCH 048/285] unstash --- lib/db/types.ml | 26 ++++++++++++++++++++++++-- lib/index_lib/load_doc.ml | 16 +++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/db/types.ml b/lib/db/types.ml index d769bc4949..2866717017 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -1,9 +1,31 @@ module Elt = struct + type kind = + | Type + | Val of + { str_type : string + (** A type can viewed as a tree. + [a -> b -> c * d] is the following tree : + {[ -> + |- a + |- -> + |- b + |- * + |- c + |- d + ]} + [type_paths] is the list of paths from root to leaf in the tree of + the type. There is an annotation to indicate the child's position. + Here it would be : + [ [["->";"0"; "a"];["->"; "1"; "->"; "0"; "b"]; ...] ] + + It is used to sort results. *) + ; type_paths : string list list + } + type t = { cost : int ; name : string - ; str_type : string - ; type_paths : string list list + ; kind : kind ; doc : string option ; pkg : string * string } diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 3770e18a3f..183d82c527 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -130,7 +130,7 @@ module Make (Storage : Db.Storage.S) = struct | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args | _ -> [] - let save_item ~pkg ~path_list ~path name type_ doc = + let save_item ~pkg ~path_list ~path ~kind name type_ doc = let b = Buffer.create 16 in let to_b = Format.formatter_of_buffer b in Format.fprintf to_b "%a%!" @@ -157,6 +157,7 @@ module Make (Storage : Db.Storage.S) = struct let paths = paths ~prefix:[] ~sgn:Pos type_ in let str_type = { Db_common.Elt.name = full_name + ; kind ; cost ; type_paths = paths ; str_type = Cache.memo str_type @@ -189,11 +190,20 @@ module Make (Storage : Db.Storage.S) = struct when Odoc_model.Names.ValueName.is_internal name -> () | Signature.Value { id = `Value (_, name); type_; doc; _ } -> - save_item ~pkg ~path_list ~path name type_ doc + save_item ~pkg ~path_list ~path ~kind:Val name type_ doc | Module (_, mdl) -> let name = Paths.Identifier.name mdl.id in if name = "Stdlib" then () else module_items ~pkg ~path_list ~path mdl - | Type (_, _) -> () + | Type + ( _ + , { id = `Type (_, name) | `CoreType name + ; doc + ; canonical + ; equation + ; representation + } ) -> + let name = name in + () | Include icl -> items ~pkg ~path_list ~path icl.expansion.content.items | TypeSubstitution _ -> () (* type t = Foo.t = actual_definition *) | TypExt _ -> () (* type t = .. *) From b04e882eadf1f1f07f9bf2f93aa4bf1c1c089daa Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 24 Apr 2023 17:09:23 +0200 Subject: [PATCH 049/285] search of types --- bin/JSherlodoc/main.ml | 17 +++--- bin/www/ui.ml | 23 +++++--- lib/db/types.ml | 2 +- lib/index_lib/load_doc.ml | 110 +++++++++++++++++++++----------------- lib/query/sort.ml | 6 ++- 5 files changed, 95 insertions(+), 63 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index a56b34e5e1..6f02165324 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -12,6 +12,15 @@ let raw_html str = let latest = ref 0 let count = ref 1 +let render_elt elt = + let open Db.Elt in + let open El in + match elt.kind with + | Db.Elt.Val { str_type; _ } -> + [ txt' "val "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' str_type ] + | Db.Elt.Type -> + [ txt' "type "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' "WIP" ] + let search ~id input = let query = El.prop El.Prop.value input |> Jstr.to_string in let _pretty_query, results = @@ -24,13 +33,7 @@ let search ~id input = El.( div ~at:At.[ class' (Jstr.of_string "result") ] - ([ code - [ txt' "val " - ; em [ txt' elt.Db.Elt.name ] - ; txt' " : " - ; txt' elt.Db.Elt.str_type - ] - ] + ([ code (render_elt elt) ] @ match elt.Db.Elt.doc with | None -> [] diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 49d6516d79..b05af9c038 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -4,6 +4,22 @@ let list_of_option = function | None -> [] | Some x -> [ x ] +let render_elt elt = + let open Db.Elt in + match elt.kind with + | Db.Elt.Val { str_type; _ } -> + [ txt "val " + ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + ; txt " : " + ; txt str_type + ] + | Db.Elt.Type -> + [ txt "type " + ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + ; txt " = " + ; txt "WIP" + ] + let render_result r = let open Db.Types.Elt in div @@ -15,12 +31,7 @@ let render_result r = ; span ~a:[ a_class [ "version" ] ] [ txt (snd r.pkg) ] ] ] - :: pre - [ txt "val " - ; a ~a:[ a_href (link r) ] [ em [ txt r.name ] ] - ; txt " : " - ; txt r.str_type - ] + :: pre (render_elt r) :: list_of_option (Option.map Unsafe.data r.doc) let render ~pretty results = diff --git a/lib/db/types.ml b/lib/db/types.ml index 2866717017..54951f4c0b 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -38,7 +38,7 @@ module Elt = struct match String.compare a.name b.name with | 0 -> begin match compare_pkg a.pkg b.pkg with - | 0 -> String.compare a.str_type b.str_type + | 0 -> Stdlib.compare a.kind b.kind | c -> c end | c -> c diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 183d82c527..9471292da7 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -130,59 +130,81 @@ module Make (Storage : Db.Storage.S) = struct | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args | _ -> [] - let save_item ~pkg ~path_list ~path ~kind name type_ doc = - let b = Buffer.create 16 in - let to_b = Format.formatter_of_buffer b in - Format.fprintf to_b "%a%!" - (Pretty.show_type - ~path:(Pretty.fmt_to_string (fun h -> Pretty.pp_path h path)) - ~parens:false) - type_ ; - let str_type = Buffer.contents b in - Buffer.reset b ; - Format.fprintf to_b "%a%s%!" Pretty.pp_path path - (Odoc_model.Names.ValueName.to_string name) ; - let full_name = Buffer.contents b in + let save_doc elt doc = let doc_words = Docstring.words_of_docs doc in - let doc = Option.map Cache.memo (Pretty.string_of_docs doc) in + List.iter (fun word -> Db.store_name (Cache_list.memo word) elt) doc_words + + let save_full_name path_list name elt = + let my_full_name = + List.rev_append (Db_common.list_of_string name) ('.' :: path_list) + in + let my_full_name = List.map Char.lowercase_ascii my_full_name in + Db.store_name (Cache_list.memo my_full_name) elt + + let generic_cost full_name path str_doc = + String.length full_name + + (5 * List.length path) + + (match str_doc with + | None -> 1000 + | _ -> 0) + + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 + + let save_val ~pkg ~path_list ~path name type_ doc = + let str_type = + Format.kasprintf Cache.memo "%a%!" + (Pretty.show_type + ~path:(Pretty.fmt_to_string (fun h -> Pretty.pp_path h path)) + ~parens:false) + type_ + in + let full_name = + Format.asprintf "%a%s%!" Pretty.pp_path path + (Odoc_model.Names.ValueName.to_string name) + in + + let str_doc = Option.map Cache.memo (Pretty.string_of_docs doc) in let cost = - String.length full_name + String.length str_type - + (5 * List.length path) - + type_size type_ - + (match doc with - | None -> 1000 - | _ -> 0) - + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 + generic_cost full_name path str_doc + + String.length str_type + type_size type_ in let paths = paths ~prefix:[] ~sgn:Pos type_ in - let str_type = + let elt = { Db_common.Elt.name = full_name - ; kind + ; kind = Db_common.Elt.Val { type_paths = paths; str_type } ; cost - ; type_paths = paths - ; str_type = Cache.memo str_type - ; doc + ; doc = str_doc ; pkg } in - List.iter - (fun word -> Db.store_name (Cache_list.memo word) str_type) - doc_words ; - let my_full_name = - List.rev_append - (Db_common.list_of_string (Odoc_model.Names.ValueName.to_string name)) - ('.' :: path_list) - in - let my_full_name = List.map Char.lowercase_ascii my_full_name in - Db.store_name (Cache_list.memo my_full_name) str_type ; + save_doc elt doc ; + save_full_name path_list (Odoc_model.Names.ValueName.to_string name) elt ; let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in - Db.store_all str_type + Db.store_all elt (List.map (fun xs -> let xs = List.concat_map Db_common.list_of_string xs in Cache_list.memo xs) type_paths) + let save_type ~pkg ~path_list ~path name doc = + let full_name = + Format.asprintf "%a%s%!" Pretty.pp_path path + (Odoc_model.Names.TypeName.to_string name) + in + + let str_doc = Option.map Cache.memo (Pretty.string_of_docs doc) in + let cost = generic_cost full_name path str_doc in + let elt = + { Db_common.Elt.name = full_name + ; kind = Db_common.Elt.Type + ; cost + ; doc = str_doc + ; pkg + } + in + save_doc elt doc ; + save_full_name path_list (Odoc_model.Names.TypeName.to_string name) elt + let rec item ~pkg ~path_list ~path = let open Odoc_model.Lang in function @@ -190,20 +212,12 @@ module Make (Storage : Db.Storage.S) = struct when Odoc_model.Names.ValueName.is_internal name -> () | Signature.Value { id = `Value (_, name); type_; doc; _ } -> - save_item ~pkg ~path_list ~path ~kind:Val name type_ doc + save_val ~pkg ~path_list ~path name type_ doc | Module (_, mdl) -> let name = Paths.Identifier.name mdl.id in if name = "Stdlib" then () else module_items ~pkg ~path_list ~path mdl - | Type - ( _ - , { id = `Type (_, name) | `CoreType name - ; doc - ; canonical - ; equation - ; representation - } ) -> - let name = name in - () + | Type (_, { id = `Type (_, name) | `CoreType name; doc; _ }) -> + save_type ~pkg ~path_list ~path name doc | Include icl -> items ~pkg ~path_list ~path icl.expansion.content.items | TypeSubstitution _ -> () (* type t = Foo.t = actual_definition *) | TypExt _ -> () (* type t = .. *) diff --git a/lib/query/sort.ml b/lib/query/sort.ml index 4ca6f14105..5ce1ee445e 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -148,7 +148,11 @@ let list query_name query_type results = (fun a -> let open Elt in let name_cost = score_name query_name a.name in - let type_cost = score_type query_type a.type_paths in + let type_cost = + match a.kind with + | Val { type_paths; _ } -> score_type query_type type_paths + | Type -> 0 + in let cost = a.Elt.cost + (2 * name_cost) + (800 * type_cost) in { a with cost }) results From 38dc4b1fda03976a8756b02d045a080aa370fb21 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 25 Apr 2023 16:36:43 +0200 Subject: [PATCH 050/285] now supports search for module --- bin/JSherlodoc/main.ml | 1 + bin/www/ui.ml | 2 ++ lib/db/types.ml | 2 +- lib/index_lib/load_doc.ml | 51 +++++++++++++++++++++++---------------- lib/query/sort.ml | 2 +- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 6f02165324..63bca4bcba 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -20,6 +20,7 @@ let render_elt elt = [ txt' "val "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' str_type ] | Db.Elt.Type -> [ txt' "type "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' "WIP" ] + | Db.Elt.Module -> [ txt' "module "; em [ txt' elt.Db.Elt.name ] ] let search ~id input = let query = El.prop El.Prop.value input |> Jstr.to_string in diff --git a/bin/www/ui.ml b/bin/www/ui.ml index b05af9c038..94d1089238 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -19,6 +19,8 @@ let render_elt elt = ; txt " = " ; txt "WIP" ] + | Db.Elt.Module -> + [ txt "module "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] let render_result r = let open Db.Types.Elt in diff --git a/lib/db/types.ml b/lib/db/types.ml index 54951f4c0b..ba0e71c270 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -1,6 +1,6 @@ module Elt = struct type kind = - | Type + | Type | Module | Val of { str_type : string (** A type can viewed as a tree. diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 9471292da7..5dd65f9847 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -141,12 +141,15 @@ module Make (Storage : Db.Storage.S) = struct let my_full_name = List.map Char.lowercase_ascii my_full_name in Db.store_name (Cache_list.memo my_full_name) elt - let generic_cost full_name path str_doc = + let generic_cost ~is_module full_name path str_doc = String.length full_name + (5 * List.length path) - + (match str_doc with - | None -> 1000 - | _ -> 0) + + (if is_module + then 0 + else + match str_doc with + | None -> 1000 + | _ -> 0) + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 let save_val ~pkg ~path_list ~path name type_ doc = @@ -164,7 +167,7 @@ module Make (Storage : Db.Storage.S) = struct let str_doc = Option.map Cache.memo (Pretty.string_of_docs doc) in let cost = - generic_cost full_name path str_doc + generic_cost ~is_module:false full_name path str_doc + String.length str_type + type_size type_ in let paths = paths ~prefix:[] ~sgn:Pos type_ in @@ -186,24 +189,20 @@ module Make (Storage : Db.Storage.S) = struct Cache_list.memo xs) type_paths) - let save_type ~pkg ~path_list ~path name doc = - let full_name = - Format.asprintf "%a%s%!" Pretty.pp_path path - (Odoc_model.Names.TypeName.to_string name) - in - + let save_named_elt ~pkg ~path_list ~path ~kind name doc = + let full_name = Format.asprintf "%a%s%!" Pretty.pp_path path name in let str_doc = Option.map Cache.memo (Pretty.string_of_docs doc) in - let cost = generic_cost full_name path str_doc in + let is_module = + match kind with + | Db_common.Elt.Module -> true + | _ -> false + in + let cost = generic_cost ~is_module full_name path str_doc in let elt = - { Db_common.Elt.name = full_name - ; kind = Db_common.Elt.Type - ; cost - ; doc = str_doc - ; pkg - } + { Db_common.Elt.name = full_name; kind; cost; doc = str_doc; pkg } in save_doc elt doc ; - save_full_name path_list (Odoc_model.Names.TypeName.to_string name) elt + save_full_name path_list name elt let rec item ~pkg ~path_list ~path = let open Odoc_model.Lang in @@ -213,11 +212,21 @@ module Make (Storage : Db.Storage.S) = struct () | Signature.Value { id = `Value (_, name); type_; doc; _ } -> save_val ~pkg ~path_list ~path name type_ doc - | Module (_, mdl) -> + | Module + ( _ + , ({ id = `Module (_, name) | `Root (_, name) + ; doc + ; hidden = + _ (* TODO : should hidden modules show up in search results ?*) + ; _ + } as mdl) ) -> + let name = Odoc_model.Names.ModuleName.to_string name in + save_named_elt ~pkg ~path_list ~path ~kind:Module name doc ; let name = Paths.Identifier.name mdl.id in if name = "Stdlib" then () else module_items ~pkg ~path_list ~path mdl | Type (_, { id = `Type (_, name) | `CoreType name; doc; _ }) -> - save_type ~pkg ~path_list ~path name doc + let name = Odoc_model.Names.TypeName.to_string name in + save_named_elt ~pkg ~path_list ~path ~kind:Type name doc | Include icl -> items ~pkg ~path_list ~path icl.expansion.content.items | TypeSubstitution _ -> () (* type t = Foo.t = actual_definition *) | TypExt _ -> () (* type t = .. *) diff --git a/lib/query/sort.ml b/lib/query/sort.ml index 5ce1ee445e..51a33ad77e 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -151,7 +151,7 @@ let list query_name query_type results = let type_cost = match a.kind with | Val { type_paths; _ } -> score_type query_type type_paths - | Type -> 0 + | Type | Module -> 0 in let cost = a.Elt.cost + (2 * name_cost) + (800 * type_cost) in { a with cost }) From 669ce1c4dab200b22a3f8532e2500c6b00057610 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 25 Apr 2023 16:54:04 +0200 Subject: [PATCH 051/285] Search for exceptions and module types --- bin/JSherlodoc/main.ml | 2 ++ bin/www/ui.ml | 4 ++++ lib/db/types.ml | 2 +- lib/index_lib/load_doc.ml | 20 ++++++++++++-------- lib/query/sort.ml | 2 +- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 63bca4bcba..8525c6438b 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -21,6 +21,8 @@ let render_elt elt = | Db.Elt.Type -> [ txt' "type "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' "WIP" ] | Db.Elt.Module -> [ txt' "module "; em [ txt' elt.Db.Elt.name ] ] + | Db.Elt.ModuleType -> [ txt' "module type"; em [ txt' elt.Db.Elt.name ] ] + | Db.Elt.Exception -> [ txt' "exception "; em [ txt' elt.Db.Elt.name ] ] let search ~id input = let query = El.prop El.Prop.value input |> Jstr.to_string in diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 94d1089238..8614327cca 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -21,6 +21,10 @@ let render_elt elt = ] | Db.Elt.Module -> [ txt "module "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | Db.Elt.ModuleType -> + [ txt "module type "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | Db.Elt.Exception -> + [ txt "exception "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] let render_result r = let open Db.Types.Elt in diff --git a/lib/db/types.ml b/lib/db/types.ml index ba0e71c270..913b0bcde9 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -1,6 +1,6 @@ module Elt = struct type kind = - | Type | Module + | Type | Module | ModuleType | Exception | Val of { str_type : string (** A type can viewed as a tree. diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 5dd65f9847..a4600466f4 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -141,10 +141,10 @@ module Make (Storage : Db.Storage.S) = struct let my_full_name = List.map Char.lowercase_ascii my_full_name in Db.store_name (Cache_list.memo my_full_name) elt - let generic_cost ~is_module full_name path str_doc = + let generic_cost ~ignore_no_doc full_name path str_doc = String.length full_name + (5 * List.length path) - + (if is_module + + (if ignore_no_doc then 0 else match str_doc with @@ -167,7 +167,7 @@ module Make (Storage : Db.Storage.S) = struct let str_doc = Option.map Cache.memo (Pretty.string_of_docs doc) in let cost = - generic_cost ~is_module:false full_name path str_doc + generic_cost ~ignore_no_doc:false full_name path str_doc + String.length str_type + type_size type_ in let paths = paths ~prefix:[] ~sgn:Pos type_ in @@ -192,12 +192,12 @@ module Make (Storage : Db.Storage.S) = struct let save_named_elt ~pkg ~path_list ~path ~kind name doc = let full_name = Format.asprintf "%a%s%!" Pretty.pp_path path name in let str_doc = Option.map Cache.memo (Pretty.string_of_docs doc) in - let is_module = + let ignore_no_doc = match kind with - | Db_common.Elt.Module -> true + | Db_common.Elt.(Module | ModuleType) -> true | _ -> false in - let cost = generic_cost ~is_module full_name path str_doc in + let cost = generic_cost ~ignore_no_doc full_name path str_doc in let elt = { Db_common.Elt.name = full_name; kind; cost; doc = str_doc; pkg } in @@ -230,12 +230,16 @@ module Make (Storage : Db.Storage.S) = struct | Include icl -> items ~pkg ~path_list ~path icl.expansion.content.items | TypeSubstitution _ -> () (* type t = Foo.t = actual_definition *) | TypExt _ -> () (* type t = .. *) - | Exception _ -> () + | Exception { id = `Exception (_, name) | `CoreException name; doc; _ } -> + let name = Odoc_model.Names.ExceptionName.to_string name in + save_named_elt ~pkg ~path_list ~path ~kind:Exception name doc | Class _ -> () | ClassType _ -> () | Comment _ -> () | Open _ -> () - | ModuleType _ -> () + | ModuleType { id = `ModuleType (_, name); doc; _ } -> + let name = Odoc_model.Names.ModuleTypeName.to_string name in + save_named_elt ~pkg ~path_list ~path ~kind:ModuleType name doc | ModuleSubstitution _ -> () | ModuleTypeSubstitution _ -> () diff --git a/lib/query/sort.ml b/lib/query/sort.ml index 51a33ad77e..72a5e79e23 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -151,7 +151,7 @@ let list query_name query_type results = let type_cost = match a.kind with | Val { type_paths; _ } -> score_type query_type type_paths - | Type | Module -> 0 + | Type | Module | ModuleType | Exception -> 0 in let cost = a.Elt.cost + (2 * name_cost) + (800 * type_cost) in { a with cost }) From 55aabdefea1b35a59a16a00648f4d1b4b9f17bb1 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 26 Apr 2023 14:45:02 +0200 Subject: [PATCH 052/285] Compatible with latest odoc version --- lib/db/types.ml | 5 +- lib/index_lib/docstring.ml | 49 ++++++++-------- lib/index_lib/load_doc.ml | 19 ++++--- lib/index_lib/pretty.ml | 114 ++++++++++++++++++++----------------- sherlodoc.opam | 2 +- 5 files changed, 104 insertions(+), 85 deletions(-) diff --git a/lib/db/types.ml b/lib/db/types.ml index 913b0bcde9..518b5ff161 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -1,6 +1,9 @@ module Elt = struct type kind = - | Type | Module | ModuleType | Exception + | Type + | Module + | ModuleType + | Exception | Val of { str_type : string (** A type can viewed as a tree. diff --git a/lib/index_lib/docstring.ml b/lib/index_lib/docstring.ml index b2a3b29517..977955afa6 100644 --- a/lib/index_lib/docstring.ml +++ b/lib/index_lib/docstring.ml @@ -1,41 +1,40 @@ open Odoc_model let words_of_string s = String.split_on_char ' ' s - -let words_of_identifier = function - | `Class (_, n) -> [ Names.ClassName.to_string n ] - | `ClassType (_, n) -> [ Names.ClassTypeName.to_string n ] - | `Constructor (_, n) -> [ Names.ConstructorName.to_string n ] - | `Exception (_, n) -> [ Names.ExceptionName.to_string n ] - | `Extension (_, n) -> [ Names.ExtensionName.to_string n ] - | `Field (_, n) -> [ Names.FieldName.to_string n ] - | `InstanceVariable (_, n) -> [ Names.InstanceVariableName.to_string n ] - | `Label (_, n) -> [ Names.LabelName.to_string n ] - | `Method (_, n) -> [ Names.MethodName.to_string n ] - | `Module (_, n) -> [ Names.ModuleName.to_string n ] - | `ModuleType (_, n) -> [ Names.ModuleTypeName.to_string n ] - | `Type (_, n) -> [ Names.TypeName.to_string n ] - | `Value (_, n) -> [ Names.ValueName.to_string n ] - | _ -> [] +let words_of_identifier id = [ Comment.Identifier.name id ] let words_of_resolved = function | `Identifier v -> words_of_identifier v - | r -> words_of_identifier r + | r -> words_of_identifier (Comment.Reference.Resolved.identifier r) -let words_of_reference = function +let words_of_reference : Comment.Reference.t -> _ = function | `Root (r, _) -> [ r ] | `Dot (_, n) -> [ n ] | `Resolved r -> words_of_resolved r - | r -> words_of_identifier r + | `InstanceVariable (_, name) -> [ Names.InstanceVariableName.to_string name ] + | `Module (_, name) -> [ Names.ModuleName.to_string name ] + | `ModuleType (_, name) -> [ Names.ModuleTypeName.to_string name ] + | `Method (_, name) -> [ Names.MethodName.to_string name ] + | `Field (_, name) -> [ Names.FieldName.to_string name ] + | `Label (_, name) -> [ Names.LabelName.to_string name ] + | `Type (_, name) -> [ Names.TypeName.to_string name ] + | `Exception (_, name) -> [ Names.ExceptionName.to_string name ] + | `Class (_, name) -> [ Names.ClassName.to_string name ] + | `ClassType (_, name) -> [ Names.ClassTypeName.to_string name ] + | `Value (_, name) -> [ Names.ValueName.to_string name ] + | `Constructor (_, name) -> [ Names.ConstructorName.to_string name ] + | `Extension (_, name) -> [ Names.ExtensionName.to_string name ] -let rec words_of_non_link = function +let rec words_of_non_link : Comment.non_link_inline_element -> _ = function + | `Math_span s -> words_of_string s | `Space -> [] | `Word w -> [ w ] | `Code_span s -> words_of_string s | `Raw_markup (_, _s) -> [] | `Styled (_, lst) -> words_of_link_content lst -and words_of_element = function +and words_of_element : Comment.inline_element -> _ = function + | `Math_span s -> words_of_string s | `Styled (_, lst) -> words_of_paragraph lst | `Reference (r, _) -> words_of_reference r | `Link (_, r) -> words_of_link_content r @@ -44,20 +43,20 @@ and words_of_element = function | `Code_span s -> words_of_string s | `Raw_markup (_, _s) -> [] -and words_of_link_content lst = +and words_of_link_content (lst : Comment.link_content) = List.concat_map (fun r -> words_of_non_link r.Odoc_model.Location_.value) lst -and words_of_paragraph lst = +and words_of_paragraph (lst : Comment.paragraph) = List.concat_map (fun elt -> words_of_element elt.Odoc_model.Location_.value) lst -let words_of_doc = function +let words_of_doc : Comment.block_element -> _ = function | `Paragraph p -> words_of_paragraph p | `Heading (_, _, p) -> words_of_link_content p | _ -> [] -let words_of_docs lst = +let words_of_docs (lst : Odoc_model.Comment.docs) = List.concat_map (fun elt -> words_of_doc elt.Odoc_model.Location_.value) lst |> List.filter_map (fun word -> let word = diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index a4600466f4..02bfa9fc08 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -152,7 +152,7 @@ module Make (Storage : Db.Storage.S) = struct | _ -> 0) + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 - let save_val ~pkg ~path_list ~path name type_ doc = + let save_val ~pkg ~path_list ~path name type_ (doc : Comment.docs) = let str_type = Format.kasprintf Cache.memo "%a%!" (Pretty.show_type @@ -207,14 +207,17 @@ module Make (Storage : Db.Storage.S) = struct let rec item ~pkg ~path_list ~path = let open Odoc_model.Lang in function - | Signature.Value { id = `Value (_, name); _ } + | Signature.Value { id = { iv = `Value (_, name); _ }; _ } when Odoc_model.Names.ValueName.is_internal name -> () - | Signature.Value { id = `Value (_, name); type_; doc; _ } -> + | Signature.Value { id = { iv = `Value (_, name); _ }; type_; doc; _ } -> save_val ~pkg ~path_list ~path name type_ doc | Module ( _ - , ({ id = `Module (_, name) | `Root (_, name) + , ({ id = + { iv = `Module (_, name) | `Root (_, name) | `Parameter (_, name) + ; _ + } ; doc ; hidden = _ (* TODO : should hidden modules show up in search results ?*) @@ -224,20 +227,22 @@ module Make (Storage : Db.Storage.S) = struct save_named_elt ~pkg ~path_list ~path ~kind:Module name doc ; let name = Paths.Identifier.name mdl.id in if name = "Stdlib" then () else module_items ~pkg ~path_list ~path mdl - | Type (_, { id = `Type (_, name) | `CoreType name; doc; _ }) -> + | Type (_, { id = { iv = `Type (_, name) | `CoreType name; _ }; doc; _ }) -> let name = Odoc_model.Names.TypeName.to_string name in save_named_elt ~pkg ~path_list ~path ~kind:Type name doc | Include icl -> items ~pkg ~path_list ~path icl.expansion.content.items | TypeSubstitution _ -> () (* type t = Foo.t = actual_definition *) | TypExt _ -> () (* type t = .. *) - | Exception { id = `Exception (_, name) | `CoreException name; doc; _ } -> + | Exception + { id = { iv = `Exception (_, name) | `CoreException name; _ }; doc; _ } + -> let name = Odoc_model.Names.ExceptionName.to_string name in save_named_elt ~pkg ~path_list ~path ~kind:Exception name doc | Class _ -> () | ClassType _ -> () | Comment _ -> () | Open _ -> () - | ModuleType { id = `ModuleType (_, name); doc; _ } -> + | ModuleType { id = { iv = `ModuleType (_, name); _ }; doc; _ } -> let name = Odoc_model.Names.ModuleTypeName.to_string name in save_named_elt ~pkg ~path_list ~path ~kind:ModuleType name doc | ModuleSubstitution _ -> () diff --git a/lib/index_lib/pretty.ml b/lib/index_lib/pretty.ml index 83533d7759..443a488770 100644 --- a/lib/index_lib/pretty.ml +++ b/lib/index_lib/pretty.ml @@ -10,40 +10,40 @@ let fmt_to_string f = Format.fprintf to_b "%!" ; Buffer.contents b -let string_of_identifier = function - | `Class (_, n) -> Names.ClassName.to_string n - | `ClassType (_, n) -> Names.ClassTypeName.to_string n - | `Constructor (_, n) -> Names.ConstructorName.to_string n - | `Exception (_, n) -> Names.ExceptionName.to_string n - | `Extension (_, n) -> Names.ExtensionName.to_string n - | `Field (_, n) -> Names.FieldName.to_string n - | `InstanceVariable (_, n) -> Names.InstanceVariableName.to_string n - | `Label (_, n) -> Names.LabelName.to_string n - | `Method (_, n) -> Names.MethodName.to_string n - | `Module (_, n) -> ModuleName.to_string n - | `ModuleType (_, n) -> Names.ModuleTypeName.to_string n - | `Type (_, n) -> Names.TypeName.to_string n - | `Value (_, n) -> Names.ValueName.to_string n - | _ -> "" +let string_of_identifier = Comment.Identifier.name let string_of_resolved = function | `Identifier v -> string_of_identifier v - | r -> string_of_identifier r + | r -> string_of_identifier (Comment.Reference.Resolved.identifier r) -let string_of_reference = function +let string_of_reference : Comment.Reference.t -> _ = function | `Root (r, _) -> r | `Dot (_, n) -> n | `Resolved r -> string_of_resolved r - | r -> string_of_identifier r - -let rec string_of_non_link = function + | `InstanceVariable (_, name) -> Names.InstanceVariableName.to_string name + | `Module (_, name) -> Names.ModuleName.to_string name + | `ModuleType (_, name) -> Names.ModuleTypeName.to_string name + | `Method (_, name) -> Names.MethodName.to_string name + | `Field (_, name) -> Names.FieldName.to_string name + | `Label (_, name) -> Names.LabelName.to_string name + | `Type (_, name) -> Names.TypeName.to_string name + | `Exception (_, name) -> Names.ExceptionName.to_string name + | `Class (_, name) -> Names.ClassName.to_string name + | `ClassType (_, name) -> Names.ClassTypeName.to_string name + | `Value (_, name) -> Names.ValueName.to_string name + | `Constructor (_, name) -> Names.ConstructorName.to_string name + | `Extension (_, name) -> Names.ExtensionName.to_string name + +let rec string_of_non_link : Comment.non_link_inline_element -> _ = function + | `Math_span s -> H.txt s | `Space -> H.txt " " | `Word w -> H.txt w | `Code_span s -> H.code [ H.txt s ] | `Raw_markup (_, s) -> H.txt s | `Styled (_, lst) -> string_of_link_content lst -and string_of_element = function +and string_of_element : Comment.inline_element -> _ = function + | `Math_span s -> H.txt s | `Styled (_, lst) -> string_of_paragraph lst | `Reference (r, _) -> H.code [ H.txt (string_of_reference r) ] | `Link (_, r) -> string_of_link_content r @@ -52,42 +52,57 @@ and string_of_element = function | `Code_span s -> H.code [ H.txt s ] | `Raw_markup (_, s) -> H.txt s -and string_of_link_content lst = +and string_of_link_content (lst : Comment.link_content) = H.span (List.map (fun r -> string_of_non_link r.Odoc_model.Location_.value) lst) -and string_of_paragraph lst = +and string_of_paragraph (lst : Comment.paragraph) = H.span (List.map (fun elt -> string_of_element elt.Odoc_model.Location_.value) lst) -let string_of_doc = function +let string_of_doc : Comment.block_element -> _ = function | `Paragraph p -> Some (H.p [ string_of_paragraph p ]) | `Heading (_, _, p) -> Some (H.p [ string_of_link_content p ]) | _ -> None -let html_of_docs lst = +let html_of_docs (lst : Comment.docs) = List.find_map (fun elt -> string_of_doc elt.Odoc_model.Location_.value) lst -let string_of_docs doc = +let string_of_docs (doc : Comment.docs) = let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) in Option.map string_of_html (html_of_docs doc) -let make_root ~module_name ~digest = +let make_root ~module_name ~digest : (_, _) result = let file = Odoc_file.create_unit ~force_hidden:false module_name in - Ok { id = `Root (None, ModuleName.make_std module_name); file; digest } + let root = `Root (None, ModuleName.make_std module_name) in + let odocoid (* odocoids are powerful drugs *) = + Paths.Identifier.{ iv = root; ihash = 0; ikey = "" } + in + let r : t = { id = odocoid; file; digest } in + Ok r let show_module_name h md = Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) -let show_module_ident h = function - | `Module (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) - | `Root (_, name) -> Format.fprintf h "%S" (Names.ModuleName.to_string name) - | _ -> Format.fprintf h "!!module!!" +let rec show_ident_long h (r : Paths.Identifier.t_pv Paths.Identifier.id) = + match r.Paths.Identifier.iv with + | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) + | `Type (md, n) -> + Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) + | _ -> Format.fprintf h "%S" (Paths.Identifier.name r) + +and show_ident_short h (r : Paths.Identifier.t_pv Paths.Identifier.id) = + match r.Paths.Identifier.iv with + | `Type (_, n) -> Format.fprintf h "%s" (Names.TypeName.to_string n) + | `CoreType n -> Format.fprintf h "%s" (Names.TypeName.to_string n) + | _ -> Format.fprintf h "%S" (Paths.Identifier.name r) -let rec show_module_t h = function +and show_module_t h = function | `Resolved t -> let open Paths.Path in - Format.fprintf h "%a" show_module_ident (Resolved.Module.identifier t) + Format.fprintf h "%a" show_ident_long + (Resolved.Module.identifier t + :> Paths.Identifier.t_pv Paths.Identifier.id) | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x | `Root x -> Format.fprintf h "%s" x | `Apply (m, _) -> Format.fprintf h "%a(_)" show_module_t m @@ -113,13 +128,14 @@ and show_module_path h = function Format.fprintf h "" show_module_path pt show_module_path md | `OpaqueModule _ -> Format.fprintf h "" -and show_signature h = function +and show_signature h sig_ = + match sig_.iv with | `Root (_, name) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) | `Module (pt, mdl) -> Format.fprintf h "%a.%a" show_signature pt show_module_name mdl | `Parameter (_, p) -> - Format.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string p) + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string p) | `Result t -> Format.fprintf h "%a" show_signature t | `ModuleType (_, p) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) @@ -130,22 +146,18 @@ let show_ident_verbose h = function | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) | _ -> Format.fprintf h "show_ident?" -let show_ident_short h = function - | `Type (_, n) -> Format.fprintf h "%s" (Names.TypeName.to_string n) - | `CoreType n -> Format.fprintf h "%s" (Names.TypeName.to_string n) - | _ -> Format.fprintf h "show_ident?" - -let show_type_name_verbose h = function +let show_type_name_verbose h : Paths.Path.Type.t -> _ = function | `Resolved t -> let open Paths.Path in - Format.fprintf h "%a" show_ident_verbose (Resolved.Type.identifier t) + Format.fprintf h "%a" show_ident_long + (Resolved.identifier (t :> Resolved.t)) | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x let show_type_name_short h = function | `Resolved t -> let open Paths.Path in - Format.fprintf h "%a" show_ident_short (Resolved.Type.identifier t) + Format.fprintf h "%a" show_ident_short (Resolved.identifier t) | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b | `Dot (_mdl, x) -> Format.fprintf h "%s" x @@ -156,7 +168,7 @@ let strip ~prefix str = (String.length str - String.length prefix) else str -let show_type_name ~path h t = +let show_type_name ~path h (t : Paths.Path.Type.t) = let blah = fmt_to_string (fun h -> show_type_name_verbose h t) in let blah = strip ~prefix:path blah in let blah = strip ~prefix:"Stdlib." blah in @@ -168,10 +180,10 @@ let show_moduletype_ident h = function let show_moduletype_name h = function | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_moduletype_ident - (Resolved.ModuleType.identifier t) - | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + Format.fprintf h "%a" show_ident_long + (Paths.Reference.Resolved.identifier t) + | `Identifier (_, b) -> + Format.fprintf h "This is a bug in sherlodoc : IDENT%b" b | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x let show_label h = function @@ -190,8 +202,8 @@ let show_type_repr h = function let show_functor_param h = function | Lang.FunctorParameter.Unit -> Printf.fprintf h "UNIT" - | Named { id = `Parameter (_, md); expr = _ } -> - Printf.fprintf h "%s" (Odoc_model.Names.ParameterName.to_string md) + | Named { id = { iv = `Parameter (_, md); _ }; expr = _ } -> + Printf.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) let type_no_parens = function | Odoc_model.Lang.TypeExpr.Var _ | Any | Constr _ | Tuple _ -> true diff --git a/sherlodoc.opam b/sherlodoc.opam index 1b9de2484b..a61540f185 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -12,7 +12,7 @@ depends: [ "ancient" "dream" "fpath" - "odoc" {= "2.1.0"} + "odoc" {= "2.2.0"} "opam-core" "tyxml" ] From 14b1146e4c2f96114b5c001a9b382117900b5ddf Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 2 May 2023 18:21:13 +0200 Subject: [PATCH 053/285] Use odoc index WIP support of typedecl --- bin/JSherlodoc/main.ml | 29 +++- bin/index/dune | 8 +- bin/index/index.ml | 14 +- bin/www/ui.ml | 50 ++++++- lib/db/types.ml | 16 ++- lib/index_lib/docstring.ml | 72 ---------- lib/index_lib/docstring.mli | 1 - lib/index_lib/dune | 1 + lib/index_lib/files.ml | 57 -------- lib/index_lib/files.mli | 5 - lib/index_lib/index_lib.ml | 23 +-- lib/index_lib/index_lib.mli | 2 +- lib/index_lib/load_doc.ml | 275 +++++++++++++++--------------------- lib/index_lib/load_doc.mli | 2 +- lib/index_lib/pretty.ml | 191 ------------------------- lib/query/parser.mly | 3 + lib/query/sort.ml | 6 +- sherlodoc.opam | 2 +- 18 files changed, 226 insertions(+), 531 deletions(-) delete mode 100644 lib/index_lib/docstring.ml delete mode 100644 lib/index_lib/docstring.mli delete mode 100644 lib/index_lib/files.ml delete mode 100644 lib/index_lib/files.mli diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 8525c6438b..68ba2c04f9 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -16,13 +16,30 @@ let render_elt elt = let open Db.Elt in let open El in match elt.kind with - | Db.Elt.Val { str_type; _ } -> + | Val { str_type; _ } -> [ txt' "val "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' str_type ] - | Db.Elt.Type -> - [ txt' "type "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' "WIP" ] - | Db.Elt.Module -> [ txt' "module "; em [ txt' elt.Db.Elt.name ] ] - | Db.Elt.ModuleType -> [ txt' "module type"; em [ txt' elt.Db.Elt.name ] ] - | Db.Elt.Exception -> [ txt' "exception "; em [ txt' elt.Db.Elt.name ] ] + | Doc -> [ txt' "Doc "; em [ txt' elt.Db.Elt.name ] ] + | TypeDecl { html = type_decl } -> + [ txt' "type "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' type_decl ] + | Module -> [ txt' "Module "; em [ txt' elt.Db.Elt.name ] ] + | Exception -> [ txt' "Exception "; em [ txt' elt.Db.Elt.name ] ] + | Class_type -> [ txt' "Class_type "; em [ txt' elt.Db.Elt.name ] ] + | Method -> [ txt' "Method "; em [ txt' elt.Db.Elt.name ] ] + | Class -> [ txt' "Class "; em [ txt' elt.Db.Elt.name ] ] + | TypeExtension -> [ txt' "TypeExtension "; em [ txt' elt.Db.Elt.name ] ] + | ExtensionConstructor -> + [ txt' "ExtensionConstructor "; em [ txt' elt.Db.Elt.name ] ] + | ModuleType -> [ txt' "ModuleType "; em [ txt' elt.Db.Elt.name ] ] + | Constructor -> [ txt' "Constructor "; em [ txt' elt.Db.Elt.name ] ] + | Field -> [ txt' "Field "; em [ txt' elt.Db.Elt.name ] ] + | FunctorParameter -> + [ txt' "FunctorParameter "; em [ txt' elt.Db.Elt.name ] ] + | ModuleSubstitution -> + [ txt' "ModuleSubstitution "; em [ txt' elt.Db.Elt.name ] ] + | ModuleTypeSubstitution -> + [ txt' "ModuleTypeSubstitution "; em [ txt' elt.Db.Elt.name ] ] + | InstanceVariable -> + [ txt' "InstanceVariable "; em [ txt' elt.Db.Elt.name ] ] let search ~id input = let query = El.prop El.Prop.value input |> Jstr.to_string in diff --git a/bin/index/dune b/bin/index/dune index a507d75d07..5414b008cf 100644 --- a/bin/index/dune +++ b/bin/index/dune @@ -1,3 +1,9 @@ (executable (name index) - (libraries cmdliner index_lib storage_ancient storage_marshal storage_js)) + (libraries + odoc.search + cmdliner + index_lib + storage_ancient + storage_marshal + storage_js)) diff --git a/bin/index/index.ml b/bin/index/index.ml index 0d4564ed09..bcb0acba18 100644 --- a/bin/index/index.ml +++ b/bin/index/index.ml @@ -1,27 +1,29 @@ -let main odoc_directory db_filename db_format = +let main index db_filename db_format = let optimize, storage = match db_format with | `ancient -> true, (module Storage_ancient : Db.Storage.S) | `marshal -> false, (module Storage_marshal : Db.Storage.S) | `js -> false, (module Storage_js : Db.Storage.S) in - Index_lib.main ~odoc_directory ~db_filename ~optimize storage + let channel = open_in index in + let index = Marshal.from_channel channel in + Index_lib.main ~index ~db_filename ~optimize storage open Cmdliner let db_format = - let doc = "Databse format" in + let doc = "Database format" in let kind = Arg.enum [ "ancient", `ancient; "marshal", `marshal; "js", `js ] in Arg.( required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) let db_filename = - let doc = "Database filename" in + let doc = "Output filename" in Arg.(required & opt (some string) None & info [ "db" ] ~docv:"DB" ~doc) let odoc_path = - let doc = "Path to a directory containing odocl files" in - Arg.(required & opt (some dir) None & info [ "odoc" ] ~docv:"ODOC_FILES" ~doc) + let doc = "Path to a binary odoc index" in + Arg.(required & opt (some file) None & info [ "odoc" ] ~docv:"ODOC_FILE" ~doc) let index = Term.(const main $ odoc_path $ db_filename $ db_format) diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 8614327cca..9d47f9e3c1 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -7,24 +7,60 @@ let list_of_option = function let render_elt elt = let open Db.Elt in match elt.kind with - | Db.Elt.Val { str_type; _ } -> + | Val { str_type; _ } -> [ txt "val " ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ; txt " : " ; txt str_type ] - | Db.Elt.Type -> + | Doc -> + [ txt "comment "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | TypeDecl { html = type_decl } -> [ txt "type " ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ; txt " = " - ; txt "WIP" + ; Unsafe.data type_decl ] - | Db.Elt.Module -> + | Module -> [ txt "module "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] - | Db.Elt.ModuleType -> - [ txt "module type "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] - | Db.Elt.Exception -> + | Exception -> [ txt "exception "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | Class_type -> + [ txt "class type "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | Method -> + [ txt "method "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | Class -> + [ txt "class "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | TypeExtension -> + [ txt "type extension " + ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + ] + | ExtensionConstructor -> + [ txt "ext constructor " + ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + ] + | ModuleType -> + [ txt "module type "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | Constructor -> + [ txt "constructor "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | Field -> + [ txt "field "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | FunctorParameter -> + [ txt "functor param " + ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + ] + | ModuleSubstitution -> + [ txt "module subst " + ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + ] + | ModuleTypeSubstitution -> + [ txt "module type subst " + ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + ] + | InstanceVariable -> + [ txt "instance variable " + ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + ] let render_result r = let open Db.Types.Elt in diff --git a/lib/db/types.ml b/lib/db/types.ml index 518b5ff161..2eab0b4168 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -1,9 +1,21 @@ module Elt = struct type kind = - | Type + | Doc + | TypeDecl of { html : string } | Module - | ModuleType | Exception + | Class_type + | Method + | Class + | TypeExtension + | ExtensionConstructor + | ModuleType + | Constructor + | Field + | FunctorParameter + | ModuleSubstitution + | ModuleTypeSubstitution + | InstanceVariable | Val of { str_type : string (** A type can viewed as a tree. diff --git a/lib/index_lib/docstring.ml b/lib/index_lib/docstring.ml deleted file mode 100644 index 977955afa6..0000000000 --- a/lib/index_lib/docstring.ml +++ /dev/null @@ -1,72 +0,0 @@ -open Odoc_model - -let words_of_string s = String.split_on_char ' ' s -let words_of_identifier id = [ Comment.Identifier.name id ] - -let words_of_resolved = function - | `Identifier v -> words_of_identifier v - | r -> words_of_identifier (Comment.Reference.Resolved.identifier r) - -let words_of_reference : Comment.Reference.t -> _ = function - | `Root (r, _) -> [ r ] - | `Dot (_, n) -> [ n ] - | `Resolved r -> words_of_resolved r - | `InstanceVariable (_, name) -> [ Names.InstanceVariableName.to_string name ] - | `Module (_, name) -> [ Names.ModuleName.to_string name ] - | `ModuleType (_, name) -> [ Names.ModuleTypeName.to_string name ] - | `Method (_, name) -> [ Names.MethodName.to_string name ] - | `Field (_, name) -> [ Names.FieldName.to_string name ] - | `Label (_, name) -> [ Names.LabelName.to_string name ] - | `Type (_, name) -> [ Names.TypeName.to_string name ] - | `Exception (_, name) -> [ Names.ExceptionName.to_string name ] - | `Class (_, name) -> [ Names.ClassName.to_string name ] - | `ClassType (_, name) -> [ Names.ClassTypeName.to_string name ] - | `Value (_, name) -> [ Names.ValueName.to_string name ] - | `Constructor (_, name) -> [ Names.ConstructorName.to_string name ] - | `Extension (_, name) -> [ Names.ExtensionName.to_string name ] - -let rec words_of_non_link : Comment.non_link_inline_element -> _ = function - | `Math_span s -> words_of_string s - | `Space -> [] - | `Word w -> [ w ] - | `Code_span s -> words_of_string s - | `Raw_markup (_, _s) -> [] - | `Styled (_, lst) -> words_of_link_content lst - -and words_of_element : Comment.inline_element -> _ = function - | `Math_span s -> words_of_string s - | `Styled (_, lst) -> words_of_paragraph lst - | `Reference (r, _) -> words_of_reference r - | `Link (_, r) -> words_of_link_content r - | `Space -> [] - | `Word w -> [ w ] - | `Code_span s -> words_of_string s - | `Raw_markup (_, _s) -> [] - -and words_of_link_content (lst : Comment.link_content) = - List.concat_map (fun r -> words_of_non_link r.Odoc_model.Location_.value) lst - -and words_of_paragraph (lst : Comment.paragraph) = - List.concat_map - (fun elt -> words_of_element elt.Odoc_model.Location_.value) - lst - -let words_of_doc : Comment.block_element -> _ = function - | `Paragraph p -> words_of_paragraph p - | `Heading (_, _, p) -> words_of_link_content p - | _ -> [] - -let words_of_docs (lst : Odoc_model.Comment.docs) = - List.concat_map (fun elt -> words_of_doc elt.Odoc_model.Location_.value) lst - |> List.filter_map (fun word -> - let word = - word |> Db.list_of_string |> List.rev_map Char.lowercase_ascii - in - let word = - List.filter - (fun chr -> - (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9')) - word - in - if word = [] then None else Some word) - |> List.sort_uniq (List.compare Char.compare) diff --git a/lib/index_lib/docstring.mli b/lib/index_lib/docstring.mli deleted file mode 100644 index 08683c37bf..0000000000 --- a/lib/index_lib/docstring.mli +++ /dev/null @@ -1 +0,0 @@ -val words_of_docs : Odoc_model.Comment.docs -> char list list diff --git a/lib/index_lib/dune b/lib/index_lib/dune index c512fafd21..71de3f538f 100644 --- a/lib/index_lib/dune +++ b/lib/index_lib/dune @@ -5,6 +5,7 @@ fpath tyxml opam-core + odoc.search odoc.loader odoc.model odoc.xref2 diff --git a/lib/index_lib/files.ml b/lib/index_lib/files.ml deleted file mode 100644 index a420e17758..0000000000 --- a/lib/index_lib/files.ml +++ /dev/null @@ -1,57 +0,0 @@ -let packages root = Sys.readdir root -let versions root dir = Array.to_list @@ Sys.readdir @@ Filename.concat root dir - -let untar root = - Array.iter - (fun dir -> - match versions root dir with - | [] -> () - | v :: vs -> - let latest_version = - List.fold_left - (fun v0 v1 -> - if OpamVersionCompare.compare v0 v1 < 0 then v1 else v0) - v vs - in - Sys.chdir Filename.(concat (concat root dir) latest_version) ; - let ok = Sys.command "tar -xvf content.tar" in - assert (ok = 0) ; - ()) - (packages root) - -let contains s1 s2 = - let re = Str.regexp_string s2 in - try - ignore (Str.search_forward re s1 0) ; - true - with Not_found -> false - -let list root_directory = - let cwd = Sys.getcwd () in - Sys.chdir root_directory ; - let h = Unix.open_process_in "find . -name '*.odocl'" in - let rec go acc = - match Stdlib.input_line h with - | exception End_of_file -> - ignore (Unix.close_process_in h) ; - acc - | line -> go (line :: acc) - in - let files = go [] in - Sys.chdir cwd ; - List.filter (fun filename -> - not - (List.exists (contains filename) - [ "page-" - ; "__" - ; "Linalg" - ; "tezos" - ; "archetype" - ; "async" - ; "kernel" - ; "camlp4" - ; "DAGaml" - ; "Luv" - ; "ocapic" - ])) - @@ files diff --git a/lib/index_lib/files.mli b/lib/index_lib/files.mli deleted file mode 100644 index c29ec535a6..0000000000 --- a/lib/index_lib/files.mli +++ /dev/null @@ -1,5 +0,0 @@ -val packages : string -> string array -val versions : string -> string -> string list -val untar : string -> unit -val contains : string -> string -> bool -val list : string -> string list diff --git a/lib/index_lib/index_lib.ml b/lib/index_lib/index_lib.ml index 06f8c429c8..4edb299cfc 100644 --- a/lib/index_lib/index_lib.ml +++ b/lib/index_lib/index_lib.ml @@ -1,34 +1,15 @@ module Storage = Db.Storage -let of_filename f = - let module_name = - String.capitalize_ascii Filename.(chop_extension (basename f)) - in - module_name, f - -let filenames odoc_directory = List.map of_filename (Files.list odoc_directory) - -let main ~odoc_directory ~db_filename ~optimize storage = +let main ~index ~db_filename ~optimize storage = let module Storage = (val storage : Storage.S) in let module Load_doc = Load_doc.Make (Storage) in let module Db = Load_doc.Db in - let files = filenames odoc_directory in - let total = List.length files in let h = Storage.open_out db_filename in let flush () = if optimize then Db.optimize () ; Load_doc.clear () ; Db.export h in - List.iteri - (fun i file -> - if !Db.load_counter > 10_000_000 - then begin - Printf.printf - "---------------- SHARD %i / %i -----------------------\n%!" i total ; - flush () - end ; - Load_doc.run ~odoc_directory file) - files ; + Load_doc.run ~index ; flush () ; Storage.close_out h diff --git a/lib/index_lib/index_lib.mli b/lib/index_lib/index_lib.mli index 52aee6577d..6ca5713dcd 100644 --- a/lib/index_lib/index_lib.mli +++ b/lib/index_lib/index_lib.mli @@ -1,5 +1,5 @@ val main : - odoc_directory:string + index:Odoc_search.Index_db.index -> db_filename:string -> optimize:bool -> (module Db.Storage.S) diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 02bfa9fc08..e38f709660 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -3,7 +3,6 @@ module Db_common = Db module Make (Storage : Db.Storage.S) = struct module Types = Db.Types module Db = Db.Make (Storage) - open Odoc_model module ModuleName = Odoc_model.Names.ModuleName module Cache = Cache.Make (struct @@ -58,8 +57,8 @@ module Make (Storage : Db.Storage.S) = struct | [] -> [] | _ :: xs as lst -> lst :: tails xs - let fullname t = - Pretty.fmt_to_string (fun h -> Pretty.show_type_name_verbose h t) + let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) + let fullname t = Format.asprintf "%a" Pretty.show_type_name_verbose t let all_type_names t = let fullname = fullname t in @@ -130,20 +129,22 @@ module Make (Storage : Db.Storage.S) = struct | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args | _ -> [] - let save_doc elt doc = - let doc_words = Docstring.words_of_docs doc in - List.iter (fun word -> Db.store_name (Cache_list.memo word) elt) doc_words + let register_doc elt doc_txt = + let doc_words = String.split_on_char ' ' doc_txt in + List.iter + (fun word -> + let word = Db_common.list_of_string word in + Db.store_name (Cache_list.memo word) elt) + doc_words - let save_full_name path_list name elt = - let my_full_name = - List.rev_append (Db_common.list_of_string name) ('.' :: path_list) - in + let register_full_name name elt = + let my_full_name = Db_common.list_of_string name in let my_full_name = List.map Char.lowercase_ascii my_full_name in Db.store_name (Cache_list.memo my_full_name) elt - let generic_cost ~ignore_no_doc full_name path str_doc = + let generic_cost ~ignore_no_doc full_name str_doc = String.length full_name - + (5 * List.length path) + (* + (5 * List.length path) TODO : restore depth based ordering *) + (if ignore_no_doc then 0 else @@ -152,162 +153,120 @@ module Make (Storage : Db.Storage.S) = struct | _ -> 0) + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 - let save_val ~pkg ~path_list ~path name type_ (doc : Comment.docs) = - let str_type = - Format.kasprintf Cache.memo "%a%!" - (Pretty.show_type - ~path:(Pretty.fmt_to_string (fun h -> Pretty.pp_path h path)) - ~parens:false) - type_ - in - let full_name = - Format.asprintf "%a%s%!" Pretty.pp_path path - (Odoc_model.Names.ValueName.to_string name) - in + let kind_cost (kind : Odoc_search.Index_db.kind) = + let open Odoc_search in + let open Odoc_search.Index_db in + match kind with + | TypeDecl _ -> 0 + | Module -> 0 + | Value { value = _; type_ } -> + let str_type = type_ |> Render.html_of_type |> string_of_html in + String.length str_type + type_size type_ + | Doc _ -> 0 + | Exception _ -> 0 + | Class_type _ -> 0 + | Method _ -> 0 + | Class _ -> 0 + | TypeExtension _ -> 0 + | ExtensionConstructor _ -> 0 + | ModuleType -> 0 + | Constructor _ -> 0 + | Field _ -> 0 + | FunctorParameter -> 0 + | ModuleSubstitution _ -> 0 + | ModuleTypeSubstitution -> 0 + | InstanceVariable _ -> 0 - let str_doc = Option.map Cache.memo (Pretty.string_of_docs doc) in - let cost = - generic_cost ~ignore_no_doc:false full_name path str_doc - + String.length str_type + type_size type_ - in - let paths = paths ~prefix:[] ~sgn:Pos type_ in - let elt = - { Db_common.Elt.name = full_name - ; kind = Db_common.Elt.Val { type_paths = paths; str_type } - ; cost - ; doc = str_doc - ; pkg - } + let convert_kind (kind : Odoc_search.Index_db.kind) = + let open Odoc_search in + let open Odoc_search.Index_db in + match kind with + | TypeDecl typedecl -> + let html = typedecl |> Render.html_of_typedecl |> string_of_html in + Db_common.Elt.TypeDecl { html } + | Module -> Db_common.Elt.ModuleType + | Value { value = _; type_ } -> + let str_type = Render.html_of_type type_ in + let paths = paths ~prefix:[] ~sgn:Pos type_ in + let str_type = string_of_html str_type in + Val { str_type; type_paths = paths } + | Doc _ -> Doc + | Exception _ -> Exception + | Class_type _ -> Class_type + | Method _ -> Method + | Class _ -> Class + | TypeExtension _ -> TypeExtension + | ExtensionConstructor _ -> ExtensionConstructor + | ModuleType -> ModuleType + | Constructor _ -> Constructor + | Field _ -> Field + | FunctorParameter -> FunctorParameter + | ModuleSubstitution _ -> ModuleSubstitution + | ModuleTypeSubstitution -> ModuleTypeSubstitution + | InstanceVariable _ -> InstanceVariable + + let register_kind elt (kind : Odoc_search.Index_db.kind) = + let open Odoc_search.Index_db in + match kind with + | TypeDecl _ -> () + | Module -> () + | Value { value = _; type_ } -> + let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in + Db.store_all elt + (List.map + (fun xs -> + let xs = List.concat_map Db_common.list_of_string xs in + Cache_list.memo xs) + type_paths) + | Doc _ -> () + | Exception _ -> () + | Class_type _ -> () + | Method _ -> () + | Class _ -> () + | TypeExtension _ -> () + | ExtensionConstructor _ -> () + | ModuleType -> () + | Constructor _ -> () + | Field _ -> () + | FunctorParameter -> () + | ModuleSubstitution _ -> () + | ModuleTypeSubstitution -> () + | InstanceVariable _ -> () + + let entry + Odoc_search.Index_db. + { id : Odoc_model.Paths.Identifier.Any.t + ; doc : Odoc_model.Comment.docs + ; kind : kind + } = + let open Odoc_search in + let open Odoc_search.Index_db in + let full_name = + id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." in - save_doc elt doc ; - save_full_name path_list (Odoc_model.Names.ValueName.to_string name) elt ; - let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in - Db.store_all elt - (List.map - (fun xs -> - let xs = List.concat_map Db_common.list_of_string xs in - Cache_list.memo xs) - type_paths) + let doc = doc |> Render.html_of_doc |> string_of_html |> Option.some + and doc_txt = Render.text_of_doc doc in + let kind' = convert_kind kind in - let save_named_elt ~pkg ~path_list ~path ~kind name doc = - let full_name = Format.asprintf "%a%s%!" Pretty.pp_path path name in - let str_doc = Option.map Cache.memo (Pretty.string_of_docs doc) in let ignore_no_doc = match kind with - | Db_common.Elt.(Module | ModuleType) -> true + | Module | ModuleType -> true | _ -> false in - let cost = generic_cost ~ignore_no_doc full_name path str_doc in + let cost = generic_cost ~ignore_no_doc full_name doc + kind_cost kind in let elt = - { Db_common.Elt.name = full_name; kind; cost; doc = str_doc; pkg } - in - save_doc elt doc ; - save_full_name path_list name elt - - let rec item ~pkg ~path_list ~path = - let open Odoc_model.Lang in - function - | Signature.Value { id = { iv = `Value (_, name); _ }; _ } - when Odoc_model.Names.ValueName.is_internal name -> - () - | Signature.Value { id = { iv = `Value (_, name); _ }; type_; doc; _ } -> - save_val ~pkg ~path_list ~path name type_ doc - | Module - ( _ - , ({ id = - { iv = `Module (_, name) | `Root (_, name) | `Parameter (_, name) - ; _ - } - ; doc - ; hidden = - _ (* TODO : should hidden modules show up in search results ?*) - ; _ - } as mdl) ) -> - let name = Odoc_model.Names.ModuleName.to_string name in - save_named_elt ~pkg ~path_list ~path ~kind:Module name doc ; - let name = Paths.Identifier.name mdl.id in - if name = "Stdlib" then () else module_items ~pkg ~path_list ~path mdl - | Type (_, { id = { iv = `Type (_, name) | `CoreType name; _ }; doc; _ }) -> - let name = Odoc_model.Names.TypeName.to_string name in - save_named_elt ~pkg ~path_list ~path ~kind:Type name doc - | Include icl -> items ~pkg ~path_list ~path icl.expansion.content.items - | TypeSubstitution _ -> () (* type t = Foo.t = actual_definition *) - | TypExt _ -> () (* type t = .. *) - | Exception - { id = { iv = `Exception (_, name) | `CoreException name; _ }; doc; _ } - -> - let name = Odoc_model.Names.ExceptionName.to_string name in - save_named_elt ~pkg ~path_list ~path ~kind:Exception name doc - | Class _ -> () - | ClassType _ -> () - | Comment _ -> () - | Open _ -> () - | ModuleType { id = { iv = `ModuleType (_, name); _ }; doc; _ } -> - let name = Odoc_model.Names.ModuleTypeName.to_string name in - save_named_elt ~pkg ~path_list ~path ~kind:ModuleType name doc - | ModuleSubstitution _ -> () - | ModuleTypeSubstitution _ -> () - - and items ~pkg ~path_list ~path item_list = - List.iter (item ~pkg ~path_list ~path) item_list - - and module_items ~pkg ~path_list ~path mdl = - let open Odoc_model.Lang.Module in - let name = Paths.Identifier.name mdl.id in - let path = name :: path in - let path_list = - List.rev_append (Db_common.list_of_string name) ('.' :: path_list) + { Db_common.Elt.name = full_name + ; kind = kind' + ; cost + ; doc + ; pkg = "fake", "package" + } in - match mdl.type_ with - | ModuleType e -> module_type_expr ~pkg ~path_list ~path e - | Alias (_, Some mdl) -> module_items_ty ~pkg ~path_list ~path mdl - | Alias (_, None) -> () - - and module_type_expr ~pkg ~path_list ~path = function - | Signature sg -> items ~pkg ~path_list ~path sg.items - | Functor (_, sg) -> module_type_expr ~pkg ~path_list ~path sg - | With { w_expansion = Some sg; _ } - | TypeOf { t_expansion = Some sg; _ } - | Path { p_expansion = Some sg; _ } -> - simple_expansion ~pkg ~path_list ~path sg - | With _ -> () - | TypeOf _ -> () - | Path _ -> () - | _ -> . - - and simple_expansion ~pkg ~path_list ~path = function - | Signature sg -> items ~pkg ~path_list ~path sg.items - | Functor (_, sg) -> simple_expansion ~pkg ~path_list ~path sg - - and module_items_ty ~pkg ~path_list ~path = function - | Functor (_, mdl) -> module_items_ty ~pkg ~path_list ~path mdl - | Signature sg -> items ~pkg ~path_list ~path sg.items + register_doc elt doc_txt ; + register_full_name full_name elt ; + register_kind elt kind module Resolver = Odoc_odoc.Resolver - let run ~odoc_directory (root_name, filename) = - let ((package, version) as pkg) = - match String.split_on_char '/' filename with - | "." :: package :: version :: _ -> package, version - | _ -> - invalid_arg - (Printf.sprintf "not a valid package/version? %S" filename) - in - Format.printf "%s %s => %s@." package version root_name ; - let filename = Filename.concat odoc_directory filename in - let fpath = Result.get_ok @@ Fpath.of_string filename in - let t = - match Odoc_odoc.Odoc_file.load fpath with - | Ok { Odoc_odoc.Odoc_file.content = Unit_content t; _ } -> t - | Ok { Odoc_odoc.Odoc_file.content = Page_content _; _ } -> - failwith "page content" - | Error (`Msg m) -> failwith ("ERROR:" ^ m) - in - let open Odoc_model.Lang.Compilation_unit in - match t.content with - | Pack _ -> () - | Module t -> - let path = [ root_name ] in - let path_list = List.rev (Db_common.list_of_string root_name) in - items ~pkg ~path_list ~path t.Odoc_model.Lang.Signature.items + let run ~index = List.iter entry index end diff --git a/lib/index_lib/load_doc.mli b/lib/index_lib/load_doc.mli index dd66c0be8c..3eb3bfc507 100644 --- a/lib/index_lib/load_doc.mli +++ b/lib/index_lib/load_doc.mli @@ -2,5 +2,5 @@ module Make (Storage : Db.Storage.S) : sig module Db : Db.S with type writer = Storage.writer val clear : unit -> unit - val run : odoc_directory:string -> string * string -> unit + val run : index:Odoc_search.Index_db.t list -> unit end diff --git a/lib/index_lib/pretty.ml b/lib/index_lib/pretty.ml index 443a488770..a983063df1 100644 --- a/lib/index_lib/pretty.ml +++ b/lib/index_lib/pretty.ml @@ -1,85 +1,9 @@ open Odoc_model -open Odoc_model.Root module ModuleName = Odoc_model.Names.ModuleName module H = Tyxml.Html -let fmt_to_string f = - let b = Buffer.create 16 in - let to_b = Format.formatter_of_buffer b in - f to_b ; - Format.fprintf to_b "%!" ; - Buffer.contents b -let string_of_identifier = Comment.Identifier.name -let string_of_resolved = function - | `Identifier v -> string_of_identifier v - | r -> string_of_identifier (Comment.Reference.Resolved.identifier r) - -let string_of_reference : Comment.Reference.t -> _ = function - | `Root (r, _) -> r - | `Dot (_, n) -> n - | `Resolved r -> string_of_resolved r - | `InstanceVariable (_, name) -> Names.InstanceVariableName.to_string name - | `Module (_, name) -> Names.ModuleName.to_string name - | `ModuleType (_, name) -> Names.ModuleTypeName.to_string name - | `Method (_, name) -> Names.MethodName.to_string name - | `Field (_, name) -> Names.FieldName.to_string name - | `Label (_, name) -> Names.LabelName.to_string name - | `Type (_, name) -> Names.TypeName.to_string name - | `Exception (_, name) -> Names.ExceptionName.to_string name - | `Class (_, name) -> Names.ClassName.to_string name - | `ClassType (_, name) -> Names.ClassTypeName.to_string name - | `Value (_, name) -> Names.ValueName.to_string name - | `Constructor (_, name) -> Names.ConstructorName.to_string name - | `Extension (_, name) -> Names.ExtensionName.to_string name - -let rec string_of_non_link : Comment.non_link_inline_element -> _ = function - | `Math_span s -> H.txt s - | `Space -> H.txt " " - | `Word w -> H.txt w - | `Code_span s -> H.code [ H.txt s ] - | `Raw_markup (_, s) -> H.txt s - | `Styled (_, lst) -> string_of_link_content lst - -and string_of_element : Comment.inline_element -> _ = function - | `Math_span s -> H.txt s - | `Styled (_, lst) -> string_of_paragraph lst - | `Reference (r, _) -> H.code [ H.txt (string_of_reference r) ] - | `Link (_, r) -> string_of_link_content r - | `Space -> H.txt " " - | `Word w -> H.txt w - | `Code_span s -> H.code [ H.txt s ] - | `Raw_markup (_, s) -> H.txt s - -and string_of_link_content (lst : Comment.link_content) = - H.span - (List.map (fun r -> string_of_non_link r.Odoc_model.Location_.value) lst) - -and string_of_paragraph (lst : Comment.paragraph) = - H.span - (List.map (fun elt -> string_of_element elt.Odoc_model.Location_.value) lst) - -let string_of_doc : Comment.block_element -> _ = function - | `Paragraph p -> Some (H.p [ string_of_paragraph p ]) - | `Heading (_, _, p) -> Some (H.p [ string_of_link_content p ]) - | _ -> None - -let html_of_docs (lst : Comment.docs) = - List.find_map (fun elt -> string_of_doc elt.Odoc_model.Location_.value) lst - -let string_of_docs (doc : Comment.docs) = - let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) in - Option.map string_of_html (html_of_docs doc) - -let make_root ~module_name ~digest : (_, _) result = - let file = Odoc_file.create_unit ~force_hidden:false module_name in - let root = `Root (None, ModuleName.make_std module_name) in - let odocoid (* odocoids are powerful drugs *) = - Paths.Identifier.{ iv = root; ihash = 0; ikey = "" } - in - let r : t = { id = odocoid; file; digest } in - Ok r let show_module_name h md = Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) @@ -140,12 +64,6 @@ and show_signature h sig_ = | `ModuleType (_, p) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) -let show_ident_verbose h = function - | `Type (md, n) -> - Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) - | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) - | _ -> Format.fprintf h "show_ident?" - let show_type_name_verbose h : Paths.Path.Type.t -> _ = function | `Resolved t -> let open Paths.Path in @@ -154,112 +72,3 @@ let show_type_name_verbose h : Paths.Path.Type.t -> _ = function | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x -let show_type_name_short h = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_ident_short (Resolved.identifier t) - | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b - | `Dot (_mdl, x) -> Format.fprintf h "%s" x - -let strip ~prefix str = - if String.starts_with ~prefix str - then - String.sub str (String.length prefix) - (String.length str - String.length prefix) - else str - -let show_type_name ~path h (t : Paths.Path.Type.t) = - let blah = fmt_to_string (fun h -> show_type_name_verbose h t) in - let blah = strip ~prefix:path blah in - let blah = strip ~prefix:"Stdlib." blah in - Format.fprintf h "%s" blah - -let show_moduletype_ident h = function - | `ModuleType (_, _) -> Format.fprintf h "ident" - | _ -> Format.fprintf h "moduletype" - -let show_moduletype_name h = function - | `Resolved t -> - Format.fprintf h "%a" show_ident_long - (Paths.Reference.Resolved.identifier t) - | `Identifier (_, b) -> - Format.fprintf h "This is a bug in sherlodoc : IDENT%b" b - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x - -let show_label h = function - | None -> () - | Some (Odoc_model.Lang.TypeExpr.Label lbl) -> Format.fprintf h "%s:" lbl - | Some (Optional lbl) -> Format.fprintf h "?%s:" lbl - -let show_type_id h = function - | `Type (_, name) -> Printf.fprintf h "%s" (Names.TypeName.to_string name) - | `CoreType name -> - Printf.fprintf h "(core)%s" (Names.TypeName.to_string name) - -let show_type_repr h = function - | None -> Printf.fprintf h "no repr" - | Some _ -> Printf.fprintf h "has repr" - -let show_functor_param h = function - | Lang.FunctorParameter.Unit -> Printf.fprintf h "UNIT" - | Named { id = { iv = `Parameter (_, md); _ }; expr = _ } -> - Printf.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) - -let type_no_parens = function - | Odoc_model.Lang.TypeExpr.Var _ | Any | Constr _ | Tuple _ -> true - | _ -> false - -let rec show_type ~path ~parens h = function - | Odoc_model.Lang.TypeExpr.Var x -> Format.fprintf h "'%s" x - | Any -> Format.fprintf h "_" - | Arrow (lbl, a, b) -> - if parens then Format.fprintf h "(" ; - Format.fprintf h "%a%a -> %a" show_label lbl - (show_type ~path ~parens:true) - a - (show_type ~path ~parens:false) - b ; - if parens then Format.fprintf h ")" - | Constr (name, []) -> Format.fprintf h "%a" (show_type_name ~path) name - | Constr (name, ([ x ] as args)) when type_no_parens x -> - Format.fprintf h "%a %a" (show_type_list ~path) args - (show_type_name ~path) name - | Constr (name, args) -> - Format.fprintf h "(%a) %a" (show_type_list ~path) args - (show_type_name ~path) name - | Tuple args -> - Format.fprintf h "(" ; - show_tuple_list ~path h args ; - Format.fprintf h ")" - | Poly (polys, t) -> - if parens then Format.fprintf h "(" ; - Format.fprintf h "%a. %a" show_polys polys - (show_type ~path ~parens:false) - t ; - if parens then Format.fprintf h ")" - | _ -> Format.fprintf h "!!todo!!" - -and show_polys h = function - | [] -> failwith "show_polys: empty list" - | [ x ] -> Format.fprintf h "'%s" x - | x :: xs -> Format.fprintf h "'%s %a" x show_polys xs - -and show_type_list ~path h = function - | [] -> failwith "empty list" - | [ x ] -> show_type ~path ~parens:false h x - | x :: xs -> - Format.fprintf h "%a, %a" - (show_type ~path ~parens:true) - x (show_type_list ~path) xs - -and show_tuple_list ~path h = function - | [] -> failwith "empty list" - | [ x ] -> show_type ~path ~parens:true h x - | x :: xs -> - Format.fprintf h "%a * %a" - (show_type ~path ~parens:true) - x (show_tuple_list ~path) xs - -let rec pp_path h = function - | [] -> Format.fprintf h "" - | x :: xs -> Format.fprintf h "%a%s." pp_path xs x diff --git a/lib/query/parser.mly b/lib/query/parser.mly index d576b8576f..dbc0ba38c7 100644 --- a/lib/query/parser.mly +++ b/lib/query/parser.mly @@ -11,6 +11,7 @@ %start main %type main +%left EOF %% separated_twolong_list(sep, elt): @@ -50,4 +51,6 @@ typ0: | PARENS_OPEN t=typ EOF { t } ; +(* ( int EOF EOF *) + typ_list: ts=separated_twolong_list(COMMA, typ) { ts } ; diff --git a/lib/query/sort.ml b/lib/query/sort.ml index 72a5e79e23..93087d0219 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -151,7 +151,11 @@ let list query_name query_type results = let type_cost = match a.kind with | Val { type_paths; _ } -> score_type query_type type_paths - | Type | Module | ModuleType | Exception -> 0 + | Doc | TypeDecl _ | Module | Exception | Class_type | Method | Class + | TypeExtension | ExtensionConstructor | ModuleType | Constructor + | Field | FunctorParameter | ModuleSubstitution + | ModuleTypeSubstitution | InstanceVariable -> + 0 in let cost = a.Elt.cost + (2 * name_cost) + (800 * type_cost) in { a with cost }) diff --git a/sherlodoc.opam b/sherlodoc.opam index a61540f185..1b9de2484b 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -12,7 +12,7 @@ depends: [ "ancient" "dream" "fpath" - "odoc" {= "2.2.0"} + "odoc" {= "2.1.0"} "opam-core" "tyxml" ] From 857994e10278a3be7e370e510d1c2e21df7019b2 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 3 May 2023 16:56:16 +0200 Subject: [PATCH 054/285] odoc with search integration --- bin/JSherlodoc/main.ml | 116 +++++++++++++------------------------- bin/index/dune | 1 + dune-project | 34 +++++++---- test/cram/dune | 2 + test/cram/odoc.t/main.ml | 38 +++++++++++++ test/cram/odoc.t/page.mld | 10 ++++ test/cram/odoc.t/run.t | 16 ++++++ 7 files changed, 127 insertions(+), 90 deletions(-) create mode 100644 test/cram/dune create mode 100644 test/cram/odoc.t/main.ml create mode 100644 test/cram/odoc.t/page.mld create mode 100644 test/cram/odoc.t/run.t diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 68ba2c04f9..c33cec0afb 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -1,89 +1,49 @@ let db = Storage_js.load Jv.(to_string @@ get global "sherlodb") -open Brr - -let inner_html = El.Prop.jstr (Jstr.v "innerHTML") - -let raw_html str = - let elt = El.div ~at:At.[ class' (Jstr.of_string "docstring") ] [] in - El.set_prop inner_html (Jstr.v str) elt ; - elt - -let latest = ref 0 -let count = ref 1 - -let render_elt elt = +let string_of_kind (kind : Db.Elt.kind) = let open Db.Elt in - let open El in - match elt.kind with - | Val { str_type; _ } -> - [ txt' "val "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' str_type ] - | Doc -> [ txt' "Doc "; em [ txt' elt.Db.Elt.name ] ] - | TypeDecl { html = type_decl } -> - [ txt' "type "; em [ txt' elt.Db.Elt.name ]; txt' " : "; txt' type_decl ] - | Module -> [ txt' "Module "; em [ txt' elt.Db.Elt.name ] ] - | Exception -> [ txt' "Exception "; em [ txt' elt.Db.Elt.name ] ] - | Class_type -> [ txt' "Class_type "; em [ txt' elt.Db.Elt.name ] ] - | Method -> [ txt' "Method "; em [ txt' elt.Db.Elt.name ] ] - | Class -> [ txt' "Class "; em [ txt' elt.Db.Elt.name ] ] - | TypeExtension -> [ txt' "TypeExtension "; em [ txt' elt.Db.Elt.name ] ] - | ExtensionConstructor -> - [ txt' "ExtensionConstructor "; em [ txt' elt.Db.Elt.name ] ] - | ModuleType -> [ txt' "ModuleType "; em [ txt' elt.Db.Elt.name ] ] - | Constructor -> [ txt' "Constructor "; em [ txt' elt.Db.Elt.name ] ] - | Field -> [ txt' "Field "; em [ txt' elt.Db.Elt.name ] ] - | FunctorParameter -> - [ txt' "FunctorParameter "; em [ txt' elt.Db.Elt.name ] ] - | ModuleSubstitution -> - [ txt' "ModuleSubstitution "; em [ txt' elt.Db.Elt.name ] ] - | ModuleTypeSubstitution -> - [ txt' "ModuleTypeSubstitution "; em [ txt' elt.Db.Elt.name ] ] - | InstanceVariable -> - [ txt' "InstanceVariable "; em [ txt' elt.Db.Elt.name ] ] - -let search ~id input = - let query = El.prop El.Prop.value input |> Jstr.to_string in + match kind with + | Doc -> "doc" + | TypeDecl _ -> "type" + | Module -> "module" + | Exception -> "exception" + | Class_type -> "class type" + | Method -> "method" + | Class -> "class" + | TypeExtension -> "type ext" + | ExtensionConstructor -> "extension constructor" + | ModuleType -> "module type" + | Constructor -> "constructor" + | Field -> "field" + | FunctorParameter -> "functor parameter" + | ModuleSubstitution -> "module subst" + | ModuleTypeSubstitution -> "module type subst" + | InstanceVariable -> "instance variable" + | Val _ -> "val" + +let search query = + let query = query |> Jv.to_jstr |> Jstr.to_string in let _pretty_query, results = Query.(api ~shards:db { query; packages = []; limit = 50 }) in - let results = List.of_seq @@ Seq.take 10 @@ List.to_seq results in - let results = - List.map - (fun elt -> - El.( - div - ~at:At.[ class' (Jstr.of_string "result") ] - ([ code (render_elt elt) ] - @ - match elt.Db.Elt.doc with - | None -> [] - | Some doc -> [ raw_html doc ]))) - results - in - let results_div = - Document.find_el_by_id G.document (Jstr.of_string "results") |> Option.get - in - if !latest < id - then begin - latest := id ; - El.set_children results_div results - end -let search input = - let id = !count in - count := id + 1 ; - search ~id input + Jv.of_list + (fun Db.Elt.{ cost = _; name; kind; doc; pkg = _ } -> + let name = Jstr.of_string name in + let kind = kind |> string_of_kind |> Jv.of_string in + let doc = doc |> Option.value ~default:"" |> Jv.of_string in + Jv.( + obj + [| "name", of_jstr name + ; "prefixname", of_string "" + ; "kind", kind + ; "comment", doc + |])) + results let main () = - let search_input = - Document.find_el_by_id G.document (Jstr.of_string "search") |> Option.get - in - let _ = - Ev.( - listen input - (fun _ -> search search_input) - (search_input |> El.document |> Document.as_target)) - in - search search_input + let module J' = Jstr in + let o = Jv.callback ~arity:1 search in + Jv.(set global "odoc_search" o) let _ = main () diff --git a/bin/index/dune b/bin/index/dune index 5414b008cf..6149594e92 100644 --- a/bin/index/dune +++ b/bin/index/dune @@ -1,4 +1,5 @@ (executable +(public_name sherlodoc_index) (name index) (libraries odoc.search diff --git a/dune-project b/dune-project index 34d08e6e8c..97b5461d42 100644 --- a/dune-project +++ b/dune-project @@ -1,21 +1,31 @@ (lang dune 2.9) +(cram enable) + (using menhir 2.1) (generate_opam_files true) -(source (github art-w/sherlodoc)) + +(source + (github art-w/sherlodoc)) + (authors "Arthur Wendling") + (maintainers "art.wendling@gmail.com") + (license MIT) + (package - (name sherlodoc) - (synopsis "Fuzzy search in OCaml documentation") - (depends - (ocaml (>= 4.14.0)) - dune - ancient - dream - fpath - (odoc (= 2.1.0)) - opam-core - tyxml)) + (name sherlodoc) + (synopsis "Fuzzy search in OCaml documentation") + (depends + (ocaml + (>= 4.14.0)) + dune + ancient + dream + fpath + (odoc + (= 2.1.0)) + opam-core + tyxml)) diff --git a/test/cram/dune b/test/cram/dune new file mode 100644 index 0000000000..bdad93487e --- /dev/null +++ b/test/cram/dune @@ -0,0 +1,2 @@ +(cram + (deps %{bin:odoc} %{bin:sherlodoc_index} ../../bin/JSherlodoc/main.bc.js)) diff --git a/test/cram/odoc.t/main.ml b/test/cram/odoc.t/main.ml new file mode 100644 index 0000000000..c740666304 --- /dev/null +++ b/test/cram/odoc.t/main.ml @@ -0,0 +1,38 @@ +type t = int +(** A comment *) + +(** {1 this is a title} + + and this is a paragraph + + *) + +module M = struct + type t + (** dsdsd *) +end + +(** a reference {!t}, and some {e formatted} {b content} with [code] and + +{[ + code blocks +]} + + *) +let v = 9 + +(** lorem 1 + *) +let lorem = 1 + +(** lorem 2 + *) +let lorem2 = 1 + +(** lorem 3 + *) +let lorem3 = 1 + +(** lorem 4 + *) +let lorem4 = 1 diff --git a/test/cram/odoc.t/page.mld b/test/cram/odoc.t/page.mld new file mode 100644 index 0000000000..37fe4527d8 --- /dev/null +++ b/test/cram/odoc.t/page.mld @@ -0,0 +1,10 @@ +{0 A title} + +A paragraph + +{v some verbatim v} + +{[and code]} + +- a list {e of} things +- bliblib diff --git a/test/cram/odoc.t/run.t b/test/cram/odoc.t/run.t new file mode 100644 index 0000000000..5ded63ddae --- /dev/null +++ b/test/cram/odoc.t/run.t @@ -0,0 +1,16 @@ + $ ocamlc -c main.ml -bin-annot -I . + $ odoc compile -I . main.cmt + $ odoc compile -I . page.mld + $ odoc link -I . main.odoc + $ odoc link -I . page-page.odoc + $ odoc compile-index --binary -I . -o index.odoc_bin + $ du -sh index.odoc_bin + 4.0K index.odoc_bin + $ sherlodoc_index --format=js --odoc=index.odoc_bin --db=db.js + $ du -sh db.js + 12K db.js + $ odoc html-generate --with-search --output-dir html main.odocl + $ odoc support-files -o html + $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js + $ cp -r html /tmp + $ firefox /tmp/html/Main/index.html From 61c298edfdceba0468a04c5cd6f755edcb642e04 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 4 May 2023 11:48:15 +0200 Subject: [PATCH 055/285] package is now optionnal --- bin/www/ui.ml | 96 ++++++++++++++++++--------------------- lib/common/dune | 2 + lib/common/option.ml | 8 ++++ lib/db/dune | 2 +- lib/db/types.ml | 24 +++++++--- lib/index_lib/load_doc.ml | 7 +-- lib/query/query.ml | 6 ++- 7 files changed, 77 insertions(+), 68 deletions(-) create mode 100644 lib/common/dune create mode 100644 lib/common/option.ml diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 9d47f9e3c1..733a062688 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -4,77 +4,67 @@ let list_of_option = function | None -> [] | Some x -> [ x ] +let render_link elt = + let open Db.Elt in + match link elt with + | Some link -> [ a_href link ] + | None -> [] + let render_elt elt = let open Db.Elt in + let link = render_link elt in match elt.kind with | Val { str_type; _ } -> - [ txt "val " - ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] - ; txt " : " - ; txt str_type - ] - | Doc -> - [ txt "comment "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + [ txt "val "; a ~a:link [ em [ txt elt.name ] ]; txt " : "; txt str_type ] + | Doc -> [ txt "comment "; a ~a:link [ em [ txt elt.name ] ] ] | TypeDecl { html = type_decl } -> [ txt "type " - ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + ; a ~a:link [ em [ txt elt.name ] ] ; txt " = " ; Unsafe.data type_decl ] - | Module -> - [ txt "module "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] - | Exception -> - [ txt "exception "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] - | Class_type -> - [ txt "class type "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] - | Method -> - [ txt "method "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] - | Class -> - [ txt "class "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + | Module -> [ txt "module "; a ~a:link [ em [ txt elt.name ] ] ] + | Exception -> [ txt "exception "; a ~a:link [ em [ txt elt.name ] ] ] + | Class_type -> [ txt "class type "; a ~a:link [ em [ txt elt.name ] ] ] + | Method -> [ txt "method "; a ~a:link [ em [ txt elt.name ] ] ] + | Class -> [ txt "class "; a ~a:link [ em [ txt elt.name ] ] ] | TypeExtension -> - [ txt "type extension " - ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] - ] + [ txt "type extension "; a ~a:link [ em [ txt elt.name ] ] ] | ExtensionConstructor -> - [ txt "ext constructor " - ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] - ] - | ModuleType -> - [ txt "module type "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] - | Constructor -> - [ txt "constructor "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] - | Field -> - [ txt "field "; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] ] + [ txt "ext constructor "; a ~a:link [ em [ txt elt.name ] ] ] + | ModuleType -> [ txt "module type "; a ~a:link [ em [ txt elt.name ] ] ] + | Constructor -> [ txt "constructor "; a ~a:link [ em [ txt elt.name ] ] ] + | Field -> [ txt "field "; a ~a:link [ em [ txt elt.name ] ] ] | FunctorParameter -> - [ txt "functor param " - ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] - ] + [ txt "functor param "; a ~a:link [ em [ txt elt.name ] ] ] | ModuleSubstitution -> - [ txt "module subst " - ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] - ] + [ txt "module subst "; a ~a:link [ em [ txt elt.name ] ] ] | ModuleTypeSubstitution -> - [ txt "module type subst " - ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] - ] + [ txt "module type subst "; a ~a:link [ em [ txt elt.name ] ] ] | InstanceVariable -> - [ txt "instance variable " - ; a ~a:[ a_href (link elt) ] [ em [ txt elt.name ] ] + [ txt "instance variable "; a ~a:link [ em [ txt elt.name ] ] ] + +let render_pkg elt = + let open Db.Elt in + match elt.pkg with + | Some { name; version } -> + let link = elt |> pkg_link |> Option.get in + [ div + ~a:[ a_class [ "pkg" ] ] + [ a + ~a:[ a_href link ] + [ txt name + ; txt " " + ; span ~a:[ a_class [ "version" ] ] [ txt version ] + ] + ] ] + | None -> [] -let render_result r = +let render_result elt = let open Db.Types.Elt in - div - ~a:[ a_class [ "pkg" ] ] - [ a - ~a:[ a_href (pkg_link r) ] - [ txt (fst r.pkg) - ; txt " " - ; span ~a:[ a_class [ "version" ] ] [ txt (snd r.pkg) ] - ] - ] - :: pre (render_elt r) - :: list_of_option (Option.map Unsafe.data r.doc) + render_pkg elt + @ (pre (render_elt elt) :: list_of_option (Option.map Unsafe.data elt.doc)) let render ~pretty results = match results with diff --git a/lib/common/dune b/lib/common/dune new file mode 100644 index 0000000000..35b990621c --- /dev/null +++ b/lib/common/dune @@ -0,0 +1,2 @@ +(library + (name common)) diff --git a/lib/common/option.ml b/lib/common/option.ml new file mode 100644 index 0000000000..bbe57da284 --- /dev/null +++ b/lib/common/option.ml @@ -0,0 +1,8 @@ +include Stdlib.Option + +module O = struct + + let (let*) = bind + let (let+) v f = map f v + +end \ No newline at end of file diff --git a/lib/db/dune b/lib/db/dune index f77b6a27ea..bd45cbf0be 100644 --- a/lib/db/dune +++ b/lib/db/dune @@ -1,3 +1,3 @@ (library (name db) - (libraries unix tyxml)) + (libraries unix tyxml common)) diff --git a/lib/db/types.ml b/lib/db/types.ml index 2eab0b4168..2b120dfb61 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -1,3 +1,5 @@ +open Common + module Elt = struct type kind = | Doc @@ -37,22 +39,28 @@ module Elt = struct ; type_paths : string list list } + type package = + { name : string + ; version : string + } + type t = { cost : int ; name : string ; kind : kind ; doc : string option - ; pkg : string * string + ; pkg : package option } - let compare_pkg (a_name, _) (b_name, _) = String.compare a_name b_name + let compare_pkg { name; version = _ } (b : package) = + String.compare name b.name let compare a b = match Int.compare a.cost b.cost with | 0 -> begin match String.compare a.name b.name with | 0 -> begin - match compare_pkg a.pkg b.pkg with + match Option.compare compare_pkg a.pkg b.pkg with | 0 -> Stdlib.compare a.kind b.kind | c -> c end @@ -62,16 +70,20 @@ module Elt = struct let compare a b = if a == b then 0 else compare a b - let pkg_link { pkg = pkg, v; _ } = - Printf.sprintf "https://ocaml.org/p/%s/%s" pkg v + let pkg_link { pkg; _ } = + let open Option.O in + let+ { name; version } = pkg in + Printf.sprintf "https://ocaml.org/p/%s/%s" name version let link t = + let open Option.O in let name, path = match List.rev (String.split_on_char '.' t.name) with | name :: path -> name, String.concat "/" (List.rev path) | _ -> "", "" in - pkg_link t ^ "/doc/" ^ path ^ "/index.html#val-" ^ name + let+ pkg_link = pkg_link t in + pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name end module String_list_map = Map.Make (struct diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index e38f709660..e4190019e3 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -255,12 +255,7 @@ module Make (Storage : Db.Storage.S) = struct in let cost = generic_cost ~ignore_no_doc full_name doc + kind_cost kind in let elt = - { Db_common.Elt.name = full_name - ; kind = kind' - ; cost - ; doc - ; pkg = "fake", "package" - } + { Db_common.Elt.name = full_name; kind = kind'; cost; doc; pkg = None } in register_doc elt doc_txt ; register_full_name full_name elt ; diff --git a/lib/query/query.ml b/lib/query/query.ml index 94089cca99..36c93cbfa2 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -83,8 +83,10 @@ let search ~shards query_name query_typ = in results -let match_packages ~packages { Db.Elt.pkg = package, _version; _ } = - List.exists (String.equal package) packages +let match_packages ~packages { Db.Elt.pkg; _ } = + match pkg with + | Some { name; version = _ } -> List.exists (String.equal name) packages + | None -> false let match_packages ~packages results = match packages with From 567724c22309e56a928d83ad5aa80f2ba8de8231 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 4 May 2023 13:22:45 +0200 Subject: [PATCH 056/285] format --- bin/JSherlodoc/dune | 2 +- bin/JSherlodoc/main.ml | 6 +++++- bin/index/dune | 2 +- lib/common/option.ml | 10 ++++------ lib/db/types.ml | 13 +++++++++---- lib/index_lib/load_doc.ml | 18 ++++++++++-------- lib/index_lib/pretty.ml | 4 ---- 7 files changed, 30 insertions(+), 25 deletions(-) diff --git a/bin/JSherlodoc/dune b/bin/JSherlodoc/dune index 7a2c3c89c8..6257027f04 100644 --- a/bin/JSherlodoc/dune +++ b/bin/JSherlodoc/dune @@ -1,4 +1,4 @@ (executable (name main) (modes js) - (libraries tyxml query storage_js brr)) + (libraries common tyxml query storage_js brr)) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index c33cec0afb..3d26c1ba89 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -31,7 +31,11 @@ let search query = (fun Db.Elt.{ cost = _; name; kind; doc; pkg = _ } -> let name = Jstr.of_string name in let kind = kind |> string_of_kind |> Jv.of_string in - let doc = doc |> Option.value ~default:"" |> Jv.of_string in + let doc = + doc + |> Option.map (fun doc -> Db.Elt.(doc.txt)) + |> Option.value ~default:"" |> Jv.of_string + in Jv.( obj [| "name", of_jstr name diff --git a/bin/index/dune b/bin/index/dune index 6149594e92..eab034c3a7 100644 --- a/bin/index/dune +++ b/bin/index/dune @@ -1,5 +1,5 @@ (executable -(public_name sherlodoc_index) + (public_name sherlodoc_index) (name index) (libraries odoc.search diff --git a/lib/common/option.ml b/lib/common/option.ml index bbe57da284..be6ca1d4d5 100644 --- a/lib/common/option.ml +++ b/lib/common/option.ml @@ -1,8 +1,6 @@ include Stdlib.Option -module O = struct - - let (let*) = bind - let (let+) v f = map f v - -end \ No newline at end of file +module O = struct + let ( let* ) = bind + let ( let+ ) v f = map f v +end diff --git a/lib/db/types.ml b/lib/db/types.ml index 2b120dfb61..d03223c3e1 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -1,6 +1,11 @@ open Common module Elt = struct + type displayable = + { html : string + ; txt : string + } + type kind = | Doc | TypeDecl of { html : string } @@ -19,7 +24,8 @@ module Elt = struct | ModuleTypeSubstitution | InstanceVariable | Val of - { str_type : string + { type_ : displayable + ; type_paths : string list list (** A type can viewed as a tree. [a -> b -> c * d] is the following tree : {[ -> @@ -30,13 +36,12 @@ module Elt = struct |- c |- d ]} - [type_paths] is the list of paths from root to leaf in the tree of + {!type_paths} is the list of paths from root to leaf in the tree of the type. There is an annotation to indicate the child's position. Here it would be : [ [["->";"0"; "a"];["->"; "1"; "->"; "0"; "b"]; ...] ] It is used to sort results. *) - ; type_paths : string list list } type package = @@ -48,7 +53,7 @@ module Elt = struct { cost : int ; name : string ; kind : kind - ; doc : string option + ; doc : displayable option ; pkg : package option } diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index e4190019e3..edef85c663 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -186,10 +186,11 @@ module Make (Storage : Db.Storage.S) = struct Db_common.Elt.TypeDecl { html } | Module -> Db_common.Elt.ModuleType | Value { value = _; type_ } -> - let str_type = Render.html_of_type type_ in let paths = paths ~prefix:[] ~sgn:Pos type_ in - let str_type = string_of_html str_type in - Val { str_type; type_paths = paths } + let html = type_ |> Render.html_of_type |> string_of_html in + let txt = Render.text_of_type type_ in + let type_ = Db_common.Elt.{ html; txt } in + Val { type_; type_paths = paths } | Doc _ -> Doc | Exception _ -> Exception | Class_type _ -> Class_type @@ -233,7 +234,7 @@ module Make (Storage : Db.Storage.S) = struct | ModuleTypeSubstitution -> () | InstanceVariable _ -> () - let entry + let register_entry Odoc_search.Index_db. { id : Odoc_model.Paths.Identifier.Any.t ; doc : Odoc_model.Comment.docs @@ -244,8 +245,9 @@ module Make (Storage : Db.Storage.S) = struct let full_name = id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." in - let doc = doc |> Render.html_of_doc |> string_of_html |> Option.some - and doc_txt = Render.text_of_doc doc in + let html = doc |> Render.html_of_doc |> string_of_html + and txt = Render.text_of_doc doc in + let doc = Some Db_common.Elt.{ html; txt } in let kind' = convert_kind kind in let ignore_no_doc = @@ -257,11 +259,11 @@ module Make (Storage : Db.Storage.S) = struct let elt = { Db_common.Elt.name = full_name; kind = kind'; cost; doc; pkg = None } in - register_doc elt doc_txt ; + register_doc elt txt ; register_full_name full_name elt ; register_kind elt kind module Resolver = Odoc_odoc.Resolver - let run ~index = List.iter entry index + let run ~index = List.iter register_entry index end diff --git a/lib/index_lib/pretty.ml b/lib/index_lib/pretty.ml index a983063df1..12ac94a1af 100644 --- a/lib/index_lib/pretty.ml +++ b/lib/index_lib/pretty.ml @@ -2,9 +2,6 @@ open Odoc_model module ModuleName = Odoc_model.Names.ModuleName module H = Tyxml.Html - - - let show_module_name h md = Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) @@ -71,4 +68,3 @@ let show_type_name_verbose h : Paths.Path.Type.t -> _ = function (Resolved.identifier (t :> Resolved.t)) | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x - From eae585d0d90a91d508b70396814f2a17133bfb1b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 4 May 2023 13:53:01 +0200 Subject: [PATCH 057/285] odoc compat : links work --- bin/JSherlodoc/main.ml | 10 +++------- bin/www/ui.ml | 11 +++++++---- lib/db/types.ml | 3 ++- lib/index_lib/load_doc.ml | 24 ++++++++++++++++-------- test/cram/odoc.t/run.t | 1 + 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 3d26c1ba89..46d53c1824 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -28,20 +28,16 @@ let search query = in Jv.of_list - (fun Db.Elt.{ cost = _; name; kind; doc; pkg = _ } -> + (fun Db.Elt.{ cost = _; name; url; kind; doc; pkg = _ } -> let name = Jstr.of_string name in let kind = kind |> string_of_kind |> Jv.of_string in - let doc = - doc - |> Option.map (fun doc -> Db.Elt.(doc.txt)) - |> Option.value ~default:"" |> Jv.of_string - in Jv.( obj [| "name", of_jstr name ; "prefixname", of_string "" ; "kind", kind - ; "comment", doc + ; "comment", of_string doc.txt + ; "url", of_string url |])) results diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 733a062688..d06c48d2f5 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -14,8 +14,12 @@ let render_elt elt = let open Db.Elt in let link = render_link elt in match elt.kind with - | Val { str_type; _ } -> - [ txt "val "; a ~a:link [ em [ txt elt.name ] ]; txt " : "; txt str_type ] + | Val { type_; _ } -> + [ txt "val " + ; a ~a:link [ em [ txt elt.name ] ] + ; txt " : " + ; txt type_.txt + ] | Doc -> [ txt "comment "; a ~a:link [ em [ txt elt.name ] ] ] | TypeDecl { html = type_decl } -> [ txt "type " @@ -63,8 +67,7 @@ let render_pkg elt = let render_result elt = let open Db.Types.Elt in - render_pkg elt - @ (pre (render_elt elt) :: list_of_option (Option.map Unsafe.data elt.doc)) + render_pkg elt @ [ pre (render_elt elt); Unsafe.data elt.doc.Db.Elt.html ] let render ~pretty results = match results with diff --git a/lib/db/types.ml b/lib/db/types.ml index d03223c3e1..48e5490d21 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -53,8 +53,9 @@ module Elt = struct { cost : int ; name : string ; kind : kind - ; doc : displayable option + ; doc : displayable ; pkg : package option + ; url : string } let compare_pkg { name; version = _ } (b : package) = diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index edef85c663..1f301ad071 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -142,14 +142,14 @@ module Make (Storage : Db.Storage.S) = struct let my_full_name = List.map Char.lowercase_ascii my_full_name in Db.store_name (Cache_list.memo my_full_name) elt - let generic_cost ~ignore_no_doc full_name str_doc = + let generic_cost ~ignore_no_doc full_name doc = String.length full_name (* + (5 * List.length path) TODO : restore depth based ordering *) + (if ignore_no_doc then 0 else - match str_doc with - | None -> 1000 + match Db_common.Elt.(doc.txt) with + | "" -> 1000 | _ -> 0) + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 @@ -162,7 +162,7 @@ module Make (Storage : Db.Storage.S) = struct | Value { value = _; type_ } -> let str_type = type_ |> Render.html_of_type |> string_of_html in String.length str_type + type_size type_ - | Doc _ -> 0 + | Doc _ -> 200 | Exception _ -> 0 | Class_type _ -> 0 | Method _ -> 0 @@ -245,11 +245,11 @@ module Make (Storage : Db.Storage.S) = struct let full_name = id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." in + let url = Render.url id in let html = doc |> Render.html_of_doc |> string_of_html and txt = Render.text_of_doc doc in - let doc = Some Db_common.Elt.{ html; txt } in + let doc = Db_common.Elt.{ html; txt } in let kind' = convert_kind kind in - let ignore_no_doc = match kind with | Module | ModuleType -> true @@ -257,10 +257,18 @@ module Make (Storage : Db.Storage.S) = struct in let cost = generic_cost ~ignore_no_doc full_name doc + kind_cost kind in let elt = - { Db_common.Elt.name = full_name; kind = kind'; cost; doc; pkg = None } + { Db_common.Elt.name = full_name + ; url + ; kind = kind' + ; cost + ; doc + ; pkg = None + } in register_doc elt txt ; - register_full_name full_name elt ; + (match kind with + | Doc _ -> () + | _ -> register_full_name full_name elt) ; register_kind elt kind module Resolver = Odoc_odoc.Resolver diff --git a/test/cram/odoc.t/run.t b/test/cram/odoc.t/run.t index 5ded63ddae..5e71d555be 100644 --- a/test/cram/odoc.t/run.t +++ b/test/cram/odoc.t/run.t @@ -10,6 +10,7 @@ $ du -sh db.js 12K db.js $ odoc html-generate --with-search --output-dir html main.odocl + $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js $ cp -r html /tmp From a3bb78ba279845f9b7fe22c08ccf70a9b8210f7b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 4 May 2023 15:31:06 +0200 Subject: [PATCH 058/285] reogranization --- bin/www/ui.ml | 2 +- lib/common/int.ml | 2 + lib/common/string_list_map.ml | 7 +++ lib/db/db.ml | 23 ++++---- lib/db/db.mli | 8 +-- lib/db/elt.ml | 97 +++++++++++++++++++++++++++++++ lib/db/storage.ml | 2 +- lib/db/storage.mli | 2 +- lib/db/types.ml | 104 +--------------------------------- lib/query/sort.ml | 2 +- lib/query/succ.ml | 14 ++--- 11 files changed, 134 insertions(+), 129 deletions(-) create mode 100644 lib/common/int.ml create mode 100644 lib/common/string_list_map.ml create mode 100644 lib/db/elt.ml diff --git a/bin/www/ui.ml b/bin/www/ui.ml index d06c48d2f5..5043acc441 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -66,7 +66,7 @@ let render_pkg elt = | None -> [] let render_result elt = - let open Db.Types.Elt in + let open Db.Elt in render_pkg elt @ [ pre (render_elt elt); Unsafe.data elt.doc.Db.Elt.html ] let render ~pretty results = diff --git a/lib/common/int.ml b/lib/common/int.ml new file mode 100644 index 0000000000..0c6f8d8cf9 --- /dev/null +++ b/lib/common/int.ml @@ -0,0 +1,2 @@ +include Stdlib.Int +module Map = Map.Make (Stdlib.Int) diff --git a/lib/common/string_list_map.ml b/lib/common/string_list_map.ml new file mode 100644 index 0000000000..03e636ba75 --- /dev/null +++ b/lib/common/string_list_map.ml @@ -0,0 +1,7 @@ +module Self = Map.Make (struct + type t = string list + + let compare = List.compare String.compare +end) + +include Self diff --git a/lib/db/db.ml b/lib/db/db.ml index a492de6204..26e8eced05 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -1,3 +1,4 @@ +module Elt = Elt module Types = Types module Storage_toplevel = Storage module Trie = Trie @@ -10,8 +11,8 @@ module type S = sig val optimize : unit -> unit val export : writer -> unit - val store_all : Elt_set.elt -> char list list -> unit - val store_name : char list -> Elt_set.elt -> unit + val store_all : Elt.Set.elt -> char list list -> unit + val store_name : char list -> Elt.Set.elt -> unit val load_counter : int ref end @@ -23,14 +24,14 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let db_names = ref (Trie.empty ()) module Hset2 = Hashtbl.Make (struct - type t = Elt_set.t * Elt_set.t + type t = Elt.Set.t * Elt.Set.t let hash = Hashtbl.hash let equal (a, b) (a', b') = a == a' && b == b' end) module Hocc2 = Hashtbl.Make (struct - type t = Elt_set.t Occ.t * Elt_set.t Occ.t + type t = Elt.Set.t Occ.t * Elt.Set.t Occ.t let hash = Hashtbl.hash let equal (a, b) (a', b') = a == a' && b == b' @@ -39,7 +40,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let elt_set_union ~hs a b = try Hset2.find hs (a, b) with Not_found -> - let r = Elt_set.union a b in + let r = Elt.Set.union a b in Hset2.add hs (a, b) r ; Hset2.add hs (b, a) r ; r @@ -66,8 +67,8 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let optimize () = let ho = Hocc2.create 16 in let hs = Hset2.create 16 in - let (_ : Elt_set.t Occ.t option) = Trie.summarize (occ_merge ~ho ~hs) !db in - let (_ : Elt_set.t option) = Trie.summarize (elt_set_union ~hs) !db_names in + let (_ : Elt.Set.t Occ.t option) = Trie.summarize (occ_merge ~ho ~hs) !db in + let (_ : Elt.Set.t option) = Trie.summarize (elt_set_union ~hs) !db_names in () let export h = @@ -78,22 +79,22 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct db_names := Trie.empty () module Hset = Hashtbl.Make (struct - type t = Elt_set.t option + type t = Elt.Set.t option let hash = Hashtbl.hash let equal x y = Option.equal (fun x y -> x == y) x y end) module Hocc = Hashtbl.Make (struct - type t = Elt_set.t Occ.t option + type t = Elt.Set.t Occ.t option let hash = Hashtbl.hash let equal x y = Option.equal (fun x y -> x == y) x y end) let set_add elt = function - | None -> Elt_set.singleton elt - | Some s -> Elt_set.add elt s + | None -> Elt.Set.singleton elt + | Some s -> Elt.Set.add elt s let set_add ~hs elt opt = try Hset.find hs opt diff --git a/lib/db/db.mli b/lib/db/db.mli index c431d921ca..6493b9ead3 100644 --- a/lib/db/db.mli +++ b/lib/db/db.mli @@ -1,9 +1,7 @@ -module Elt = Types.Elt +module Elt = Elt module Types = Types module Storage = Storage module Trie = Trie -module Elt_set = Types.Elt_set -module String_list_map = Types.String_list_map val list_of_string : string -> char list @@ -12,8 +10,8 @@ module type S = sig val optimize : unit -> unit val export : writer -> unit - val store_all : Elt_set.elt -> char list list -> unit - val store_name : char list -> Elt_set.elt -> unit + val store_all : Elt.Set.elt -> char list list -> unit + val store_name : char list -> Elt.Set.elt -> unit val load_counter : int ref end diff --git a/lib/db/elt.ml b/lib/db/elt.ml new file mode 100644 index 0000000000..39b37df8ad --- /dev/null +++ b/lib/db/elt.ml @@ -0,0 +1,97 @@ +open Common + +type displayable = + { html : string + ; txt : string + } + +type kind = + | Doc + | TypeDecl of { html : string } + | Module + | Exception + | Class_type + | Method + | Class + | TypeExtension + | ExtensionConstructor + | ModuleType + | Constructor + | Field + | FunctorParameter + | ModuleSubstitution + | ModuleTypeSubstitution + | InstanceVariable + | Val of + { type_ : displayable + ; type_paths : string list list + (** A type can viewed as a tree. + [a -> b -> c * d] is the following tree : + {[ -> + |- a + |- -> + |- b + |- * + |- c + |- d + ]} + {!type_paths} is the list of paths from root to leaf in the tree of + the type. There is an annotation to indicate the child's position. + Here it would be : + [ [["->";"0"; "a"];["->"; "1"; "->"; "0"; "b"]; ...] ] + + It is used to sort results. *) + } + +type package = + { name : string + ; version : string + } + +module T = struct + type t = + { cost : int + ; name : string + ; kind : kind + ; doc : displayable + ; pkg : package option + ; url : string + } + + let compare_pkg { name; version = _ } (b : package) = + String.compare name b.name + + let compare a b = + match Int.compare a.cost b.cost with + | 0 -> begin + match String.compare a.name b.name with + | 0 -> begin + match Option.compare compare_pkg a.pkg b.pkg with + | 0 -> Stdlib.compare a.kind b.kind + | c -> c + end + | c -> c + end + | c -> c + + let compare a b = if a == b then 0 else compare a b +end + +include T + +let pkg_link { pkg; _ } = + let open Option.O in + let+ { name; version } = pkg in + Printf.sprintf "https://ocaml.org/p/%s/%s" name version + +let link t = + let open Option.O in + let name, path = + match List.rev (String.split_on_char '.' t.name) with + | name :: path -> name, String.concat "/" (List.rev path) + | _ -> "", "" + in + let+ pkg_link = pkg_link t in + pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name + +module Set = Set.Make (T) diff --git a/lib/db/storage.ml b/lib/db/storage.ml index 7da033af26..fa25dee477 100644 --- a/lib/db/storage.ml +++ b/lib/db/storage.ml @@ -1,6 +1,6 @@ type t = { db : Types.db - ; db_names : Types.Elt_set.t Trie.t + ; db_names : Elt.Set.t Trie.t } module type S = sig diff --git a/lib/db/storage.mli b/lib/db/storage.mli index 7da033af26..fa25dee477 100644 --- a/lib/db/storage.mli +++ b/lib/db/storage.mli @@ -1,6 +1,6 @@ type t = { db : Types.db - ; db_names : Types.Elt_set.t Trie.t + ; db_names : Elt.Set.t Trie.t } module type S = sig diff --git a/lib/db/types.ml b/lib/db/types.ml index 48e5490d21..5f087178c7 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -1,103 +1,5 @@ open Common -module Elt = struct - type displayable = - { html : string - ; txt : string - } - - type kind = - | Doc - | TypeDecl of { html : string } - | Module - | Exception - | Class_type - | Method - | Class - | TypeExtension - | ExtensionConstructor - | ModuleType - | Constructor - | Field - | FunctorParameter - | ModuleSubstitution - | ModuleTypeSubstitution - | InstanceVariable - | Val of - { type_ : displayable - ; type_paths : string list list - (** A type can viewed as a tree. - [a -> b -> c * d] is the following tree : - {[ -> - |- a - |- -> - |- b - |- * - |- c - |- d - ]} - {!type_paths} is the list of paths from root to leaf in the tree of - the type. There is an annotation to indicate the child's position. - Here it would be : - [ [["->";"0"; "a"];["->"; "1"; "->"; "0"; "b"]; ...] ] - - It is used to sort results. *) - } - - type package = - { name : string - ; version : string - } - - type t = - { cost : int - ; name : string - ; kind : kind - ; doc : displayable - ; pkg : package option - ; url : string - } - - let compare_pkg { name; version = _ } (b : package) = - String.compare name b.name - - let compare a b = - match Int.compare a.cost b.cost with - | 0 -> begin - match String.compare a.name b.name with - | 0 -> begin - match Option.compare compare_pkg a.pkg b.pkg with - | 0 -> Stdlib.compare a.kind b.kind - | c -> c - end - | c -> c - end - | c -> c - - let compare a b = if a == b then 0 else compare a b - - let pkg_link { pkg; _ } = - let open Option.O in - let+ { name; version } = pkg in - Printf.sprintf "https://ocaml.org/p/%s/%s" name version - - let link t = - let open Option.O in - let name, path = - match List.rev (String.split_on_char '.' t.name) with - | name :: path -> name, String.concat "/" (List.rev path) - | _ -> "", "" - in - let+ pkg_link = pkg_link t in - pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name -end - -module String_list_map = Map.Make (struct - type t = string list - - let compare = List.compare String.compare -end) - let regroup lst = String_list_map.bindings @@ List.fold_left @@ -120,11 +22,9 @@ let regroup_chars lst = Char_list_map.add s (count + 1) acc) Char_list_map.empty lst -module Int_map = Map.Make (Int) -module Elt_set = Set.Make (Elt) -module Occ = Int_map +module Occ = Int.Map -type candidates = Elt_set.t Occ.t +type candidates = Elt.Set.t Occ.t type db = candidates Trie.t type sgn = diff --git a/lib/query/sort.ml b/lib/query/sort.ml index 93087d0219..735fad30c2 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -1,4 +1,4 @@ -module Elt = Db.Types.Elt +module Elt = Db.Elt let is_substring ~sub s = let re = Re.(compile (seq [ rep any; str sub ])) in diff --git a/lib/query/succ.ml b/lib/query/succ.ml index 636eaf31a8..97d932df22 100644 --- a/lib/query/succ.ml +++ b/lib/query/succ.ml @@ -1,9 +1,9 @@ -open Db.Types +open Db type s = | All | Empty - | Set of Elt_set.t + | Set of Elt.Set.t | Inter of s * s | Union of s * s @@ -16,9 +16,9 @@ let all = { cardinal = -1; s = All } let empty = { cardinal = 0; s = Empty } let of_set s = - if Elt_set.is_empty s + if Elt.Set.is_empty s then empty - else { cardinal = Elt_set.cardinal s; s = Set s } + else { cardinal = Elt.Set.cardinal s; s = Set s } let inter a b = match a.s, b.s with @@ -38,9 +38,9 @@ let union a b = let x, y = if a.cardinal < b.cardinal then x, y else y, x in { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } -let succ_ge' elt set = Elt_set.find_first (fun e -> Elt.compare e elt >= 0) set -let succ_gt' elt set = Elt_set.find_first (fun e -> Elt.compare e elt > 0) set -let first' set = Elt_set.find_first (fun _ -> true) set +let succ_ge' elt set = Elt.Set.find_first (fun e -> Elt.compare e elt >= 0) set +let succ_gt' elt set = Elt.Set.find_first (fun e -> Elt.compare e elt > 0) set +let first' set = Elt.Set.find_first (fun _ -> true) set exception Gt of Elt.t From 2cdd2b56a611362c424f6e55bd338a1c6521b292 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 4 May 2023 15:36:23 +0200 Subject: [PATCH 059/285] char_list_map separated --- lib/common/char_list_map.ml | 7 +++++++ lib/db/types.ml | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 lib/common/char_list_map.ml diff --git a/lib/common/char_list_map.ml b/lib/common/char_list_map.ml new file mode 100644 index 0000000000..efbcb8d141 --- /dev/null +++ b/lib/common/char_list_map.ml @@ -0,0 +1,7 @@ +module Self = Map.Make (struct + type t = char list + + let compare = List.compare Char.compare +end) + +include Self diff --git a/lib/db/types.ml b/lib/db/types.ml index 5f087178c7..f1827b74f1 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -8,11 +8,7 @@ let regroup lst = String_list_map.add s (count + 1) acc) String_list_map.empty lst -module Char_list_map = Map.Make (struct - type t = char list - let compare = List.compare Char.compare -end) let regroup_chars lst = Char_list_map.bindings From d3bb61bf2dd4883b5ea4c048f1d5bd33138b2717 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 10 May 2023 14:15:01 +0200 Subject: [PATCH 060/285] Adds type based search of constructors and fields --- bin/JSherlodoc/main.ml | 1 - lib/db/types.ml | 2 -- lib/index_lib/load_doc.ml | 37 +++++++++++++++++++++++++++---------- lib/index_lib/pretty.ml | 4 +++- test/cram/odoc.t/main.ml | 17 ++++++++++++++--- test/cram/odoc.t/run.t | 2 ++ 6 files changed, 46 insertions(+), 17 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 46d53c1824..cf594d4a4e 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -26,7 +26,6 @@ let search query = let _pretty_query, results = Query.(api ~shards:db { query; packages = []; limit = 50 }) in - Jv.of_list (fun Db.Elt.{ cost = _; name; url; kind; doc; pkg = _ } -> let name = Jstr.of_string name in diff --git a/lib/db/types.ml b/lib/db/types.ml index f1827b74f1..734721bcc4 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -8,8 +8,6 @@ let regroup lst = String_list_map.add s (count + 1) acc) String_list_map.empty lst - - let regroup_chars lst = Char_list_map.bindings @@ List.fold_left diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 1f301ad071..4f5c4387d7 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -206,19 +206,24 @@ module Make (Storage : Db.Storage.S) = struct | ModuleTypeSubstitution -> ModuleTypeSubstitution | InstanceVariable _ -> InstanceVariable + let register_type_expr elt type_ = + let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in + (* let str = String.concat "|" (List.concat_map (fun li -> ";" :: li) type_paths) in + print_endline str; *) + Db.store_all elt + (List.map + (fun xs -> + let xs = List.concat_map Db_common.list_of_string xs in + Cache_list.memo xs) + type_paths) + let register_kind elt (kind : Odoc_search.Index_db.kind) = let open Odoc_search.Index_db in + let open Odoc_model.Lang in match kind with | TypeDecl _ -> () | Module -> () - | Value { value = _; type_ } -> - let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in - Db.store_all elt - (List.map - (fun xs -> - let xs = List.concat_map Db_common.list_of_string xs in - Cache_list.memo xs) - type_paths) + | Value { value = _; type_ } -> register_type_expr elt type_ | Doc _ -> () | Exception _ -> () | Class_type _ -> () @@ -227,8 +232,20 @@ module Make (Storage : Db.Storage.S) = struct | TypeExtension _ -> () | ExtensionConstructor _ -> () | ModuleType -> () - | Constructor _ -> () - | Field _ -> () + | Constructor { args = TypeDecl.Constructor.Tuple args; res } -> + let type_ = + match args with + | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) + | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) + | _ -> res + in + register_type_expr elt type_ + | Constructor + { args = Odoc_model.Lang.TypeDecl.Constructor.Record _; res = _ } -> + () + | Field { mutable_ = _; parent_type; type_ } -> + let type_ = TypeExpr.Arrow (None, parent_type, type_) in + register_type_expr elt type_ | FunctorParameter -> () | ModuleSubstitution _ -> () | ModuleTypeSubstitution -> () diff --git a/lib/index_lib/pretty.ml b/lib/index_lib/pretty.ml index 12ac94a1af..32cd310a58 100644 --- a/lib/index_lib/pretty.ml +++ b/lib/index_lib/pretty.ml @@ -66,5 +66,7 @@ let show_type_name_verbose h : Paths.Path.Type.t -> _ = function let open Paths.Path in Format.fprintf h "%a" show_ident_long (Resolved.identifier (t :> Resolved.t)) - | `Identifier (_, b) -> Format.fprintf h "IDENT%b" b + | `Identifier (path, _hidden) -> + let name = Paths.Identifier.(fullname (path :> t)) |> String.concat "." in + Format.fprintf h "%s" name | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x diff --git a/test/cram/odoc.t/main.ml b/test/cram/odoc.t/main.ml index c740666304..6a4ebc012d 100644 --- a/test/cram/odoc.t/main.ml +++ b/test/cram/odoc.t/main.ml @@ -23,16 +23,27 @@ let v = 9 (** lorem 1 *) -let lorem = 1 +let lorem = fun _ -> 'a' (** lorem 2 *) -let lorem2 = 1 +let lorem2 = fun _ -> 'a' (** lorem 3 *) -let lorem3 = 1 +let lorem3 = fun _ -> 'e' (** lorem 4 *) let lorem4 = 1 + + +type my_type = int * char + +type babar = + | A of string + | B + | C of int + +type celeste = + {x : babar; y : int -> string} \ No newline at end of file diff --git a/test/cram/odoc.t/run.t b/test/cram/odoc.t/run.t index 5e71d555be..e26d4e464b 100644 --- a/test/cram/odoc.t/run.t +++ b/test/cram/odoc.t/run.t @@ -3,6 +3,7 @@ $ odoc compile -I . page.mld $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc +$ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/**/*.odocl . $ odoc compile-index --binary -I . -o index.odoc_bin $ du -sh index.odoc_bin 4.0K index.odoc_bin @@ -10,6 +11,7 @@ $ du -sh db.js 12K db.js $ odoc html-generate --with-search --output-dir html main.odocl +$ odoc html-generate --with-search --output-dir html stdlib.odocl $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js From fa59ab8e483fb7f30970196949b3a7a5af208f24 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 10 May 2023 16:43:12 +0200 Subject: [PATCH 061/285] Print types --- bin/JSherlodoc/main.ml | 30 +++++++++++++-------- bin/www/ui.ml | 14 ++++++++-- lib/db/elt.ml | 46 ++++++++++++++++++-------------- lib/index_lib/load_doc.ml | 55 ++++++++++++++++++++++++++++----------- lib/query/sort.ml | 10 ++++--- test/cram/odoc.t/main.ml | 2 +- 6 files changed, 105 insertions(+), 52 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index cf594d4a4e..13f8ad3f65 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -13,8 +13,8 @@ let string_of_kind (kind : Db.Elt.kind) = | TypeExtension -> "type ext" | ExtensionConstructor -> "extension constructor" | ModuleType -> "module type" - | Constructor -> "constructor" - | Field -> "field" + | Constructor _ -> "constructor" + | Field _ -> "field" | FunctorParameter -> "functor parameter" | ModuleSubstitution -> "module subst" | ModuleTypeSubstitution -> "module type subst" @@ -29,15 +29,23 @@ let search query = Jv.of_list (fun Db.Elt.{ cost = _; name; url; kind; doc; pkg = _ } -> let name = Jstr.of_string name in - let kind = kind |> string_of_kind |> Jv.of_string in - Jv.( - obj - [| "name", of_jstr name - ; "prefixname", of_string "" - ; "kind", kind - ; "comment", of_string doc.txt - ; "url", of_string url - |])) + let jkind = kind |> string_of_kind |> Jv.of_string in + let o = + Jv.( + obj + [| "name", of_jstr name + ; "prefixname", of_string "" + ; "kind", jkind + ; "comment", of_string doc.txt + ; "url", of_string url + |]) + in + Db.Elt.( + match kind with + | Val { type_; _ } | Constructor { type_; _ } | Field { type_; _ } -> + Jv.(set o "type" (of_string type_.txt)) + | _ -> ()) ; + o) results let main () = diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 5043acc441..278f8cd6bc 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -37,8 +37,18 @@ let render_elt elt = | ExtensionConstructor -> [ txt "ext constructor "; a ~a:link [ em [ txt elt.name ] ] ] | ModuleType -> [ txt "module type "; a ~a:link [ em [ txt elt.name ] ] ] - | Constructor -> [ txt "constructor "; a ~a:link [ em [ txt elt.name ] ] ] - | Field -> [ txt "field "; a ~a:link [ em [ txt elt.name ] ] ] + | Constructor { type_; _ } -> + [ txt "constructor " + ; a ~a:link [ em [ txt elt.name ] ] + ; txt " : " + ; txt type_.txt + ] + | Field { type_; _ } -> + [ txt "field " + ; a ~a:link [ em [ txt elt.name ] ] + ; txt " : " + ; txt type_.txt + ] | FunctorParameter -> [ txt "functor param "; a ~a:link [ em [ txt elt.name ] ] ] | ModuleSubstitution -> diff --git a/lib/db/elt.ml b/lib/db/elt.ml index 39b37df8ad..2e29421b9e 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -5,6 +5,24 @@ type displayable = ; txt : string } +type type_path = string list list +(** A type can viewed as a tree. + [a -> b -> c * d] is the following tree : + {[ -> + |- a + |- -> + |- b + |- * + |- c + |- d + ]} + {!type_paths} is the list of paths from root to leaf in the tree of + the type. There is an annotation to indicate the child's position. + Here it would be : + [ [["->";"0"; "a"];["->"; "1"; "->"; "0"; "b"]; ...] ] + + It is used to sort results. *) + type kind = | Doc | TypeDecl of { html : string } @@ -16,31 +34,21 @@ type kind = | TypeExtension | ExtensionConstructor | ModuleType - | Constructor - | Field + | Constructor of + { type_ : displayable + ; type_paths : type_path + } + | Field of + { type_ : displayable + ; type_paths : type_path + } | FunctorParameter | ModuleSubstitution | ModuleTypeSubstitution | InstanceVariable | Val of { type_ : displayable - ; type_paths : string list list - (** A type can viewed as a tree. - [a -> b -> c * d] is the following tree : - {[ -> - |- a - |- -> - |- b - |- * - |- c - |- d - ]} - {!type_paths} is the list of paths from root to leaf in the tree of - the type. There is an annotation to indicate the child's position. - Here it would be : - [ [["->";"0"; "a"];["->"; "1"; "->"; "0"; "b"]; ...] ] - - It is used to sort results. *) + ; type_paths : type_path } type package = diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 4f5c4387d7..76e648e0de 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -177,6 +177,33 @@ module Make (Storage : Db.Storage.S) = struct | ModuleTypeSubstitution -> 0 | InstanceVariable _ -> 0 + let searchable_type_of_constructor args res = + let open Odoc_model.Lang in + match args with + | TypeDecl.Constructor.Tuple args -> ( + match args with + | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) + | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) + | _ -> res) + | TypeDecl.Constructor.Record fields -> + List.fold_left + (fun res field -> + let open TypeDecl.Field in + let field_name = Odoc_model.Paths.Identifier.name field.id in + TypeExpr.Arrow (Some (Label field_name), field.type_, res)) + res fields + + let searchable_type_of_record parent_type type_ = + let open Odoc_model.Lang in + TypeExpr.Arrow (None, parent_type, type_) + + let display_type_expr type_ = + let open Odoc_search in + let html = type_ |> Render.html_of_type |> string_of_html in + let txt = Render.text_of_type type_ in + print_endline txt ; + Db_common.Elt.{ html; txt } + let convert_kind (kind : Odoc_search.Index_db.kind) = let open Odoc_search in let open Odoc_search.Index_db in @@ -187,10 +214,18 @@ module Make (Storage : Db.Storage.S) = struct | Module -> Db_common.Elt.ModuleType | Value { value = _; type_ } -> let paths = paths ~prefix:[] ~sgn:Pos type_ in - let html = type_ |> Render.html_of_type |> string_of_html in - let txt = Render.text_of_type type_ in - let type_ = Db_common.Elt.{ html; txt } in + let type_ = display_type_expr type_ in Val { type_; type_paths = paths } + | Constructor { args; res } -> + let type_ = searchable_type_of_constructor args res in + let type_paths = paths ~prefix:[] ~sgn:Pos type_ in + let type_ = display_type_expr type_ in + Constructor { type_; type_paths } + | Field { mutable_ = _; parent_type; type_ } -> + let type_ = searchable_type_of_record parent_type type_ in + let type_paths = paths ~prefix:[] ~sgn:Pos type_ in + let type_ = display_type_expr type_ in + Field { type_; type_paths } | Doc _ -> Doc | Exception _ -> Exception | Class_type _ -> Class_type @@ -199,8 +234,6 @@ module Make (Storage : Db.Storage.S) = struct | TypeExtension _ -> TypeExtension | ExtensionConstructor _ -> ExtensionConstructor | ModuleType -> ModuleType - | Constructor _ -> Constructor - | Field _ -> Field | FunctorParameter -> FunctorParameter | ModuleSubstitution _ -> ModuleSubstitution | ModuleTypeSubstitution -> ModuleTypeSubstitution @@ -232,17 +265,9 @@ module Make (Storage : Db.Storage.S) = struct | TypeExtension _ -> () | ExtensionConstructor _ -> () | ModuleType -> () - | Constructor { args = TypeDecl.Constructor.Tuple args; res } -> - let type_ = - match args with - | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) - | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) - | _ -> res - in + | Constructor { args; res } -> + let type_ = searchable_type_of_constructor args res in register_type_expr elt type_ - | Constructor - { args = Odoc_model.Lang.TypeDecl.Constructor.Record _; res = _ } -> - () | Field { mutable_ = _; parent_type; type_ } -> let type_ = TypeExpr.Arrow (None, parent_type, type_) in register_type_expr elt type_ diff --git a/lib/query/sort.ml b/lib/query/sort.ml index 735fad30c2..4a9fddb9a5 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -150,11 +150,13 @@ let list query_name query_type results = let name_cost = score_name query_name a.name in let type_cost = match a.kind with - | Val { type_paths; _ } -> score_type query_type type_paths + | Val { type_paths; _ } + | Constructor { type_paths; _ } + | Field { type_paths; _ } -> + score_type query_type type_paths | Doc | TypeDecl _ | Module | Exception | Class_type | Method | Class - | TypeExtension | ExtensionConstructor | ModuleType | Constructor - | Field | FunctorParameter | ModuleSubstitution - | ModuleTypeSubstitution | InstanceVariable -> + | TypeExtension | ExtensionConstructor | ModuleType | FunctorParameter + | ModuleSubstitution | ModuleTypeSubstitution | InstanceVariable -> 0 in let cost = a.Elt.cost + (2 * name_cost) + (800 * type_cost) in diff --git a/test/cram/odoc.t/main.ml b/test/cram/odoc.t/main.ml index 6a4ebc012d..68e2d1a49a 100644 --- a/test/cram/odoc.t/main.ml +++ b/test/cram/odoc.t/main.ml @@ -43,7 +43,7 @@ type my_type = int * char type babar = | A of string | B - | C of int + | C of {z:int; w:char} type celeste = {x : babar; y : int -> string} \ No newline at end of file From 27faf9beb4d7aeed6176bcfcc336387c0006a891 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 15 May 2023 15:46:34 +0200 Subject: [PATCH 062/285] REfactoring + new sorting system --- bin/JSherlodoc/main.ml | 5 +- lib/common/list.ml | 7 + lib/{index_lib => db}/cache.ml | 0 lib/{index_lib => db}/cache.mli | 0 lib/db/caches.ml | 38 +++ lib/db/db.ml | 21 +- lib/db/db.mli | 5 +- lib/index_lib/load_doc.ml | 133 +++------ lib/query/sort.ml | 490 +++++++++++++++++++++----------- lib/storage_js/storage_js.ml | 2 +- test/cram/odoc.t/run.t | 21 +- 11 files changed, 458 insertions(+), 264 deletions(-) create mode 100644 lib/common/list.ml rename lib/{index_lib => db}/cache.ml (100%) rename lib/{index_lib => db}/cache.mli (100%) create mode 100644 lib/db/caches.ml diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 13f8ad3f65..8748402821 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -1,4 +1,5 @@ -let db = Storage_js.load Jv.(to_string @@ get global "sherlodb") +let db = lazy ( +Storage_js.load Jv.(to_string @@ call global "sherlodoc_db" [||])) let string_of_kind (kind : Db.Elt.kind) = let open Db.Elt in @@ -24,7 +25,7 @@ let string_of_kind (kind : Db.Elt.kind) = let search query = let query = query |> Jv.to_jstr |> Jstr.to_string in let _pretty_query, results = - Query.(api ~shards:db { query; packages = []; limit = 50 }) + Query.(api ~shards:(Lazy.force db) { query; packages = []; limit = 50 }) in Jv.of_list (fun Db.Elt.{ cost = _; name; url; kind; doc; pkg = _ } -> diff --git a/lib/common/list.ml b/lib/common/list.ml new file mode 100644 index 0000000000..38809c948e --- /dev/null +++ b/lib/common/list.ml @@ -0,0 +1,7 @@ +include Stdlib.List + +let sort_map ~f ~compare li = + li + |> map (fun elt -> elt, f elt) + |> sort (fun (_, wit) (_, wit') -> compare wit wit') + |> map (fun (elt, _) -> elt) diff --git a/lib/index_lib/cache.ml b/lib/db/cache.ml similarity index 100% rename from lib/index_lib/cache.ml rename to lib/db/cache.ml diff --git a/lib/index_lib/cache.mli b/lib/db/cache.mli similarity index 100% rename from lib/index_lib/cache.mli rename to lib/db/cache.mli diff --git a/lib/db/caches.ml b/lib/db/caches.ml new file mode 100644 index 0000000000..643f8f18f9 --- /dev/null +++ b/lib/db/caches.ml @@ -0,0 +1,38 @@ +module Cache = Cache.Make (struct +type t = string + +let copy str = String.init (String.length str) (String.get str) +end) + +module Cache_list = struct +module H = Hashtbl.Make (struct + type t = char list + + let equal = List.equal Char.equal + let hash = Hashtbl.hash +end) + +let cache = H.create 128 + +let memo lst = + let rec go lst = + try H.find cache lst + with Not_found -> + let lst = + match lst with + | [] -> [] + | x :: xs -> x :: go xs + in + H.add cache lst lst ; + lst + in + go lst +end + +(* + <* for%iter item do *> + + ... + + <* done *> +*) \ No newline at end of file diff --git a/lib/db/db.ml b/lib/db/db.ml index 26e8eced05..d711e32da5 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -2,7 +2,9 @@ module Elt = Elt module Types = Types module Storage_toplevel = Storage module Trie = Trie +module Caches = Caches include Types +open Caches let list_of_string s = List.init (String.length s) (String.get s) @@ -11,8 +13,8 @@ module type S = sig val optimize : unit -> unit val export : writer -> unit - val store_all : Elt.Set.elt -> char list list -> unit - val store_name : char list -> Elt.Set.elt -> unit + val store_type : Elt.t -> char list list -> unit + val store_word : string -> Elt.t -> unit val load_counter : int ref end @@ -117,34 +119,37 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct Hocc.add ho opt r ; r - let store ~ho ~hs name typ ~count = + let store ~ho ~hs name elt ~count = let rec go db name = match name with | [] -> db | _ :: next -> incr load_counter ; - let db = Trie.add name (candidates_add ~ho ~hs typ ~count) db in + let db = Trie.add name (candidates_add ~ho ~hs elt ~count) db in go db next in db := go !db name - let store_all typ paths = + let store_type elt paths = let ho = Hocc.create 16 in let hs = Hset.create 16 in List.iter - (fun (path, count) -> store ~ho ~hs ~count path typ) + (fun (path, count) -> store ~ho ~hs ~count path elt) (regroup_chars paths) - let store_name name typ = + let store_chars name elt = let hs = Hset.create 16 in let rec go db = function | [] -> db | _ :: next as name -> incr load_counter ; - let db = Trie.add name (set_add ~hs typ) db in + let db = Trie.add name (set_add ~hs elt) db in go db next in db_names := go !db_names name + + let store_word word elt = + (word |> list_of_string |> List.rev |> Cache_list.memo |> store_chars) elt end module Storage = Storage diff --git a/lib/db/db.mli b/lib/db/db.mli index 6493b9ead3..a5e7362e7f 100644 --- a/lib/db/db.mli +++ b/lib/db/db.mli @@ -2,6 +2,7 @@ module Elt = Elt module Types = Types module Storage = Storage module Trie = Trie +module Caches = Caches val list_of_string : string -> char list @@ -10,8 +11,8 @@ module type S = sig val optimize : unit -> unit val export : writer -> unit - val store_all : Elt.Set.elt -> char list list -> unit - val store_name : char list -> Elt.Set.elt -> unit + val store_type : Elt.t -> char list list -> unit + val store_word : string -> Elt.t -> unit val load_counter : int ref end diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 76e648e0de..1facd27a70 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -1,41 +1,11 @@ module Db_common = Db +open Db.Caches module Make (Storage : Db.Storage.S) = struct module Types = Db.Types module Db = Db.Make (Storage) module ModuleName = Odoc_model.Names.ModuleName - module Cache = Cache.Make (struct - type t = string - - let copy str = String.init (String.length str) (String.get str) - end) - - module Cache_list = struct - module H = Hashtbl.Make (struct - type t = char list - - let equal = List.equal Char.equal - let hash = Hashtbl.hash - end) - - let cache = H.create 128 - - let memo lst = - let rec go lst = - try H.find cache lst - with Not_found -> - let lst = - match lst with - | [] -> [] - | x :: xs -> x :: go xs - in - H.add cache lst lst ; - lst - in - go lst - end - let clear () = Cache.clear () let rec type_size = function @@ -131,51 +101,11 @@ module Make (Storage : Db.Storage.S) = struct let register_doc elt doc_txt = let doc_words = String.split_on_char ' ' doc_txt in - List.iter - (fun word -> - let word = Db_common.list_of_string word in - Db.store_name (Cache_list.memo word) elt) - doc_words + List.iter (fun word -> Db.store_word word elt) doc_words let register_full_name name elt = - let my_full_name = Db_common.list_of_string name in - let my_full_name = List.map Char.lowercase_ascii my_full_name in - Db.store_name (Cache_list.memo my_full_name) elt - - let generic_cost ~ignore_no_doc full_name doc = - String.length full_name - (* + (5 * List.length path) TODO : restore depth based ordering *) - + (if ignore_no_doc - then 0 - else - match Db_common.Elt.(doc.txt) with - | "" -> 1000 - | _ -> 0) - + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 - - let kind_cost (kind : Odoc_search.Index_db.kind) = - let open Odoc_search in - let open Odoc_search.Index_db in - match kind with - | TypeDecl _ -> 0 - | Module -> 0 - | Value { value = _; type_ } -> - let str_type = type_ |> Render.html_of_type |> string_of_html in - String.length str_type + type_size type_ - | Doc _ -> 200 - | Exception _ -> 0 - | Class_type _ -> 0 - | Method _ -> 0 - | Class _ -> 0 - | TypeExtension _ -> 0 - | ExtensionConstructor _ -> 0 - | ModuleType -> 0 - | Constructor _ -> 0 - | Field _ -> 0 - | FunctorParameter -> 0 - | ModuleSubstitution _ -> 0 - | ModuleTypeSubstitution -> 0 - | InstanceVariable _ -> 0 + let name = String.lowercase_ascii name in + Db.store_word name elt let searchable_type_of_constructor args res = let open Odoc_model.Lang in @@ -201,9 +131,37 @@ module Make (Storage : Db.Storage.S) = struct let open Odoc_search in let html = type_ |> Render.html_of_type |> string_of_html in let txt = Render.text_of_type type_ in - print_endline txt ; Db_common.Elt.{ html; txt } + let generic_cost ~ignore_no_doc full_name doc = + String.length full_name + (* + (5 * List.length path) TODO : restore depth based ordering *) + + (if ignore_no_doc + then 0 + else + match Db_common.Elt.(doc.txt) with + | "" -> 1000 + | _ -> 0) + + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 + + let type_cost type_ = + String.length (display_type_expr type_).txt + type_size type_ + + let kind_cost (kind : Odoc_search.Index_db.kind) = + let open Odoc_search in + let open Odoc_search.Index_db in + match kind with + | Constructor { args; res } -> + type_cost (searchable_type_of_constructor args res) + | Field { parent_type; type_; _ } -> + type_cost (searchable_type_of_record parent_type type_) + | Value { value = _; type_ } -> type_cost type_ + | Doc _ -> 400 + | TypeDecl _ | Module | Exception _ | Class_type _ | Method _ | Class _ + | TypeExtension _ | ExtensionConstructor _ | ModuleType | FunctorParameter + | ModuleSubstitution _ | ModuleTypeSubstitution | InstanceVariable _ -> + 200 + let convert_kind (kind : Odoc_search.Index_db.kind) = let open Odoc_search in let open Odoc_search.Index_db in @@ -243,7 +201,7 @@ module Make (Storage : Db.Storage.S) = struct let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in (* let str = String.concat "|" (List.concat_map (fun li -> ";" :: li) type_paths) in print_endline str; *) - Db.store_all elt + Db.store_type elt (List.map (fun xs -> let xs = List.concat_map Db_common.list_of_string xs in @@ -288,9 +246,11 @@ module Make (Storage : Db.Storage.S) = struct id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." in let url = Render.url id in - let html = doc |> Render.html_of_doc |> string_of_html - and txt = Render.text_of_doc doc in - let doc = Db_common.Elt.{ html; txt } in + let doc = + let html = doc |> Render.html_of_doc |> string_of_html + and txt = Render.text_of_doc doc in + Db_common.Elt.{ html; txt } + in let kind' = convert_kind kind in let ignore_no_doc = match kind with @@ -298,16 +258,15 @@ module Make (Storage : Db.Storage.S) = struct | _ -> false in let cost = generic_cost ~ignore_no_doc full_name doc + kind_cost kind in + let name = + match kind with + | Doc _ -> Odoc_model.Paths.Identifier.prefixname id + | _ -> full_name + in let elt = - { Db_common.Elt.name = full_name - ; url - ; kind = kind' - ; cost - ; doc - ; pkg = None - } + Db_common.Elt.{ name; url; kind = kind'; cost; doc; pkg = None } in - register_doc elt txt ; + register_doc elt doc.txt ; (match kind with | Doc _ -> () | _ -> register_full_name full_name elt) ; diff --git a/lib/query/sort.ml b/lib/query/sort.ml index 4a9fddb9a5..2ea4201edc 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -1,166 +1,334 @@ +open Common module Elt = Db.Elt -let is_substring ~sub s = - let re = Re.(compile (seq [ rep any; str sub ])) in - Re.execp re s - -let score_name query_name name = - if String.starts_with ~prefix:query_name name - || String.ends_with ~suffix:query_name name - then 1 - else if is_substring ~sub:("(" ^ query_name) name - || is_substring ~sub:(query_name ^ ")") name - then 1 - else if is_substring ~sub:("." ^ query_name) name - || is_substring ~sub:(query_name ^ ".") name - then 2 - else if is_substring ~sub:("_" ^ query_name) name - || is_substring ~sub:(query_name ^ "_") name - then 3 - else if is_substring ~sub:query_name name - then 4 - else (* Matches only in the docstring are always worse *) 2000 - -let score_name query_name name = - match score_name query_name name with - | 4 -> - let query_name_lower = String.lowercase_ascii query_name in - let name_lower = String.lowercase_ascii name in - 3 - + (if query_name = query_name_lower then 0 else 100) - + score_name query_name_lower name_lower - | c -> c - -let score_name query_name name = - List.fold_left - (fun acc query_name -> acc + score_name query_name name) - 0 query_name - -let distance xs ys = - let len_xs = List.length xs in - let len_ys = List.length ys in - let cache = Array.make_matrix (1 + len_xs) (1 + len_ys) (-1) in - let rec memo i j xs ys = - let r = cache.(i).(j) in - if r >= 0 - then r - else begin - let r = go i j xs ys in - cache.(i).(j) <- r ; - r - end - and go i j xs ys = - match xs, ys with - | [], _ -> 0 - | [ "_" ], _ -> 0 - | _, [] -> List.length xs - | x :: xs, y :: ys when String.ends_with ~suffix:x y -> - memo (i + 1) (j + 1) xs ys - | _, "->1" :: ys -> memo i (j + 1) xs ys - | "->1" :: xs, _ -> 1 + memo (i + 1) j xs ys - | _ :: xs', _ :: ys' -> - 7 - + min - (memo (i + 1) (j + 1) xs' ys') - (min (memo (i + 1) j xs' ys) (memo i (j + 1) xs ys')) - in - go 0 0 xs ys - -let minimize = function - | [] -> 0 - | arr -> - let used = Array.make (List.length (List.hd arr)) false in - let arr = - Array.map (fun lst -> - let lst = (1, None) :: List.mapi (fun i x -> x, Some i) lst in - List.sort Stdlib.compare lst) - @@ Array.of_list arr - in - Array.sort (fun xs ys -> Stdlib.compare xs ys) arr ; - let heuristics = Array.make (Array.length arr + 1) 0 in - for i = Array.length heuristics - 2 downto 0 do - let best = fst (List.hd arr.(i)) in - heuristics.(i) <- heuristics.(i + 1) + best - done ; - let best = ref 1000 in - let limit = ref 0 in - let rec go rem acc i = - incr limit ; - if !limit > 10_000 - then false - else if rem <= 0 - then begin - let score = acc + (1 * (Array.length arr - i)) in - best := min score !best ; - true - end - else if i >= Array.length arr - then begin - best := min !best (acc + (100 * rem)) ; - true - end - else if acc + heuristics.(i) >= !best - then true - else - let rec find = function - | [] -> true - | (cost, j) :: rest -> - let ok = - match j with - | None -> - go rem - (acc + cost - + if rem > Array.length arr - i then 100 else 0) - (i + 1) - | Some j -> - if used.(j) - then true - else begin - used.(j) <- true ; - let ok = go (rem - 1) (acc + cost) (i + 1) in - used.(j) <- false ; - ok - end - in - if ok then find rest else false - in - find arr.(i) - in - let _ = go (Array.length used) 0 0 in - !best - -let score_type query_type paths = - match paths, query_type with - | _, [] | [], _ -> 0 - | _ -> - let arr = - List.map - (fun p -> - let p = List.rev p in - List.map (fun q -> distance (List.rev q) p) query_type) - paths +module Type_distance = struct + let distance xs ys = + let len_xs = List.length xs in + let len_ys = List.length ys in + let cache = Array.make_matrix (1 + len_xs) (1 + len_ys) (-1) in + let rec memo i j xs ys = + let r = cache.(i).(j) in + if r >= 0 + then r + else begin + let r = go i j xs ys in + cache.(i).(j) <- r ; + r + end + and go i j xs ys = + match xs, ys with + | [], _ -> 0 + | [ "_" ], _ -> 0 + | _, [] -> List.length xs + | x :: xs, y :: ys when String.ends_with ~suffix:x y -> + memo (i + 1) (j + 1) xs ys + | _, "->1" :: ys -> memo i (j + 1) xs ys + | "->1" :: xs, _ -> 1 + memo (i + 1) j xs ys + | _ :: xs', _ :: ys' -> + 7 + + min + (memo (i + 1) (j + 1) xs' ys') + (min (memo (i + 1) j xs' ys) (memo i (j + 1) xs ys')) + in + go 0 0 xs ys + + let minimize = function + | [] -> 0 + | arr -> + let used = Array.make (List.length (List.hd arr)) false in + let arr = + Array.map (fun lst -> + let lst = (1, None) :: List.mapi (fun i x -> x, Some i) lst in + List.sort Stdlib.compare lst) + @@ Array.of_list arr + in + Array.sort (fun xs ys -> Stdlib.compare xs ys) arr ; + let heuristics = Array.make (Array.length arr + 1) 0 in + for i = Array.length heuristics - 2 downto 0 do + let best = fst (List.hd arr.(i)) in + heuristics.(i) <- heuristics.(i + 1) + best + done ; + let best = ref 1000 in + let limit = ref 0 in + let rec go rem acc i = + incr limit ; + if !limit > 10_000 + then false + else if rem <= 0 + then begin + let score = acc + (1 * (Array.length arr - i)) in + best := min score !best ; + true + end + else if i >= Array.length arr + then begin + best := min !best (acc + (100 * rem)) ; + true + end + else if acc + heuristics.(i) >= !best + then true + else + let rec find = function + | [] -> true + | (cost, j) :: rest -> + let ok = + match j with + | None -> + go rem + (acc + cost + + if rem > Array.length arr - i then 100 else 0) + (i + 1) + | Some j -> + if used.(j) + then true + else begin + used.(j) <- true ; + let ok = go (rem - 1) (acc + cost) (i + 1) in + used.(j) <- false ; + ok + end + in + if ok then find rest else false + in + find arr.(i) + in + let _ = go (Array.length used) 0 0 in + !best + + let v query_type paths = + match paths, query_type with + | _, [] | [], _ -> 0 + | _ -> + let arr = + List.map + (fun p -> + let p = List.rev p in + List.map (fun q -> distance (List.rev q) p) query_type) + paths + in + minimize arr +end + +module Reasoning = struct + module Name_match = struct + type t = + | PrefixSuffix + | SubDot + | SubUnderscore + | Sub + | Lowercase + | Doc + + let is_substring ~sub s = + let re = Re.(compile (seq [ rep any; str sub ])) in + Re.execp re s + + let with_word query_word name = + if String.starts_with ~prefix:query_word name + || String.ends_with ~suffix:query_word name + then PrefixSuffix + else if is_substring ~sub:("(" ^ query_word) name + || is_substring ~sub:(query_word ^ ")") name + then PrefixSuffix + else if is_substring ~sub:("." ^ query_word) name + || is_substring ~sub:(query_word ^ ".") name + then SubDot + else if is_substring ~sub:("_" ^ query_word) name + || is_substring ~sub:(query_word ^ "_") name + then SubUnderscore + else if is_substring ~sub:query_word name + then Sub + else if String.lowercase_ascii query_word = String.lowercase_ascii name + then Lowercase + else (* Matches only in the docstring are always worse *) Doc + + let with_words query_words elt = + match elt.Elt.kind with + | Elt.Doc -> List.map (fun _ : t -> Doc) query_words + | _ -> List.map (fun word -> with_word word elt.Elt.name) query_words + + let compare nm nm' = + let to_int nm = + match nm with + | PrefixSuffix -> 0 + | SubDot -> 1 + | SubUnderscore -> 2 + | Sub -> 3 + | Lowercase -> 4 + | Doc -> 5 in - minimize arr + Int.compare (to_int nm) (to_int nm') + end + + type kind = + | Doc + | TypeDecl + | Module + | Exception + | Class_type + | Method + | Class + | TypeExtension + | ExtensionConstructor + | ModuleType + | Constructor + | Field + | FunctorParameter + | ModuleSubstitution + | ModuleTypeSubstitution + | InstanceVariable + | Val + + type t = + { is_stdlib : bool + ; has_doc : bool + ; name_matches : Name_match.t list + ; type_distance : int option + ; type_in_query : bool + ; type_in_elt : bool + ; kind : kind + } + + let type_distance query_type elt = + let open Elt in + match query_type, elt.kind with + | [], _ -> None + | ( _ + , ( Elt.Constructor { type_paths } + | Elt.Field { type_paths } + | Elt.Val { type_paths } ) ) -> + Some (Type_distance.v query_type type_paths) + | _ -> None + + let type_in_query query_type = query_type <> [] + + let type_in_elt elt = + let open Elt in + match elt.kind with + | Constructor _ | Field _ | Val _ -> true + | _ -> false + + let is_stdlib elt = + let open Elt in + String.starts_with ~prefix:"Stdlib." elt.name + + let has_doc elt = + let open Elt in + elt.doc.txt <> "" + + let kind elt = + match elt.Elt.kind with + | Elt.Doc -> Doc + | Elt.TypeDecl _ -> TypeDecl + | Elt.Module -> Module + | Elt.Exception -> Exception + | Elt.Class_type -> Class_type + | Elt.Method -> Method + | Elt.Class -> Class + | Elt.TypeExtension -> TypeExtension + | Elt.ExtensionConstructor -> ExtensionConstructor + | Elt.ModuleType -> ModuleType + | Elt.Constructor _ -> Constructor + | Elt.Field _ -> Field + | Elt.FunctorParameter -> FunctorParameter + | Elt.ModuleSubstitution -> ModuleSubstitution + | Elt.ModuleTypeSubstitution -> ModuleTypeSubstitution + | Elt.InstanceVariable -> InstanceVariable + | Elt.Val _ -> Val + + let v query_words query_type elt = + let is_stdlib = is_stdlib elt in + let has_doc = has_doc elt in + let name_matches = Name_match.with_words query_words elt in + let kind = kind elt in + let type_distance = type_distance query_type elt in + let type_in_elt = type_in_elt elt in + let type_in_query = type_in_query query_type in + { is_stdlib + ; has_doc + ; name_matches + ; type_distance + ; type_in_elt + ; type_in_query + ; kind + } + + let compare_is_stblib b1 b2 = if b1 && b2 then 0 else if b1 then -1 else 1 + let compare_has_doc b1 b2 = if b1 && b2 then 0 else if b1 then -1 else 1 + + let compare_kind k k' = + let to_int = function + | Val -> 0 + | Module -> 0 + | Doc -> 5 + | Constructor -> 1 + | Field -> 1 + | TypeDecl -> 1 + | ModuleType -> 2 + | Exception -> 3 + | Class_type -> 4 + | Class -> 4 + | TypeExtension -> 4 + | ExtensionConstructor -> 5 + | FunctorParameter -> 6 + | Method -> 5 + | ModuleSubstitution -> 5 + | ModuleTypeSubstitution -> 5 + | InstanceVariable -> 6 + in + Int.compare (to_int k) (to_int k') + + let score + { is_stdlib + ; has_doc + ; name_matches + ; type_distance + ; type_in_elt + ; type_in_query + ; kind + } = + let kind = + match kind with + | Val | Module -> 0 + | Constructor | Field | TypeDecl -> 10 + | ModuleType -> 20 + | Exception -> 30 + | Class_type | Class | TypeExtension -> 40 + | ExtensionConstructor | Method | ModuleSubstitution + | ModuleTypeSubstitution | Doc -> + 50 + | FunctorParameter | InstanceVariable -> 60 + in + let name_matches = + let open Name_match in + name_matches + |> List.map (function + | PrefixSuffix -> 0 + | SubDot -> 1 + | SubUnderscore -> 2 + | Sub -> 3 + | Lowercase -> 4 + | Doc -> 1000) + |> List.fold_left ( + ) 0 + in + let type_cost = + if type_in_elt && type_in_query + then Option.get type_distance + else if type_in_elt + then 0 + else + (* If query request a type, elements which do not have one are not to be + placed high. *) + 10000 + in + (if is_stdlib then 0 else 100) + + (if has_doc then 0 else 500) + + name_matches + type_cost + kind + + let compare r r' = Int.compare (score r) (score r') +end let list query_name query_type results = - let results = - List.map - (fun a -> - let open Elt in - let name_cost = score_name query_name a.name in - let type_cost = - match a.kind with - | Val { type_paths; _ } - | Constructor { type_paths; _ } - | Field { type_paths; _ } -> - score_type query_type type_paths - | Doc | TypeDecl _ | Module | Exception | Class_type | Method | Class - | TypeExtension | ExtensionConstructor | ModuleType | FunctorParameter - | ModuleSubstitution | ModuleTypeSubstitution | InstanceVariable -> - 0 - in - let cost = a.Elt.cost + (2 * name_cost) + (800 * type_cost) in - { a with cost }) - results - in - List.sort Elt.compare results + let open Reasoning in + let f = v query_name query_type in + List.sort_map ~f ~compare results diff --git a/lib/storage_js/storage_js.ml b/lib/storage_js/storage_js.ml index d8cc423b66..7c737603ec 100644 --- a/lib/storage_js/storage_js.ml +++ b/lib/storage_js/storage_js.ml @@ -6,7 +6,7 @@ let close_out = close_out let save ~db t = let str = Marshal.to_string t [] in let str = Base64.encode_string str in - Printf.fprintf db "sherlodb=%S;\n%!" str + Printf.fprintf db "function sherlodoc_db () { return %S; }\n%!" str let load str = let str = Base64.decode_exn str in diff --git a/test/cram/odoc.t/run.t b/test/cram/odoc.t/run.t index e26d4e464b..f3bd6695cf 100644 --- a/test/cram/odoc.t/run.t +++ b/test/cram/odoc.t/run.t @@ -3,17 +3,32 @@ $ odoc compile -I . page.mld $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc -$ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/**/*.odocl . + $ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . + $ ls + dream.odocl + main.cmi + main.cmo + main.cmt + main.ml + main.odoc + main.odocl + page-index.odocl + page-page.odoc + page-page.odocl + page.mld $ odoc compile-index --binary -I . -o index.odoc_bin $ du -sh index.odoc_bin - 4.0K index.odoc_bin + 488K index.odoc_bin $ sherlodoc_index --format=js --odoc=index.odoc_bin --db=db.js $ du -sh db.js - 12K db.js + 868K db.js $ odoc html-generate --with-search --output-dir html main.odocl + $ odoc html-generate --with-search --output-dir html dream.odocl $ odoc html-generate --with-search --output-dir html stdlib.odocl $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js + $ du -sh html/index.js + 1.1M html/index.js $ cp -r html /tmp $ firefox /tmp/html/Main/index.html From 0820ee8e5b98eb24901c195342dc2768321bc50d Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 15 May 2023 16:22:34 +0200 Subject: [PATCH 063/285] Take name length into account to sort results --- lib/query/sort.ml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/query/sort.ml b/lib/query/sort.ml index 2ea4201edc..a8439aa336 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -181,6 +181,7 @@ module Reasoning = struct type t = { is_stdlib : bool + ; name_length : int ; has_doc : bool ; name_matches : Name_match.t list ; type_distance : int option @@ -236,6 +237,8 @@ module Reasoning = struct | Elt.InstanceVariable -> InstanceVariable | Elt.Val _ -> Val + let name_length elt = String.length elt.Elt.name + let v query_words query_type elt = let is_stdlib = is_stdlib elt in let has_doc = has_doc elt in @@ -244,6 +247,7 @@ module Reasoning = struct let type_distance = type_distance query_type elt in let type_in_elt = type_in_elt elt in let type_in_query = type_in_query query_type in + let name_length = name_length elt in { is_stdlib ; has_doc ; name_matches @@ -251,6 +255,7 @@ module Reasoning = struct ; type_in_elt ; type_in_query ; kind + ; name_length } let compare_is_stblib b1 b2 = if b1 && b2 then 0 else if b1 then -1 else 1 @@ -286,11 +291,11 @@ module Reasoning = struct ; type_in_elt ; type_in_query ; kind + ; name_length } = let kind = match kind with - | Val | Module -> 0 - | Constructor | Field | TypeDecl -> 10 + | Val | Module | Constructor | Field | TypeDecl -> 0 | ModuleType -> 20 | Exception -> 30 | Class_type | Class | TypeExtension -> 40 @@ -323,7 +328,7 @@ module Reasoning = struct in (if is_stdlib then 0 else 100) + (if has_doc then 0 else 500) - + name_matches + type_cost + kind + + name_matches + type_cost + kind + name_length let compare r r' = Int.compare (score r) (score r') end From 88e8e7a5555d2065192b0dd12daf4cc908728df2 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 16 May 2023 15:45:03 +0200 Subject: [PATCH 064/285] add support to print typedecl (with a hack) --- bin/JSherlodoc/main.ml | 12 ++++++++++-- lib/db/elt.ml | 2 +- lib/index_lib/load_doc.ml | 17 ++++++++++------- lib/query/sort.ml | 6 +++--- test/cram/odoc.t/main.ml | 26 +++++++++++++++++--------- test/cram/odoc.t/run.t | 14 ++++++++------ 6 files changed, 49 insertions(+), 28 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 8748402821..19bcf5e8ac 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -1,5 +1,5 @@ -let db = lazy ( -Storage_js.load Jv.(to_string @@ call global "sherlodoc_db" [||])) +let db = + lazy (Storage_js.load Jv.(to_string @@ call global "sherlodoc_db" [||])) let string_of_kind (kind : Db.Elt.kind) = let open Db.Elt in @@ -45,6 +45,14 @@ let search query = match kind with | Val { type_; _ } | Constructor { type_; _ } | Field { type_; _ } -> Jv.(set o "type" (of_string type_.txt)) + | TypeDecl { type_decl } -> + (* TODO : remove this hack and switch to real typedecl render *) + let txt = type_decl.txt in + let txt = String.split_on_char '=' txt in + if List.length txt > 1 + then + let txt = txt |> List.tl |> String.concat "=" |> String.trim in + Jv.(set o "type" (of_string txt)) | _ -> ()) ; o) results diff --git a/lib/db/elt.ml b/lib/db/elt.ml index 2e29421b9e..02b88600a7 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -25,7 +25,7 @@ type type_path = string list list type kind = | Doc - | TypeDecl of { html : string } + | TypeDecl of { type_decl : displayable } | Module | Exception | Class_type diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 1facd27a70..30a5328587 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -1,3 +1,5 @@ + +module Elt = Db.Elt module Db_common = Db open Db.Caches @@ -131,7 +133,7 @@ module Make (Storage : Db.Storage.S) = struct let open Odoc_search in let html = type_ |> Render.html_of_type |> string_of_html in let txt = Render.text_of_type type_ in - Db_common.Elt.{ html; txt } + Elt.{ html; txt } let generic_cost ~ignore_no_doc full_name doc = String.length full_name @@ -139,7 +141,7 @@ module Make (Storage : Db.Storage.S) = struct + (if ignore_no_doc then 0 else - match Db_common.Elt.(doc.txt) with + match Elt.(doc.txt) with | "" -> 1000 | _ -> 0) + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 @@ -148,7 +150,6 @@ module Make (Storage : Db.Storage.S) = struct String.length (display_type_expr type_).txt + type_size type_ let kind_cost (kind : Odoc_search.Index_db.kind) = - let open Odoc_search in let open Odoc_search.Index_db in match kind with | Constructor { args; res } -> @@ -168,8 +169,10 @@ module Make (Storage : Db.Storage.S) = struct match kind with | TypeDecl typedecl -> let html = typedecl |> Render.html_of_typedecl |> string_of_html in - Db_common.Elt.TypeDecl { html } - | Module -> Db_common.Elt.ModuleType + let txt = Render.text_of_typedecl typedecl in + let type_decl = Elt.{ txt; html } in + Elt.TypeDecl { type_decl } + | Module -> Elt.ModuleType | Value { value = _; type_ } -> let paths = paths ~prefix:[] ~sgn:Pos type_ in let type_ = display_type_expr type_ in @@ -249,7 +252,7 @@ module Make (Storage : Db.Storage.S) = struct let doc = let html = doc |> Render.html_of_doc |> string_of_html and txt = Render.text_of_doc doc in - Db_common.Elt.{ html; txt } + Elt.{ html; txt } in let kind' = convert_kind kind in let ignore_no_doc = @@ -264,7 +267,7 @@ module Make (Storage : Db.Storage.S) = struct | _ -> full_name in let elt = - Db_common.Elt.{ name; url; kind = kind'; cost; doc; pkg = None } + Elt.{ name; url; kind = kind'; cost; doc; pkg = None } in register_doc elt doc.txt ; (match kind with diff --git a/lib/query/sort.ml b/lib/query/sort.ml index a8439aa336..f0bb19ada7 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -195,9 +195,9 @@ module Reasoning = struct match query_type, elt.kind with | [], _ -> None | ( _ - , ( Elt.Constructor { type_paths } - | Elt.Field { type_paths } - | Elt.Val { type_paths } ) ) -> + , ( Elt.Constructor { type_paths; _ } + | Elt.Field { type_paths; _ } + | Elt.Val { type_paths; _ } ) ) -> Some (Type_distance.v query_type type_paths) | _ -> None diff --git a/test/cram/odoc.t/main.ml b/test/cram/odoc.t/main.ml index 68e2d1a49a..c283b8a554 100644 --- a/test/cram/odoc.t/main.ml +++ b/test/cram/odoc.t/main.ml @@ -23,27 +23,35 @@ let v = 9 (** lorem 1 *) -let lorem = fun _ -> 'a' +let lorem _ = 'a' (** lorem 2 *) -let lorem2 = fun _ -> 'a' +let lorem2 _ = 'a' (** lorem 3 *) -let lorem3 = fun _ -> 'e' +let lorem3 _ = 'e' (** lorem 4 *) let lorem4 = 1 - type my_type = int * char type babar = | A of string - | B - | C of {z:int; w:char} - -type celeste = - {x : babar; y : int -> string} \ No newline at end of file + | B + | C of + { z : int + ; w : char + } + +type _ celeste = + { x : babar + ; y : int -> string + } + +type 'a list = + | Cons of 'a * 'a list + | Nil diff --git a/test/cram/odoc.t/run.t b/test/cram/odoc.t/run.t index f3bd6695cf..7de41ae2df 100644 --- a/test/cram/odoc.t/run.t +++ b/test/cram/odoc.t/run.t @@ -3,32 +3,34 @@ $ odoc compile -I . page.mld $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc - $ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . +$ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . $ ls - dream.odocl main.cmi main.cmo main.cmt main.ml main.odoc main.odocl - page-index.odocl page-page.odoc page-page.odocl page.mld $ odoc compile-index --binary -I . -o index.odoc_bin $ du -sh index.odoc_bin - 488K index.odoc_bin + 8.0K index.odoc_bin $ sherlodoc_index --format=js --odoc=index.odoc_bin --db=db.js $ du -sh db.js - 868K db.js + 20K db.js $ odoc html-generate --with-search --output-dir html main.odocl $ odoc html-generate --with-search --output-dir html dream.odocl + odoc: FILE.odocl argument: no 'dream.odocl' file or directory + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + [2] $ odoc html-generate --with-search --output-dir html stdlib.odocl $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js $ du -sh html/index.js - 1.1M html/index.js + 3.8M html/index.js $ cp -r html /tmp $ firefox /tmp/html/Main/index.html From e71ce7398deb89b716ca668cc0db70c40083c2c1 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 22 May 2023 09:09:21 +0200 Subject: [PATCH 065/285] Remove useless html from search results Co-authored-by: panglesd --- bin/JSherlodoc/main.ml | 11 +++++----- bin/www/ui.ml | 10 +++++----- lib/db/elt.ml | 8 ++++---- lib/index_lib/load_doc.ml | 42 ++++++++++++++++++++++++++------------- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 19bcf5e8ac..4aae52386c 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -44,14 +44,15 @@ let search query = Db.Elt.( match kind with | Val { type_; _ } | Constructor { type_; _ } | Field { type_; _ } -> - Jv.(set o "type" (of_string type_.txt)) + Jv.(set o "type" (of_string type_)) | TypeDecl { type_decl } -> (* TODO : remove this hack and switch to real typedecl render *) - let txt = type_decl.txt in - let txt = String.split_on_char '=' txt in - if List.length txt > 1 + let segments = String.split_on_char '=' type_decl in + if List.length segments > 1 then - let txt = txt |> List.tl |> String.concat "=" |> String.trim in + let txt = + segments |> List.tl |> String.concat "=" |> String.trim + in Jv.(set o "type" (of_string txt)) | _ -> ()) ; o) diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 278f8cd6bc..41d5caaa0f 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -18,14 +18,14 @@ let render_elt elt = [ txt "val " ; a ~a:link [ em [ txt elt.name ] ] ; txt " : " - ; txt type_.txt + ; txt type_ ] | Doc -> [ txt "comment "; a ~a:link [ em [ txt elt.name ] ] ] - | TypeDecl { html = type_decl } -> + | TypeDecl { type_decl } -> [ txt "type " ; a ~a:link [ em [ txt elt.name ] ] ; txt " = " - ; Unsafe.data type_decl + ; txt type_decl ] | Module -> [ txt "module "; a ~a:link [ em [ txt elt.name ] ] ] | Exception -> [ txt "exception "; a ~a:link [ em [ txt elt.name ] ] ] @@ -41,13 +41,13 @@ let render_elt elt = [ txt "constructor " ; a ~a:link [ em [ txt elt.name ] ] ; txt " : " - ; txt type_.txt + ; txt type_ ] | Field { type_; _ } -> [ txt "field " ; a ~a:link [ em [ txt elt.name ] ] ; txt " : " - ; txt type_.txt + ; txt type_ ] | FunctorParameter -> [ txt "functor param "; a ~a:link [ em [ txt elt.name ] ] ] diff --git a/lib/db/elt.ml b/lib/db/elt.ml index 02b88600a7..fb77462e0c 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -25,7 +25,7 @@ type type_path = string list list type kind = | Doc - | TypeDecl of { type_decl : displayable } + | TypeDecl of { type_decl : string } | Module | Exception | Class_type @@ -35,11 +35,11 @@ type kind = | ExtensionConstructor | ModuleType | Constructor of - { type_ : displayable + { type_ : string ; type_paths : type_path } | Field of - { type_ : displayable + { type_ : string ; type_paths : type_path } | FunctorParameter @@ -47,7 +47,7 @@ type kind = | ModuleTypeSubstitution | InstanceVariable | Val of - { type_ : displayable + { type_ : string ; type_paths : type_path } diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 30a5328587..ac5f54af36 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -1,4 +1,3 @@ - module Elt = Db.Elt module Db_common = Db open Db.Caches @@ -125,6 +124,22 @@ module Make (Storage : Db.Storage.S) = struct TypeExpr.Arrow (Some (Label field_name), field.type_, res)) res fields + let display_constructor_type args res = + let open Odoc_model.Lang in + match args with + | TypeDecl.Constructor.Tuple args -> + let type_ = + match args with + | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) + | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) + | _ -> res + in + Odoc_search.Render.text_of_type type_ + | TypeDecl.Constructor.Record fields -> + let fields = Odoc_search.Render.text_of_record fields in + let res = Odoc_search.Render.text_of_type res in + fields ^ " -> " ^ res + let searchable_type_of_record parent_type type_ = let open Odoc_model.Lang in TypeExpr.Arrow (None, parent_type, type_) @@ -168,24 +183,25 @@ module Make (Storage : Db.Storage.S) = struct let open Odoc_search.Index_db in match kind with | TypeDecl typedecl -> - let html = typedecl |> Render.html_of_typedecl |> string_of_html in - let txt = Render.text_of_typedecl typedecl in - let type_decl = Elt.{ txt; html } in + let type_decl = Render.text_of_typedecl typedecl in Elt.TypeDecl { type_decl } | Module -> Elt.ModuleType | Value { value = _; type_ } -> let paths = paths ~prefix:[] ~sgn:Pos type_ in - let type_ = display_type_expr type_ in + let type_ = Render.text_of_type type_ in Val { type_; type_paths = paths } | Constructor { args; res } -> - let type_ = searchable_type_of_constructor args res in - let type_paths = paths ~prefix:[] ~sgn:Pos type_ in - let type_ = display_type_expr type_ in + let searchable_type = searchable_type_of_constructor args res in + let type_paths = type_paths ~prefix:[] ~sgn:Pos searchable_type in + let type_ = display_constructor_type args res in Constructor { type_; type_paths } | Field { mutable_ = _; parent_type; type_ } -> - let type_ = searchable_type_of_record parent_type type_ in - let type_paths = paths ~prefix:[] ~sgn:Pos type_ in - let type_ = display_type_expr type_ in + let type_paths = + type_ + |> searchable_type_of_record parent_type + |> paths ~prefix:[] ~sgn:Pos + in + let type_ = (display_type_expr type_).txt in Field { type_; type_paths } | Doc _ -> Doc | Exception _ -> Exception @@ -266,9 +282,7 @@ module Make (Storage : Db.Storage.S) = struct | Doc _ -> Odoc_model.Paths.Identifier.prefixname id | _ -> full_name in - let elt = - Elt.{ name; url; kind = kind'; cost; doc; pkg = None } - in + let elt = Elt.{ name; url; kind = kind'; cost; doc; pkg = None } in register_doc elt doc.txt ; (match kind with | Doc _ -> () From a52a33710f74cfbe6332a7214d2977ac8c4e0245 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 22 May 2023 17:33:44 +0200 Subject: [PATCH 066/285] add tests --- test/cram/dune | 1 + test/cram/odig.t/run.t | 49 ++++++++++++++++++++++++++++++++++++++++++ test/cram/odoc.t/run.t | 9 ++++---- 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 test/cram/odig.t/run.t diff --git a/test/cram/dune b/test/cram/dune index bdad93487e..94c7c65a64 100644 --- a/test/cram/dune +++ b/test/cram/dune @@ -1,2 +1,3 @@ (cram + (alias runexamples) (deps %{bin:odoc} %{bin:sherlodoc_index} ../../bin/JSherlodoc/main.bc.js)) diff --git a/test/cram/odig.t/run.t b/test/cram/odig.t/run.t new file mode 100644 index 0000000000..7657a2c5ba --- /dev/null +++ b/test/cram/odig.t/run.t @@ -0,0 +1,49 @@ + $ git clone git@github.com:aantron/dream.git + Cloning into 'dream'... + $ cd dream + $ dune build @doc 2> /dev/null + [1] + $ pwd + $TESTCASE_ROOT/dream + $ cd .. + $ find . -name '*.odocl' + ./dream/_build/default/_doc/_odocls/playground/page-index.odocl + ./dream/_build/default/_doc/_odocls/dream-pure/page-index.odocl + ./dream/_build/default/_doc/_odocls/dream-pure/dream_pure.odocl + ./dream/_build/default/_doc/_odocls/hello/page-index.odocl + $ odoc compile-index --binary -I dream/_build/default/_doc/_odocls/playground -I dream/_build/default/_doc/_odocls/dream-pure -I dream/_build/default/_doc/_odocls/hello -o index.odoc_bin + $ sherlodoc_index --format=js --odoc=index.odoc_bin --db=db.js + $ du -sh db.js + 196K db.js + $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/playground/page-index.odocl + $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/dream-pure/page-index.odocl + $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/dream-pure/dream_pure.odocl + $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/hello/page-index.odocl + $ ls + db.js + dream + html + index.odoc_bin + $ ls dream/_build/default/_doc/_odocls/dream-pure + dream_pure.odocl + page-index.odocl + $ odoc support-files -o html + $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js + $ du -sh html/index.js + 4.0M html/index.js + $ ls html + dream-pure + fonts + hello + highlight.pack.js + index.js + katex.min.css + katex.min.js + odoc.css + odoc_search.js + playground + $ ls html/dream-pure + Dream_pure + index.html + $ cp -r html /tmp + $ xdg-open /tmp/html/dream-pure/index.html diff --git a/test/cram/odoc.t/run.t b/test/cram/odoc.t/run.t index 7de41ae2df..0e52485b65 100644 --- a/test/cram/odoc.t/run.t +++ b/test/cram/odoc.t/run.t @@ -19,13 +19,14 @@ $ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . 8.0K index.odoc_bin $ sherlodoc_index --format=js --odoc=index.odoc_bin --db=db.js $ du -sh db.js - 20K db.js + 16K db.js $ odoc html-generate --with-search --output-dir html main.odocl - $ odoc html-generate --with-search --output-dir html dream.odocl - odoc: FILE.odocl argument: no 'dream.odocl' file or directory + $ odoc html-generate -- $ odoc html-generate --with-search --output-dir html main.odocl + odoc: too many arguments, don't know what to do with 'odoc', 'html-generate', '--with-search', '--output-dir', 'html', 'main.odocl' Usage: odoc html-generate [OPTION]… FILE.odocl Try 'odoc html-generate --help' or 'odoc --help' for more information. [2] +-search --output-dir html dream.odocl $ odoc html-generate --with-search --output-dir html stdlib.odocl $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html @@ -33,4 +34,4 @@ $ odoc html-generate --with-search --output-dir html stdlib.odocl $ du -sh html/index.js 3.8M html/index.js $ cp -r html /tmp - $ firefox /tmp/html/Main/index.html + $ xdg-open /tmp/html/Main/index.html From a58f0d6762e18cc7fa5b7c62c9925ed957f21588 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 23 May 2023 17:59:56 +0200 Subject: [PATCH 067/285] Index now binds to odoc instead of having to call it first. Break www, so its disabled. Co-authored-by: panglesd --- bin/JSherlodoc/main.ml | 45 +++++----------------- bin/index/index.ml | 21 +++++++--- bin/www/{dune => _dune} | 0 bin/www/ui.ml | 8 ---- lib/db/elt.ml | 31 ++++++--------- lib/index_lib/index_lib.mli | 2 +- lib/index_lib/load_doc.ml | 67 ++++++++++++++------------------ lib/index_lib/load_doc.mli | 2 +- lib/index_lib/pretty.ml | 49 +++++++++++++++++++++++- lib/query/sort.ml | 22 +---------- test/cram/odig.t/run.t | 49 ------------------------ test/cram/odig/run.t | 76 +++++++++++++++++++++++++++++++++++++ test/cram/odoc.t/run.t | 19 +++------- 13 files changed, 197 insertions(+), 194 deletions(-) rename bin/www/{dune => _dune} (100%) delete mode 100644 test/cram/odig.t/run.t create mode 100644 test/cram/odig/run.t diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 4aae52386c..c2110f1f25 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -16,51 +16,24 @@ let string_of_kind (kind : Db.Elt.kind) = | ModuleType -> "module type" | Constructor _ -> "constructor" | Field _ -> "field" - | FunctorParameter -> "functor parameter" - | ModuleSubstitution -> "module subst" - | ModuleTypeSubstitution -> "module type subst" - | InstanceVariable -> "instance variable" | Val _ -> "val" -let search query = +let search message = + let query = Jv.get message "data" in let query = query |> Jv.to_jstr |> Jstr.to_string in let _pretty_query, results = Query.(api ~shards:(Lazy.force db) { query; packages = []; limit = 50 }) in - Jv.of_list - (fun Db.Elt.{ cost = _; name; url; kind; doc; pkg = _ } -> - let name = Jstr.of_string name in - let jkind = kind |> string_of_kind |> Jv.of_string in - let o = - Jv.( - obj - [| "name", of_jstr name - ; "prefixname", of_string "" - ; "kind", jkind - ; "comment", of_string doc.txt - ; "url", of_string url - |]) - in - Db.Elt.( - match kind with - | Val { type_; _ } | Constructor { type_; _ } | Field { type_; _ } -> - Jv.(set o "type" (of_string type_)) - | TypeDecl { type_decl } -> - (* TODO : remove this hack and switch to real typedecl render *) - let segments = String.split_on_char '=' type_decl in - if List.length segments > 1 - then - let txt = - segments |> List.tl |> String.concat "=" |> String.trim - in - Jv.(set o "type" (of_string txt)) - | _ -> ()) ; - o) - results + Jv.(apply (get global "postMessage")) + [| Jv.of_list + (fun Db.Elt.{ json_output; _ } -> + json_output |> Jstr.of_string |> Brr.Json.decode |> Result.get_ok) + results + |] let main () = let module J' = Jstr in let o = Jv.callback ~arity:1 search in - Jv.(set global "odoc_search" o) + Jv.(set global "onmessage" o) let _ = main () diff --git a/bin/index/index.ml b/bin/index/index.ml index bcb0acba18..c3dd355176 100644 --- a/bin/index/index.ml +++ b/bin/index/index.ml @@ -1,12 +1,21 @@ -let main index db_filename db_format = +let main files db_filename db_format = + let index = files |> List.map Fpath.of_string |> List.map Result.get_ok in let optimize, storage = match db_format with | `ancient -> true, (module Storage_ancient : Db.Storage.S) | `marshal -> false, (module Storage_marshal : Db.Storage.S) | `js -> false, (module Storage_js : Db.Storage.S) in - let channel = open_in index in - let index = Marshal.from_channel channel in + let add_entries li e = (Odoc_search.Entry.entries_of_item e) @ li in + let index = + index |> + List.fold_left (fun li file -> + file + |> Odoc_odoc.Indexing.handle_file + ~page:(Odoc_model.Fold.page ~f:add_entries li) + ~unit:(Odoc_model.Fold.unit ~f:add_entries li) + |> Result.get_ok |> Option.value ~default:[]) [] + in Index_lib.main ~index ~db_filename ~optimize storage open Cmdliner @@ -21,11 +30,11 @@ let db_filename = let doc = "Output filename" in Arg.(required & opt (some string) None & info [ "db" ] ~docv:"DB" ~doc) -let odoc_path = +let odoc_files = let doc = "Path to a binary odoc index" in - Arg.(required & opt (some file) None & info [ "odoc" ] ~docv:"ODOC_FILE" ~doc) + Arg.(non_empty & (pos_all file [] @@ info ~doc ~docv:"ODOC_FILE" [])) -let index = Term.(const main $ odoc_path $ db_filename $ db_format) +let index = Term.(const main $ odoc_files $ db_filename $ db_format) let cmd = let doc = "Index odocl files" in diff --git a/bin/www/dune b/bin/www/_dune similarity index 100% rename from bin/www/dune rename to bin/www/_dune diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 41d5caaa0f..54097d0e87 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -49,14 +49,6 @@ let render_elt elt = ; txt " : " ; txt type_ ] - | FunctorParameter -> - [ txt "functor param "; a ~a:link [ em [ txt elt.name ] ] ] - | ModuleSubstitution -> - [ txt "module subst "; a ~a:link [ em [ txt elt.name ] ] ] - | ModuleTypeSubstitution -> - [ txt "module type subst "; a ~a:link [ em [ txt elt.name ] ] ] - | InstanceVariable -> - [ txt "instance variable "; a ~a:link [ em [ txt elt.name ] ] ] let render_pkg elt = let open Db.Elt in diff --git a/lib/db/elt.ml b/lib/db/elt.ml index fb77462e0c..0e3fac9e59 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -42,10 +42,6 @@ type kind = { type_ : string ; type_paths : type_path } - | FunctorParameter - | ModuleSubstitution - | ModuleTypeSubstitution - | InstanceVariable | Val of { type_ : string ; type_paths : type_path @@ -58,29 +54,26 @@ type package = module T = struct type t = - { cost : int - ; name : string + { name : string ; kind : kind - ; doc : displayable + ; has_doc: bool ; pkg : package option - ; url : string + ; json_output : string } let compare_pkg { name; version = _ } (b : package) = String.compare name b.name let compare a b = - match Int.compare a.cost b.cost with - | 0 -> begin - match String.compare a.name b.name with - | 0 -> begin - match Option.compare compare_pkg a.pkg b.pkg with - | 0 -> Stdlib.compare a.kind b.kind - | c -> c - end - | c -> c - end - | c -> c + begin + match String.compare a.name b.name with + | 0 -> begin + match Option.compare compare_pkg a.pkg b.pkg with + | 0 -> Stdlib.compare a.kind b.kind + | c -> c + end + | c -> c + end let compare a b = if a == b then 0 else compare a b end diff --git a/lib/index_lib/index_lib.mli b/lib/index_lib/index_lib.mli index 6ca5713dcd..d307a4b2d2 100644 --- a/lib/index_lib/index_lib.mli +++ b/lib/index_lib/index_lib.mli @@ -1,5 +1,5 @@ val main : - index:Odoc_search.Index_db.index + index:Odoc_search.Entry.t list -> db_filename:string -> optimize:bool -> (module Db.Storage.S) diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index ac5f54af36..13eae11775 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -144,12 +144,6 @@ module Make (Storage : Db.Storage.S) = struct let open Odoc_model.Lang in TypeExpr.Arrow (None, parent_type, type_) - let display_type_expr type_ = - let open Odoc_search in - let html = type_ |> Render.html_of_type |> string_of_html in - let txt = Render.text_of_type type_ in - Elt.{ html; txt } - let generic_cost ~ignore_no_doc full_name doc = String.length full_name (* + (5 * List.length path) TODO : restore depth based ordering *) @@ -162,10 +156,10 @@ module Make (Storage : Db.Storage.S) = struct + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 let type_cost type_ = - String.length (display_type_expr type_).txt + type_size type_ + String.length (Odoc_search.Render.text_of_type type_) + type_size type_ - let kind_cost (kind : Odoc_search.Index_db.kind) = - let open Odoc_search.Index_db in + let kind_cost (kind : Odoc_search.Entry.extra) = + let open Odoc_search.Entry in match kind with | Constructor { args; res } -> type_cost (searchable_type_of_constructor args res) @@ -174,16 +168,15 @@ module Make (Storage : Db.Storage.S) = struct | Value { value = _; type_ } -> type_cost type_ | Doc _ -> 400 | TypeDecl _ | Module | Exception _ | Class_type _ | Method _ | Class _ - | TypeExtension _ | ExtensionConstructor _ | ModuleType | FunctorParameter - | ModuleSubstitution _ | ModuleTypeSubstitution | InstanceVariable _ -> + | TypeExtension _ | ExtensionConstructor _ | ModuleType -> 200 - let convert_kind (kind : Odoc_search.Index_db.kind) = + let convert_kind (kind : Odoc_search.Entry.extra) = let open Odoc_search in - let open Odoc_search.Index_db in + let open Odoc_search.Entry in match kind with | TypeDecl typedecl -> - let type_decl = Render.text_of_typedecl typedecl in + let type_decl = typedecl.txt in Elt.TypeDecl { type_decl } | Module -> Elt.ModuleType | Value { value = _; type_ } -> @@ -201,7 +194,7 @@ module Make (Storage : Db.Storage.S) = struct |> searchable_type_of_record parent_type |> paths ~prefix:[] ~sgn:Pos in - let type_ = (display_type_expr type_).txt in + let type_ = Render.text_of_type type_ in Field { type_; type_paths } | Doc _ -> Doc | Exception _ -> Exception @@ -211,10 +204,6 @@ module Make (Storage : Db.Storage.S) = struct | TypeExtension _ -> TypeExtension | ExtensionConstructor _ -> ExtensionConstructor | ModuleType -> ModuleType - | FunctorParameter -> FunctorParameter - | ModuleSubstitution _ -> ModuleSubstitution - | ModuleTypeSubstitution -> ModuleTypeSubstitution - | InstanceVariable _ -> InstanceVariable let register_type_expr elt type_ = let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in @@ -227,8 +216,8 @@ module Make (Storage : Db.Storage.S) = struct Cache_list.memo xs) type_paths) - let register_kind elt (kind : Odoc_search.Index_db.kind) = - let open Odoc_search.Index_db in + let register_kind elt (kind : Odoc_search.Entry.extra) = + let open Odoc_search.Entry in let open Odoc_model.Lang in match kind with | TypeDecl _ -> () @@ -248,46 +237,46 @@ module Make (Storage : Db.Storage.S) = struct | Field { mutable_ = _; parent_type; type_ } -> let type_ = TypeExpr.Arrow (None, parent_type, type_) in register_type_expr elt type_ - | FunctorParameter -> () - | ModuleSubstitution _ -> () - | ModuleTypeSubstitution -> () - | InstanceVariable _ -> () + let register_entry - Odoc_search.Index_db. + (Odoc_search.Entry. { id : Odoc_model.Paths.Identifier.Any.t ; doc : Odoc_model.Comment.docs - ; kind : kind - } = + ; extra : extra + } as entry) = let open Odoc_search in - let open Odoc_search.Index_db in + let open Odoc_search.Entry in let full_name = - id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." + id |> Pretty.fullname |> String.concat "." in - let url = Render.url id in let doc = let html = doc |> Render.html_of_doc |> string_of_html and txt = Render.text_of_doc doc in Elt.{ html; txt } in - let kind' = convert_kind kind in + let kind' = convert_kind extra in let ignore_no_doc = - match kind with + match extra with | Module | ModuleType -> true | _ -> false in - let cost = generic_cost ~ignore_no_doc full_name doc + kind_cost kind in + (* TODO : use entry cost *) + let _cost = generic_cost ~ignore_no_doc full_name doc + kind_cost extra in let name = - match kind with - | Doc _ -> Odoc_model.Paths.Identifier.prefixname id + match extra with + | Doc _ -> Pretty.prefixname id | _ -> full_name in - let elt = Elt.{ name; url; kind = kind'; cost; doc; pkg = None } in + let json_output = Json_output.string_of_entry entry in + let has_doc = doc.txt <> "" in + let elt = Elt.{ name; kind = kind'; pkg = None ; json_output ; has_doc} in + register_doc elt doc.txt ; - (match kind with + (match extra with | Doc _ -> () | _ -> register_full_name full_name elt) ; - register_kind elt kind + register_kind elt extra module Resolver = Odoc_odoc.Resolver diff --git a/lib/index_lib/load_doc.mli b/lib/index_lib/load_doc.mli index 3eb3bfc507..747e710d65 100644 --- a/lib/index_lib/load_doc.mli +++ b/lib/index_lib/load_doc.mli @@ -2,5 +2,5 @@ module Make (Storage : Db.Storage.S) : sig module Db : Db.S with type writer = Storage.writer val clear : unit -> unit - val run : index:Odoc_search.Index_db.t list -> unit + val run : index:Odoc_search.Entry.t list -> unit end diff --git a/lib/index_lib/pretty.ml b/lib/index_lib/pretty.ml index 32cd310a58..64d87780c0 100644 --- a/lib/index_lib/pretty.ml +++ b/lib/index_lib/pretty.ml @@ -61,12 +61,59 @@ and show_signature h sig_ = | `ModuleType (_, p) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) +let rec full_name_aux : Paths.Identifier.t -> string list = + let open Names in + let open Paths.Identifier in + fun x -> + match x.iv with + | `Root (_, name) -> [ ModuleName.to_string name ] + | `Page (_, name) -> [ PageName.to_string name ] + | `LeafPage (_, name) -> [ PageName.to_string name ] + | `Module (parent, name) -> + ModuleName.to_string name :: full_name_aux (parent :> t) + | `Parameter (parent, name) -> + ModuleName.to_string name :: full_name_aux (parent :> t) + | `Result x -> full_name_aux (x :> t) + | `ModuleType (parent, name) -> + ModuleTypeName.to_string name :: full_name_aux (parent :> t) + | `Type (parent, name) -> + TypeName.to_string name :: full_name_aux (parent :> t) + | `CoreType name -> [ TypeName.to_string name ] + | `Constructor (parent, name) -> + ConstructorName.to_string name :: full_name_aux (parent :> t) + | `Field (parent, name) -> + FieldName.to_string name :: full_name_aux (parent :> t) + | `Extension (parent, name) -> + ExtensionName.to_string name :: full_name_aux (parent :> t) + | `Exception (parent, name) -> + ExceptionName.to_string name :: full_name_aux (parent :> t) + | `CoreException name -> [ ExceptionName.to_string name ] + | `Value (parent, name) -> + ValueName.to_string name :: full_name_aux (parent :> t) + | `Class (parent, name) -> + ClassName.to_string name :: full_name_aux (parent :> t) + | `ClassType (parent, name) -> + ClassTypeName.to_string name :: full_name_aux (parent :> t) + | `Method (parent, name) -> + MethodName.to_string name :: full_name_aux (parent :> t) + | `InstanceVariable (parent, name) -> + InstanceVariableName.to_string name :: full_name_aux (parent :> t) + | `Label (parent, name) -> + LabelName.to_string name :: full_name_aux (parent :> t) + +let fullname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string list = + fun n -> List.rev @@ full_name_aux (n :> Paths.Identifier.t) + + let prefixname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string = + fun n -> + match full_name_aux (n :> Paths.Identifier.t) with [] -> "" | _ :: q -> String.concat "." q + let show_type_name_verbose h : Paths.Path.Type.t -> _ = function | `Resolved t -> let open Paths.Path in Format.fprintf h "%a" show_ident_long (Resolved.identifier (t :> Resolved.t)) | `Identifier (path, _hidden) -> - let name = Paths.Identifier.(fullname (path :> t)) |> String.concat "." in + let name = fullname (path :> Paths.Identifier.t) |> String.concat "." in Format.fprintf h "%s" name | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x diff --git a/lib/query/sort.ml b/lib/query/sort.ml index f0bb19ada7..e6aee2a85d 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -173,10 +173,6 @@ module Reasoning = struct | ModuleType | Constructor | Field - | FunctorParameter - | ModuleSubstitution - | ModuleTypeSubstitution - | InstanceVariable | Val type t = @@ -213,9 +209,6 @@ module Reasoning = struct let open Elt in String.starts_with ~prefix:"Stdlib." elt.name - let has_doc elt = - let open Elt in - elt.doc.txt <> "" let kind elt = match elt.Elt.kind with @@ -231,17 +224,13 @@ module Reasoning = struct | Elt.ModuleType -> ModuleType | Elt.Constructor _ -> Constructor | Elt.Field _ -> Field - | Elt.FunctorParameter -> FunctorParameter - | Elt.ModuleSubstitution -> ModuleSubstitution - | Elt.ModuleTypeSubstitution -> ModuleTypeSubstitution - | Elt.InstanceVariable -> InstanceVariable | Elt.Val _ -> Val let name_length elt = String.length elt.Elt.name let v query_words query_type elt = let is_stdlib = is_stdlib elt in - let has_doc = has_doc elt in + let has_doc = elt.Elt.has_doc in let name_matches = Name_match.with_words query_words elt in let kind = kind elt in let type_distance = type_distance query_type elt in @@ -275,11 +264,7 @@ module Reasoning = struct | Class -> 4 | TypeExtension -> 4 | ExtensionConstructor -> 5 - | FunctorParameter -> 6 | Method -> 5 - | ModuleSubstitution -> 5 - | ModuleTypeSubstitution -> 5 - | InstanceVariable -> 6 in Int.compare (to_int k) (to_int k') @@ -299,10 +284,7 @@ module Reasoning = struct | ModuleType -> 20 | Exception -> 30 | Class_type | Class | TypeExtension -> 40 - | ExtensionConstructor | Method | ModuleSubstitution - | ModuleTypeSubstitution | Doc -> - 50 - | FunctorParameter | InstanceVariable -> 60 + | ExtensionConstructor | Method | Doc -> 50 in let name_matches = let open Name_match in diff --git a/test/cram/odig.t/run.t b/test/cram/odig.t/run.t deleted file mode 100644 index 7657a2c5ba..0000000000 --- a/test/cram/odig.t/run.t +++ /dev/null @@ -1,49 +0,0 @@ - $ git clone git@github.com:aantron/dream.git - Cloning into 'dream'... - $ cd dream - $ dune build @doc 2> /dev/null - [1] - $ pwd - $TESTCASE_ROOT/dream - $ cd .. - $ find . -name '*.odocl' - ./dream/_build/default/_doc/_odocls/playground/page-index.odocl - ./dream/_build/default/_doc/_odocls/dream-pure/page-index.odocl - ./dream/_build/default/_doc/_odocls/dream-pure/dream_pure.odocl - ./dream/_build/default/_doc/_odocls/hello/page-index.odocl - $ odoc compile-index --binary -I dream/_build/default/_doc/_odocls/playground -I dream/_build/default/_doc/_odocls/dream-pure -I dream/_build/default/_doc/_odocls/hello -o index.odoc_bin - $ sherlodoc_index --format=js --odoc=index.odoc_bin --db=db.js - $ du -sh db.js - 196K db.js - $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/playground/page-index.odocl - $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/dream-pure/page-index.odocl - $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/dream-pure/dream_pure.odocl - $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/hello/page-index.odocl - $ ls - db.js - dream - html - index.odoc_bin - $ ls dream/_build/default/_doc/_odocls/dream-pure - dream_pure.odocl - page-index.odocl - $ odoc support-files -o html - $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js - $ du -sh html/index.js - 4.0M html/index.js - $ ls html - dream-pure - fonts - hello - highlight.pack.js - index.js - katex.min.css - katex.min.js - odoc.css - odoc_search.js - playground - $ ls html/dream-pure - Dream_pure - index.html - $ cp -r html /tmp - $ xdg-open /tmp/html/dream-pure/index.html diff --git a/test/cram/odig/run.t b/test/cram/odig/run.t new file mode 100644 index 0000000000..fa4c6af794 --- /dev/null +++ b/test/cram/odig/run.t @@ -0,0 +1,76 @@ + $ git clone git@github.com:aantron/dream.git + $ cd dream + cd: dream: No such file or directory + [1] + $ dune build @doc 2> /dev/null + $ pwd + $TESTCASE_ROOT + $ cd .. + $ find . -name '*.odocl' + $ odoc compile-index --binary -I dream/_build/default/_doc/_odocls/playground -I dream/_build/default/_doc/_odocls/dream-pure -I dream/_build/default/_doc/_odocls/hello -o index.odoc_bin + odoc: unknown option '--binary'. + Usage: odoc compile-index [OPTION]… + Try 'odoc compile-index --help' or 'odoc --help' for more information. + [2] + $ sherlodoc_index --format=js --odoc=index.odoc_bin --db=db.js + index: option '--odoc': no 'index.odoc_bin' file or directory + Usage: index [--db=DB] [--format=DB_FORMAT] [--odoc=ODOC_FILE] [OPTION]… + Try 'index --help' for more information. + [124] + $ du -sh db.js + du: cannot access 'db.js': No such file or directory + [1] + $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/playground/page-index.odocl + odoc: FILE.odocl argument: no + 'dream/_build/default/_doc/_odocls/playground/page-index.odocl' file or + directory + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + [2] + $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/dream-pure/page-index.odocl + odoc: FILE.odocl argument: no + 'dream/_build/default/_doc/_odocls/dream-pure/page-index.odocl' file or + directory + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + [2] + $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/dream-pure/dream_pure.odocl + odoc: FILE.odocl argument: no + 'dream/_build/default/_doc/_odocls/dream-pure/dream_pure.odocl' file or + directory + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + [2] + $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/hello/page-index.odocl + odoc: FILE.odocl argument: no + 'dream/_build/default/_doc/_odocls/hello/page-index.odocl' file or + directory + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + [2] + $ ls + html + odig + $ ls dream/_build/default/_doc/_odocls/dream-pure + ls: cannot access 'dream/_build/default/_doc/_odocls/dream-pure': No such file or directory + [2] + $ odoc support-files -o html + $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js + cat: db.js: No such file or directory + cat: ../../../bin/JSherlodoc/main.bc.js: No such file or directory + [1] + $ du -sh html/index.js + 0 html/index.js + $ ls html + fonts + highlight.pack.js + index.js + katex.min.css + katex.min.js + odoc.css + odoc_search.js + $ ls html/dream-pure + ls: cannot access 'html/dream-pure': No such file or directory + [2] + $ cp -r html /tmp + $ xdg-open /tmp/html/dream-pure/index.html diff --git a/test/cram/odoc.t/run.t b/test/cram/odoc.t/run.t index 0e52485b65..2cf1253c94 100644 --- a/test/cram/odoc.t/run.t +++ b/test/cram/odoc.t/run.t @@ -14,24 +14,15 @@ $ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . page-page.odoc page-page.odocl page.mld - $ odoc compile-index --binary -I . -o index.odoc_bin - $ du -sh index.odoc_bin - 8.0K index.odoc_bin - $ sherlodoc_index --format=js --odoc=index.odoc_bin --db=db.js + $ sherlodoc_index --format=js --db=db.js *.odocl $ du -sh db.js - 16K db.js + 20K db.js $ odoc html-generate --with-search --output-dir html main.odocl - $ odoc html-generate -- $ odoc html-generate --with-search --output-dir html main.odocl - odoc: too many arguments, don't know what to do with 'odoc', 'html-generate', '--with-search', '--output-dir', 'html', 'main.odocl' - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - [2] --search --output-dir html dream.odocl -$ odoc html-generate --with-search --output-dir html stdlib.odocl $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js $ du -sh html/index.js - 3.8M html/index.js + 4.0M html/index.js $ cp -r html /tmp - $ xdg-open /tmp/html/Main/index.html + $ firefox /tmp/html/Main/index.html + From d665c8b6262df91f6501656f64b5a601997aeb6b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 24 May 2023 12:28:35 +0200 Subject: [PATCH 068/285] Compatibilty with odoc 89175b19aeae7e181fd46ce6f74b643367713cfb --- bin/JSherlodoc/main.ml | 4 ++-- lib/db/elt.ml | 2 +- lib/index_lib/load_doc.ml | 4 ++-- test/cram/odoc.t/run.t | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index c2110f1f25..b784e285e4 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -26,8 +26,8 @@ let search message = in Jv.(apply (get global "postMessage")) [| Jv.of_list - (fun Db.Elt.{ json_output; _ } -> - json_output |> Jstr.of_string |> Brr.Json.decode |> Result.get_ok) + (fun Db.Elt.{ json_display; _ } -> + json_display |> Jstr.of_string |> Brr.Json.decode |> Result.get_ok) results |] diff --git a/lib/db/elt.ml b/lib/db/elt.ml index 0e3fac9e59..94177d9575 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -58,7 +58,7 @@ module T = struct ; kind : kind ; has_doc: bool ; pkg : package option - ; json_output : string + ; json_display : string } let compare_pkg { name; version = _ } (b : package) = diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 13eae11775..4e9686e79b 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -268,9 +268,9 @@ module Make (Storage : Db.Storage.S) = struct | Doc _ -> Pretty.prefixname id | _ -> full_name in - let json_output = Json_output.string_of_entry entry in + let json_display = entry |> Json_display.of_entry |> Odoc_html.Json.to_string in let has_doc = doc.txt <> "" in - let elt = Elt.{ name; kind = kind'; pkg = None ; json_output ; has_doc} in + let elt = Elt.{ name; kind = kind'; pkg = None ; json_display ; has_doc} in register_doc elt doc.txt ; (match extra with diff --git a/test/cram/odoc.t/run.t b/test/cram/odoc.t/run.t index 2cf1253c94..975d8e8820 100644 --- a/test/cram/odoc.t/run.t +++ b/test/cram/odoc.t/run.t @@ -16,7 +16,7 @@ $ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . page.mld $ sherlodoc_index --format=js --db=db.js *.odocl $ du -sh db.js - 20K db.js + 16K db.js $ odoc html-generate --with-search --output-dir html main.odocl $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html From 3fafe4a86932a6e80aaf2e3640d26ac4178d7e1f Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 26 May 2023 16:03:20 +0200 Subject: [PATCH 069/285] add size options and size tests --- .vscode/settings.json | 6 ++ bin/JSherlodoc/main.ml | 2 +- bin/index/index.ml | 48 ++++++++--- bin/www/ui.ml | 12 +-- lib/db/db.ml | 2 +- lib/db/elt.ml | 2 +- lib/index_lib/index_lib.ml | 5 +- lib/index_lib/index_lib.mli | 6 +- lib/index_lib/load_doc.ml | 81 ++++++++++-------- lib/index_lib/load_doc.mli | 9 +- lib/index_lib/pretty.ml | 8 +- .../cram/base.t/base_internalhash_types.odocl | Bin 0 -> 3353 bytes test/cram/base.t/caml.odocl | Bin 0 -> 32790 bytes test/cram/base.t/md5_lib.odocl | Bin 0 -> 2391 bytes test/cram/base.t/page-index.odocl | Bin 0 -> 39593 bytes test/cram/base.t/run.t | 28 ++++++ test/cram/base.t/shadow_stdlib.odocl | Bin 0 -> 81028 bytes test/cram/odig/run.t | 76 ---------------- test/cram/{odoc.t => simple.t}/main.ml | 0 test/cram/{odoc.t => simple.t}/page.mld | 0 test/cram/{odoc.t => simple.t}/run.t | 0 21 files changed, 141 insertions(+), 144 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 test/cram/base.t/base_internalhash_types.odocl create mode 100644 test/cram/base.t/caml.odocl create mode 100644 test/cram/base.t/md5_lib.odocl create mode 100644 test/cram/base.t/page-index.odocl create mode 100644 test/cram/base.t/run.t create mode 100644 test/cram/base.t/shadow_stdlib.odocl delete mode 100644 test/cram/odig/run.t rename test/cram/{odoc.t => simple.t}/main.ml (100%) rename test/cram/{odoc.t => simple.t}/page.mld (100%) rename test/cram/{odoc.t => simple.t}/run.t (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..f042043f47 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "ocaml.sandbox": { + "kind": "opam", + "switch": "sherlodoc" + } +} \ No newline at end of file diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index b784e285e4..d6baa03336 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -27,7 +27,7 @@ let search message = Jv.(apply (get global "postMessage")) [| Jv.of_list (fun Db.Elt.{ json_display; _ } -> - json_display |> Jstr.of_string |> Brr.Json.decode |> Result.get_ok) + json_display |> Jstr.of_string |> Brr.Json.decode |> Result.get_ok) results |] diff --git a/bin/index/index.ml b/bin/index/index.ml index c3dd355176..490ae4ec1f 100644 --- a/bin/index/index.ml +++ b/bin/index/index.ml @@ -1,4 +1,5 @@ -let main files db_filename db_format = +let main files index_docstring index_name type_search empty_payload db_filename + db_format = let index = files |> List.map Fpath.of_string |> List.map Result.get_ok in let optimize, storage = match db_format with @@ -6,20 +7,42 @@ let main files db_filename db_format = | `marshal -> false, (module Storage_marshal : Db.Storage.S) | `js -> false, (module Storage_js : Db.Storage.S) in - let add_entries li e = (Odoc_search.Entry.entries_of_item e) @ li in + let add_entries li e = Odoc_search.Entry.entries_of_item e @ li in let index = - index |> - List.fold_left (fun li file -> - file - |> Odoc_odoc.Indexing.handle_file - ~page:(Odoc_model.Fold.page ~f:add_entries li) - ~unit:(Odoc_model.Fold.unit ~f:add_entries li) - |> Result.get_ok |> Option.value ~default:[]) [] + index + |> List.fold_left + (fun li file -> + file + |> Odoc_odoc.Indexing.handle_file + ~page:(Odoc_model.Fold.page ~f:add_entries li) + ~unit:(Odoc_model.Fold.unit ~f:add_entries li) + |> Result.get_ok |> Option.value ~default:[]) + [] in - Index_lib.main ~index ~db_filename ~optimize storage + Index_lib.main ~index_docstring ~index_name ~type_search ~empty_payload ~index + ~db_filename ~optimize storage open Cmdliner +let index_docstring = + let doc = "Use the docstring to index the results." in + Arg.(value & opt bool true & info ~doc [ "index-docstring" ]) + +let index_name = + let doc = "Use the name to index the results." in + Arg.(value & opt bool true & info ~doc [ "index-name" ]) + +let type_search = + let doc = "Enable type based search" in + Arg.(value & opt bool true & info ~doc [ "type-search" ]) + +let empty_payload = + let doc = + "Dont put anything in the payloads. For testing purposes, will break the \ + UI." + in + Arg.(value & flag & info ~doc [ "empty-payload" ]) + let db_format = let doc = "Database format" in let kind = Arg.enum [ "ancient", `ancient; "marshal", `marshal; "js", `js ] in @@ -34,7 +57,10 @@ let odoc_files = let doc = "Path to a binary odoc index" in Arg.(non_empty & (pos_all file [] @@ info ~doc ~docv:"ODOC_FILE" [])) -let index = Term.(const main $ odoc_files $ db_filename $ db_format) +let index = + Term.( + const main $ odoc_files $ index_docstring $ index_name $ type_search + $ empty_payload $ db_filename $ db_format) let cmd = let doc = "Index odocl files" in diff --git a/bin/www/ui.ml b/bin/www/ui.ml index 54097d0e87..4704ce8854 100644 --- a/bin/www/ui.ml +++ b/bin/www/ui.ml @@ -15,11 +15,7 @@ let render_elt elt = let link = render_link elt in match elt.kind with | Val { type_; _ } -> - [ txt "val " - ; a ~a:link [ em [ txt elt.name ] ] - ; txt " : " - ; txt type_ - ] + [ txt "val "; a ~a:link [ em [ txt elt.name ] ]; txt " : "; txt type_ ] | Doc -> [ txt "comment "; a ~a:link [ em [ txt elt.name ] ] ] | TypeDecl { type_decl } -> [ txt "type " @@ -44,11 +40,7 @@ let render_elt elt = ; txt type_ ] | Field { type_; _ } -> - [ txt "field " - ; a ~a:link [ em [ txt elt.name ] ] - ; txt " : " - ; txt type_ - ] + [ txt "field "; a ~a:link [ em [ txt elt.name ] ]; txt " : "; txt type_ ] let render_pkg elt = let open Db.Elt in diff --git a/lib/db/db.ml b/lib/db/db.ml index d711e32da5..428ace2b2f 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -134,7 +134,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let ho = Hocc.create 16 in let hs = Hset.create 16 in List.iter - (fun (path, count) -> store ~ho ~hs ~count path elt) + (fun (path, count) -> store ~ho ~hs ~count (Cache_list.memo path) elt) (regroup_chars paths) let store_chars name elt = diff --git a/lib/db/elt.ml b/lib/db/elt.ml index 94177d9575..d5f6cf98b7 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -56,7 +56,7 @@ module T = struct type t = { name : string ; kind : kind - ; has_doc: bool + ; has_doc : bool ; pkg : package option ; json_display : string } diff --git a/lib/index_lib/index_lib.ml b/lib/index_lib/index_lib.ml index 4edb299cfc..f4e72d42a3 100644 --- a/lib/index_lib/index_lib.ml +++ b/lib/index_lib/index_lib.ml @@ -1,6 +1,7 @@ module Storage = Db.Storage -let main ~index ~db_filename ~optimize storage = +let main ~index_docstring ~index_name ~type_search ~empty_payload ~index + ~db_filename ~optimize storage = let module Storage = (val storage : Storage.S) in let module Load_doc = Load_doc.Make (Storage) in let module Db = Load_doc.Db in @@ -10,6 +11,6 @@ let main ~index ~db_filename ~optimize storage = Load_doc.clear () ; Db.export h in - Load_doc.run ~index ; + Load_doc.run ~index_docstring ~index_name ~type_search ~empty_payload ~index ; flush () ; Storage.close_out h diff --git a/lib/index_lib/index_lib.mli b/lib/index_lib/index_lib.mli index d307a4b2d2..43778502ba 100644 --- a/lib/index_lib/index_lib.mli +++ b/lib/index_lib/index_lib.mli @@ -1,5 +1,9 @@ val main : - index:Odoc_search.Entry.t list + index_docstring:bool + -> index_name:bool + -> type_search:bool + -> empty_payload:bool + -> index:Odoc_search.Entry.t list -> db_filename:string -> optimize:bool -> (module Db.Storage.S) diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 4e9686e79b..97be9b3beb 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -216,40 +216,39 @@ module Make (Storage : Db.Storage.S) = struct Cache_list.memo xs) type_paths) - let register_kind elt (kind : Odoc_search.Entry.extra) = + let register_kind ~type_search elt (kind : Odoc_search.Entry.extra) = let open Odoc_search.Entry in let open Odoc_model.Lang in - match kind with - | TypeDecl _ -> () - | Module -> () - | Value { value = _; type_ } -> register_type_expr elt type_ - | Doc _ -> () - | Exception _ -> () - | Class_type _ -> () - | Method _ -> () - | Class _ -> () - | TypeExtension _ -> () - | ExtensionConstructor _ -> () - | ModuleType -> () - | Constructor { args; res } -> - let type_ = searchable_type_of_constructor args res in - register_type_expr elt type_ - | Field { mutable_ = _; parent_type; type_ } -> - let type_ = TypeExpr.Arrow (None, parent_type, type_) in - register_type_expr elt type_ - + if type_search + then + match kind with + | TypeDecl _ -> () + | Module -> () + | Value { value = _; type_ } -> register_type_expr elt type_ + | Doc _ -> () + | Exception _ -> () + | Class_type _ -> () + | Method _ -> () + | Class _ -> () + | TypeExtension _ -> () + | ExtensionConstructor _ -> () + | ModuleType -> () + | Constructor { args; res } -> + let type_ = searchable_type_of_constructor args res in + register_type_expr elt type_ + | Field { mutable_ = _; parent_type; type_ } -> + let type_ = TypeExpr.Arrow (None, parent_type, type_) in + register_type_expr elt type_ - let register_entry + let register_entry ~empty_payload ~index_name ~type_search ~index_docstring (Odoc_search.Entry. - { id : Odoc_model.Paths.Identifier.Any.t - ; doc : Odoc_model.Comment.docs - ; extra : extra - } as entry) = + { id : Odoc_model.Paths.Identifier.Any.t + ; doc : Odoc_model.Comment.docs + ; extra : extra + } as entry) = let open Odoc_search in let open Odoc_search.Entry in - let full_name = - id |> Pretty.fullname |> String.concat "." - in + let full_name = id |> Pretty.fullname |> String.concat "." in let doc = let html = doc |> Render.html_of_doc |> string_of_html and txt = Render.text_of_doc doc in @@ -268,17 +267,25 @@ module Make (Storage : Db.Storage.S) = struct | Doc _ -> Pretty.prefixname id | _ -> full_name in - let json_display = entry |> Json_display.of_entry |> Odoc_html.Json.to_string in + let json_display = + if empty_payload + then "" + else entry |> Json_display.of_entry |> Odoc_html.Json.to_string + in let has_doc = doc.txt <> "" in - let elt = Elt.{ name; kind = kind'; pkg = None ; json_display ; has_doc} in - - register_doc elt doc.txt ; - (match extra with - | Doc _ -> () - | _ -> register_full_name full_name elt) ; - register_kind elt extra + let elt = Elt.{ name; kind = kind'; pkg = None; json_display; has_doc } in + if index_docstring then register_doc elt doc.txt ; + (if index_name + then + match extra with + | Doc _ -> () + | _ -> register_full_name full_name elt) ; + register_kind ~type_search elt extra module Resolver = Odoc_odoc.Resolver - let run ~index = List.iter register_entry index + let run ~index_docstring ~index_name ~type_search ~empty_payload ~index = + List.iter + (register_entry ~index_docstring ~index_name ~type_search ~empty_payload) + index end diff --git a/lib/index_lib/load_doc.mli b/lib/index_lib/load_doc.mli index 747e710d65..3ceec4f905 100644 --- a/lib/index_lib/load_doc.mli +++ b/lib/index_lib/load_doc.mli @@ -2,5 +2,12 @@ module Make (Storage : Db.Storage.S) : sig module Db : Db.S with type writer = Storage.writer val clear : unit -> unit - val run : index:Odoc_search.Entry.t list -> unit + + val run : + index_docstring:bool + -> index_name:bool + -> type_search:bool + -> empty_payload:bool + -> index:Odoc_search.Entry.t list + -> unit end diff --git a/lib/index_lib/pretty.ml b/lib/index_lib/pretty.ml index 64d87780c0..8ddc4100f4 100644 --- a/lib/index_lib/pretty.ml +++ b/lib/index_lib/pretty.ml @@ -104,9 +104,11 @@ let rec full_name_aux : Paths.Identifier.t -> string list = let fullname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string list = fun n -> List.rev @@ full_name_aux (n :> Paths.Identifier.t) - let prefixname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string = - fun n -> - match full_name_aux (n :> Paths.Identifier.t) with [] -> "" | _ :: q -> String.concat "." q +let prefixname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string = + fun n -> + match full_name_aux (n :> Paths.Identifier.t) with + | [] -> "" + | _ :: q -> String.concat "." q let show_type_name_verbose h : Paths.Path.Type.t -> _ = function | `Resolved t -> diff --git a/test/cram/base.t/base_internalhash_types.odocl b/test/cram/base.t/base_internalhash_types.odocl new file mode 100644 index 0000000000000000000000000000000000000000..61d01f3f946cb0fb80b6d114c142d3aa0b10dfd1 GIT binary patch literal 3353 zcmcguU2GIp6rLGpunRS4umLp)rQQB_cS)f|tUC9$rBF;Ml+sd+!|d*~U6}1GJJZ%; zg$I2=v~(AQ#Nfjv0Spn7Mu;)N05NDZ^3Vi>KPh5V4DwPRFlr#+xpTKOOn=hG2a~;< z{l5L?ob#P~?%g$_Mx@;D-%_`!dEJIazyFQHC(m;nw;R@@u%3riF+5C!%6(5_l7bH_ zOXnCw&JU}mCM>!A`P&5vg?>&~VR%{6`$gk}mkHyc`gOOwhp-v=_! z6H$~yMFoq0ToyhsurIsm@U6E723a-Pog63Z=eVrPuvU_TB#Yxh-2YINYg~LJEoRN$ z%Dl-|M4pgUHELWRZ_yef8CNanN-ScgLPJB5y0-oUzh+&pZaUF?G>4FaW-F@4!l_XI z@b6bX{_Ebzo->zA&K-FwEvJTk#cqRxW-=0_TQEiQ199CK2zD89EvUs~x)y9o8auRz zWd@B1lwv;?RKh(mJsON^9cqtmg)aWNyR71mp<@r-3Gw%Hw!DfUA2}ia1pTi1`RN~s zSf2KqmTGB2(J)RD<&bWqJsN}x_hlK?=F&iarC zQ%6O8ltFPvGys60Bn#y4F=O4GRQ5XMkm<`q1wT^6*V3_O%CMqxz>aHH!`!AHl>mA)q00eJfy8Q7C9-|a)a#Xhg5ZugEc^yWQ z=Db50ym?$C@f;w6+cL4@hDj|*{KJ&PTU}i?AcDh8SDffcCJa+E%WUxi`UQ@-;zfW6 z&dgSx+D!*u;+IegJJTic`G5$9@uKI)Z)v(t`z-OLl*G=2Nqh(p!HJ9&HaikuMJc?? zO9o0TH~1Y4fcvmHCDa?jd-utApn3h1&*C$i282No8+Ralxe6=h7wik4vwr_h>@S%iG(1<(A@7|1D20 z&GYUEn7njjY$K8QuhQj_qz28fiw7@dbFW<-UZE7|(PS;{Pz!X)EO{~&sF{`5Jra6{rF$>|D8i~K-wNRQawOedjN%(;j zf~})-eSu7u88;gf&rQ>47GbgrVcv8u3NnS{?3XIa*ra5Fczp;9y*}#Gfljzl+_Nk! z3Y>z!S-pyvo{byd(#dwbQKoQI=$#euJy}NfD@9T%NoYJYG9nZ4piEN7B%!57w&5lQ zx2*vs5#tOgb+U|Wh&ae#q!zUF**b=I)XNkF7&6wvqnL>2ksa8?vJ8)oFw}>r6w)y` L02dXit&{%+Zw5=$ literal 0 HcmV?d00001 diff --git a/test/cram/base.t/caml.odocl b/test/cram/base.t/caml.odocl new file mode 100644 index 0000000000000000000000000000000000000000..90cc8dd703172b2b220f93ef0f03e964715727bb GIT binary patch literal 32790 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 literal 0 HcmV?d00001 diff --git a/test/cram/base.t/page-index.odocl b/test/cram/base.t/page-index.odocl new file mode 100644 index 0000000000000000000000000000000000000000..894f6c4b95e62971f2de4d4539f4f4876b3f848e GIT binary patch literal 39593 zcmbuo2V7jowLgAYSb7(|F0eF7$i3S!5<)T(G7W80q{mgK zKNy&aciG*lc-8UWd}H^G_uiU& z!L4ndOEZ^wxXy8!4>``!R>zs!ukQQt|J#M$otArFTH3N}DfR9v)~!1)`TvKGLr#$E1aN>=)deiuAM>_GZ=ljRMq0*|%V_v2nJaTDFKjyk6&xUiS<*W5w zYW-&Ax#GEwU;8&;Fggh?Rb8E`Yf^b$KKI|(tK>O5*3Co$iO~2+ED(&uMlSGp-tod) zvwX3U#qdfOYDmjfT`}c(W^C_8%CqKA?|6c))2h0l;<-) zc=k?Q^U^!2HvDg5yIDrU*bO40v+Gjd7MrWwc z7y(^3B>TibsIG|V(;iI356=XGF@0wL+omwy_Fo}gp zZK}IdZ9cM8R&Q7=s|!8Vw^YBdOjZ}JB&+)&tL}|_Z5mg4n1=}J?oQs}84#+QHHRPg zECJouCHuS?gzD}wXKD!0Y2HP2_m*Ur_k&Q~{iaLX%xqvP97u$z=SKv31n% zM+A0@Abtu$b&s2qHTKL>pBD(|jwa9bdl0JoAV0%&B7P_uj%W?|E5Y4~WY3pCsO}ll zQxAwYC6$2gS=+~(k_k$6FYxJHL*h*-AiVpy^eq9Ux}8qbxoIXsH|R~N)>yZ*UV8cf zt;f-2x;Dl~b#W=VJQ#y(!lcylJMEnT{l&L6d>0S<`);6c0zV&Ge?cta>`tHrVt<4$kW-TWmEi@}z&E z@2X{1^P&~3rq`1Vv)QxB+*HfpR4h87mDW>8XwT;4U3p4Dsh(cG{rD`*JKesghQOX} z(y;-Q>KQa0-Nw=DX(PO6m-OubrFw=;R>D;^w5rA9y{x3F(=Zv*AXjRnMI1)jS!& zywax&6WDV|Iz~aM9(Xm^*F4R4CvY9Ijx}{XQQ0-^?)|w=r$K`An)e&D2;59+3a~j zZRu27*ax;B9*@H`2DH=ndfrZqElFqS^}Gj^+QI@~lZZ^m0-=bVeVz{yYl}y`EnZyhY5Z=eMBL7Hdw!(V5vqG&l$ItMB4Z#M&a})bn>xYRgS#Q2mFav*Xk+ z)gf%liRAF7dO@iz&IZ%bK2>V2#P$r)=wsjX~E+e7im z>1ZsHprF8;>L1}2QFO&uU`tIXWgJ)qQ9 z4olj@(a}+ak!HT79w5fnWMJY=jet^HSxl{=@pv@E=Zz7(RYa7EA0AU%mw3F?BLr;~ zkC#f6+G^)VYd9X6nQAr9bgRaDT~fMJ^>(UWJ4+Igj>r*me0uQjBSx>xlGF!5sa_j1 zjz$8ra|yoLGlciLMDRE$)yttt(m|!ZnXq1oOH$tfO7(L5-o)`n>iY@mO-AtE)DMGF zz3d*FrsC!fKS5BhxW&|`L8)GzOXBQPpCzzYCQ|BGL8;y;Bl1PQKK0v#_r^u=KLDkA z*_rug=0av_{FJa>i62vc1xocEVl^@rEcN$<^d6S8{TY<%Wz*^JIj_$sZ*Gt5GFETeQG)t* z$Y|UIO7(I2%ZZXV?KXn?lIgEE?JiKNkNrohj<#C0TTHv3;6CvoX|DyP`Zz!B2#p7( zrXsNpsSN7s9*xhLm_6-F1opX9|7)OBAN!)ls5bIx-yx(= zJW<*YL8-o_o+#~S8r$yD`CqH;P%n6EE_UepM)S_ua5V0zN+_Rx^gpTX+tqg1tA?L_ z>T1L6)Qtb4pKceo?sY(=eay(Xja{%&WN*6a?^OM`5?6-Sw0At6tPFX*^%o~1vA}FJ zJ~cBQo$i>8cZA}Jh-cjo(|(@S5*t~Gxsq;sSE>Fk)z2PtZNKZBbjRK*;`NKu^wxt? z{nlxk$?R<*q+cwycMT}jZ!LBg?o1DW_d+$$sRm(sFFbi2WKwkeKT4Fo&XsCl1FX@K zS?k@gc-CIxX}InecP*Q>m#p|?-Dx>$0QO{2waV+=ss_5%0A}B^a+TNX?=-hLKtCL~ z-pHllN_~g>2pH%~s=fCBC^fLlbZXreor+EdV!G=X!2?6mH3muza9rOqGaH7eb z2PCZb9s#8Wc=D}v1&=z0@tz>wfXqGbt)SEZ`;)fqt~}FwH{k=~Q@rZ1lV)79AU(JshD{_dlz71FkUI`({8Jaj=PRvZsER#sklatnksP*$Aq(<~}}3_~2H#k57P7gX|DEd+>gakiqMv*R!D1Ae%`x7v8TEGALHk z`)yEakoB=;91mkMckhn~9h4Zt`%_S9?`5H)ZiCw1x=vP$U#p=`wFlL!rP}*PHMD~E zre`hI-b+30TQB&_GVQ%|MeY3uw0CHk_NJ$*p>8!K+NwdO|C^XR8T zi}W|Wgn%K@-}FjQYKRk$_UCK?j5QkQrrKGPVWJn^b^b0_# zAr5|qjm29z2aHN))RhTGTuHWD^8mXvOK4=6PhGyNn6OW#i5kYuju zgP_z9$4l)TPMYdaI&SHZ8j`Rn9rtor4cV~C<|pangbj)BNXHo$)KD_#oV2$&tHIr( z*Xc*q?hR@;*A4tsqtMUuO2T$a)gb*gP--{pznv%PCkfgus-J#8D7BkK(-DqL(=?e1 zA{;!1Xc8TYcpw#Y3Bc7JXp?K_&dGOB@x_e3l`6WiSawNY&*lzLu>E8jR zcC%>O4$ehG6S1S(_ND)r@ZB!){0x-ZZ3ESIYy8X*{YG>4xMcJPwP%CclMHK(`Ah#B zL3<>HO#cTcwP!1<+~Ig)LJv|#8i9LylaG{<1xoGVN!Dm4PDUXidt{bnl!Ef6tTCrs zvn6mSFcV5dr)RBE$*5NQI@LZzPb>QQjEl2Y&&@=q#yXJmcf>;|ad+5iat8+t9i+iJ zK=ZV{qUnXKt79Yo|9`TQ@yTdY`?}OVu3k0|()CH7GtMJ$pOh{$E(WFcaVTpO_>8Lv z+9$DW1|D#m+Q&hIVp+xr z!TZ7@sxT!L%;SIQ zhj%P9@RzMP#;-zBF>I3xUZC-2+)3E5Bo!H_K&fGyJn1zlZ^na!3`_Eq@h~Vg%wDj~ z?N>7%Cwy3ZVaAi7)G!y38%=7N@eV?UrG}jGUQlY7t5~KmmhoW%hNX6u@f0XE%*#1` zUVHOqJWbeeaxur7@eC+6%y!2W|73iX&|$GW8P9=I!8%&Zq=rVu=QJlQof z9h4fj=|Xd0bk~u-rVnAIu*zj<^mszQy{gPT_)~WrSYCn{WvWE6JY`)K` zMP@TG_VYYz&=xLpEdl#wmStW5O6|89W56t@n9`z2${ z>;a|rbIjVt>p|wqINz|^FHvhII__8dxm416C=i=tPnCHC!TY6Hk{JM{_OnNCnLRpf zdyW&jUtD_TBq+6?McW*i4Xra*pCxd=NH_B+D7BxXmsLD7D`f zCPx$TNiu7hCkfjx>0svlpwxaVUu)MgU#GGCZt1=OP!|qsE0gOOnddY*;u7#%)JUfq z;hu|(Tjsk79}&Zv`2kRBgk|YAZkhi|@Q6#Ep9G~wc%~-H4w;`PY(yq&=9fUJkv&Gg zo8nX2Q)hmIppm_zuipWsMuMhW+Z3&v@iJHDj|m?MN#CD=QX^c(^p8bm_592H4Phfv z#mxKzC^f=a4JYB5ea+%D3fKnqo_wAr(r4cj|PhK=D3zQn+P_H!{84X~fk{q)N z2_BI^FRK)k8nJR*vt%VKt48xiT=L9n0MvzpLpfXh%4*Zt0g+}_hdR*dP5Gc1r!|Pt z5|K~1#L z#o%OZ0i}XgA>)a#u}xV!2n>pjW$gl`f*k2^f|WH)NKnF@tRN^AWZ#X|NtBeel(V9Q z2E}=2O@UHDj#`^xSjQc)pj40@d=nOtwB9^HP*9@Ptha(vL9V(dHSs+J z1*P7e^+8Z7c+6Pr78HRvt${*-h^@rxWX0Xc=Xv6U#871Y9Fz))p@?Yfm-So1LSiVg{s>Bitf62( zlJ$3jLSiVgUIwK??9^Ll#}o0nFa+7;UTdC*^Qu7$QIJ40+U*l+3kddWh}GTfl^_FDDHwC%PLv1%f4KN zcc?HPnS3vEbtx$OTKaLABT`ce%HBjkSVGb4t)NtR!u-6$D8jm(SR^xXb9O&5!|e2o z`_A4&Kv?`;_I^;X7?|F46BqGWrg4(l5n6ELb47HYu+=3#8%_lz?5fISA0*P7@(MQi z>(&{|lzmu@cB(N{{1zLg>?OhM6`raq?)&62!*s<;hAEqZ*->6^<&9e2>^lh>mF3p# zQ=rr+$FfaRk;7WF4-zyg!EE-!pwuXrB;7kvvL7dSRH~8LPl8gT9Lw5#I{O_2jY=?^ z{a#RNl;hME6QAg7f0)owiBz+n0;NWIZOA_vFo}Hj(}ay4NKWYNXF#b@HaP9b>Y~_A zXI6x>zeGr*wUPY;LPlNk{|P8H%0?%-NT2;H!bZjFWd9D78s!4H zbx_%VCTR4K+~JF$)Tk|9tj0FWIa-7^)wY}z%^H)5l9R5+pcdCBCyH$2^Jf2u1}mpP zjrFK8)TAgj_v`&^8ZX1o(jGIg+0W+9sZr5R6-6GuVpf}TN!Dd{EffBvBN#!2F*2od z*bY=L{+DFebIpgx-k8-B8~MNd{YvVa)2^ajDvD>PCtI_TS6O-SH0OL`MJ1=txdfDo z+R88AydH|H364tTH)lO46=n006l%_Oghj=I;a{soby^k znxmnpYp3MfIWYpGqM11dL8&Om*o#8aoFjxsCCtt_4oXGg?P!o}NUDuw z&aG;qQ%zzud9g{!Idk6PO{M31F5df#o3k30ZZA365ow zyG?RFLfC|aGC3ayr6yRu97E-NmXHaTbiW8nO<3u2%9Zmqf+k$j{T3*N4M%!}U1Iwo zffM2=bN(Hany`-2)`Ro||C;a#ag;g#0ZL8SaG6U+y6ayEo{(@k=f6Oy35by-+%hvB zpTquS%=}yrp%bz%AU6Y)ny`VjKM@I-j`GR^GvnnR_hukqxDrV~sE~}C|MQ}{&54kg-RLt6TYX@?VX)Na23zd5U(0UwPXlj~0 ztmj4Ut2H+164c#l5_6bWuiK5Dpx~_U^#Ni`Zb>?q+=oD^Nj8|toHO@P!Y0L1=AH$m zCOLVq;d|~|37VA5A@^ON)FeloZpHf`p_3AH=6)2En&d(^FZbkrijYaEbLV~zl$vCL zHU|##R*>8;6FBLT<<~(egpOK7ysVM?T|y>hy5;@|l$zx9)qi+Aq8CYWe@@t>B(S+J zfKrnz@b(#$Wkcf}w&nhj7?Un>{}q&)QVdB%(9%sSebV5`o!xV#d?{(YT`J;gy&x+2Fh~74K4U z_W7&3lIJ9~$g3qzTo&W<8bPTzPd6%Inai3xZdV68RRYs{v6IMKzr;yg;8}hCo4&Bz zNnEhv4PF8#ad1iGnRgXI2PN{%>jb3^vc9gCr`M0MnK%bUYx8Uoy0gO z9w3h>bveaYGk5wA?(#NTOIPf#5pFZ zettG6b&PYJB{MC*h&ab2=gBVvrH;iH+28zHLXJt1Kfe)_I>x!aoe}x%1Ra}AI;H$| zpwuzs96CV7#`D>zsS4y@Lh!ukWd4<))I8gRb=YQsazBzIy`P4Joxh&A^I{Y7H-S>~ zI~L#RHbUn6}OG$Ell}eC1hblZt^)$YJrV4oW7Zv`9C0RLCkgjPe7@KCFVN+R|GAHxz7I` zD7C=zf)Wb-x`hrVA zspBldwr~_h@>#R>rr;XFkBbxwHh@yc*>p^)_?q)5Mh^Sydo#<4~ z1~|IK2D%`Vx{Sv!&!Uv8jR-27Q^00#O5+!Gm<#sM8Y7mN~eLTc^>6QItN}na@gv7iBUj(I2upPJNzTj&FIh`&w{1%ZoP`=>e zu5;0gQN=Hv>SBxD6m`*d2|76P)uy)Kr}*&=I8bxbCD#@D=@_Np1$`B#Q>q~azXvpf z!`4I00;#t31%K7J)9IRmF9D+4x07(dyuneJsxhZireR?wpc6Rk8kBp9tFXW@ob@se zg(V6k4mPMu6s53Qvz+x}SPOlCw&LI%dU1$b*s3|sddZ^;*8&>E!HHL^Yt9#5q;Y4x zqT`7A=UL!99DU`czo<;c8@&v*VKyy!S$8 zs_b!!LD9Y606OSRc^$hFlB8K8Dg2{yHezhMVbm7; zlA`P-zT^_ms$1SSu-uodxFxypW%v?jqm>xjfTA>wIU7Y{MOlC#v5j2L#9L&@VGzjk zX4#@b&2u(NVY8?d5N60m_Mc6M13E=0s?nIUQCw(I1E2vMHu5(iP*IzPoQ)#bq7Fb1 z>_!fjS~-&qx3>r*3XZc;Bv#Z-Bn~SvI)5y3 zM4ulj2;A8y5-Zw4Bn}Rb{Ncc?er2y{w+5Y!5*!u5{%kyi!&b?XnTx4u6@?8C9o8pR zqKNJV^)fUpB+iP8=th8{aY+ew05mo1`MHc!v|uo&Tjp!g&Cn;(DJy+md@i~}V@|j0 zy!QaYY3+;o)&&-w)|ewN=X;A@59m4^Ho}@gyciudGqp%*hSM!ER?!oHFpBgFKDoR_ z0)4y29eE4iTl5}4`*3jfv3hiFN>^KFw4*EfkY+jZs=c@9V}M3+*feC5sg4$XMq^I5 zBqBv$0CZ#8x6Jfwk4{m|H54&rfg)If%^0rDxbot{K+!LjOuqg`=fwfOd{g9zyL8Y=Vz?*xS-9p>{7y8e63(1&iz zT4z2b^FMW3smxkDkBdSt?OS}wIIZ{=4LYtj`HF7`1e>&t!wtKdS$s-k&Nc}(iV@gs zgPq@Im+f%RS}YH1%-JUXtr&65Hu$$~9J3}j*%v>lL1&wUtHlUvwhiLo_;a<4fR5*j z->V$FCFt}a@LxQqiQxCMaoCz+a+B+-qZ)N~NY!xFO@OA; zSg*JQdQ~Up9Vx(V%IU{I^do>hr#aWFx{Vq|w84yI#|38Z2U7G3iyF~GRKoCVgXG8w+z>MA(x9X!BbowO` zTJ;G)kWD{N7%PO&X~^k!O_XN=VWRZ2xMam=)z>xZ^t&YXZ9tG%KMb5MhMO%j+bO=+}SA`7)$a1?ZUxAlc6dp z(WtXiq*YQ02-4cgg)`Uguo9n!ot;uVD`^G<3$~M|nVrQYYc=NVl=)S10iZE&O1`=0 zjv4wK0_xKAp!VgTlFO7c2&=Ulnz(pAl=Lkb;fp+N-S0cRe1unARVwMC`7n5$xpdog z@x$0iX}(xd0(%37GuV@~!6g{lL4w)AG@7qgl)%aWat6i2l)%ai_TsS9+x0<+5~wk7 zXHZ;62~5l&T*shw9a9mr{j3B=2B0%2uA>A-W)QApkW)?BKU@MM1JoImM6(1&25%8N zgFJ1L!9WQN3_xd4CQiv+MB3>L4NWP0%0)+ zZBfVy=aU9=c1em^@>vBEhYdh%P*L(F4LZAIL9yg(fVy$8jx=!qQ1Ts(IlEly@k2mR zk6l(h%qv4BKhu!2%cUN_1_brk#Z%ivDkXo=h_lNzq5lF1TDOZ!;Ud3(XwcauRq#>| zAn4UDHcxAz$&}$H*Xl~MG}GC2AUSNM`G5}K;1tC_i{)H0E~TX!baqLSQd$Klf`cQA zmhhb2Yg^i&VP{uN&fEehhJz)(HcVTTT+%jQp!1eq zp&@72f}H&ofEI9A4QWoke^^Sw0*pq~qjZa=sbQJ(%N3OoeAaPh-!l>(dQfX9!&XDW8Q-E+*4QLR@kU2Zg#?pH<p1Jb8^TtrYoC{KRf8LD&)cIx;k;v?M(D@Ow!lrfOVf>VgF%M3Qi}kpM9oMV8 zrB4FdjDsJ#nZ8FiqtlDhcL3hzO~FbO4F_+DEq$MI_Tuz=;lLN$`qD2hvGo^wN^TAO zb-Aryae=Dz<7DgiT3bJa-AQEZ^%Fg<8O~mr%%#r&!erjdx7~C!KBv2WRb$RxmzH+7doYsMDF!A85?kD`ln9p8$f&?PUjzwMeshuk=?MboPpOF8v)KXyRUW3RYwP ztRZKwxP;Od0qw!Ts}8mfR+geMXRoX{l%)fL8t>%_M$({^d-6W~ZzP=YCfuuBY|tc^vdBEA`@-AH_NI6D@ZwZsVb&qn`FRDp*{WM%Ej3F2lW zSaDyhP-RQDR9$$fr{vgk70YjSS&2-am$pLY1I3Y<-%l-riVh`~WLNh)wFssd4*?(!&3CS8lxdZ4Bj-xE} zV04Uzt~^6yPUu*2oXas~LU3#$E-_kFDqp2BCnWMNhmi?E-XX+wT9=R@>aXQ`%j*pa zmh3Gk_Y>Gf4JJA{6!w7SYYgUuML){VS0Hh4*Jj$8t;5T5q#8h-u;~3A}$Er2}{scju{_R!F8z3hvAz=9tB5`o0)`E}h z+4G*zuoISKt^8I%bU9lLF)2{_-5PSjl3JJF2k1r|Y%~0^czi;S*h3n0!eTVa&j5N$q8g#<5qCjs3G>gNAejVd;_+o7bm8yA%R{6UO+ljaY{(d+ByoY+Xxq_MA zItnTOh;qiD3geLOV)sz~wI#mnGEd{Ng=dz#hZPqt%0El)Va&RRJtlrAe^z78n7D`X zuL9bLgEtDg8FIb&kZ$`MkGK{LmAKVJK2JQj-|wp#F#<~U=rC$9p5#n@gPtX<70>CH@&a4Rx3 z>WqnkRUon$gMy9O9K#y4iV_VvW0GT3R04|N7~>gizC%{w(~vVJ`@|}m0gdC}oeO@% zXF8UvSgS#2OtvmmTmWbi2MU|o(cE<2y2xYzFF?{AU#=O>m@I=-TmuNxVvM)+`A6|_ zOx>5Hw1DGyQXMPctH+MxIKg*p)`%-;I5B<3TpJfEFnvK&W0Qq(d^=m8_y&VIxP#&|Ut3Fj zn%+9W_TfNctUcT3Ycp>;CA%fCi3A-RZ@7Wo{|z?`H@5qxqA`8wUuE;9@Wt=B=?)q+ zeCx+VgM3wAn?AR>1^u7nGadN80d`_y!x7?0jZvi7)&`C~1(F=fMrS(cMFoPO@Ev%I zm#*7R{c*FlFW`1y*{EK_5hfzORyqaV{5jm7-4+PrMZ7q^GBYy^e5OOME#oudbmbYG z5x71Zol*a*sbLOSeQt?qhJ8|&75c?(iice|GnU{?r6`un%go90M zZwl{y&m^1G(y?+G+(`z?8<1Kl-p%KMus4izzysTM{Yu|HaDxhf`9O`qp zRhg|JXI>)x$^t+zL-V{?jQ52nv?Z%7)1Wgi#<#K>5RC6UZye(~US*?(oO#(bR@n+@ z9*4sg5^FiAkWWQ1sp%mr*BPF(AV#(FA_Wo$hm`i7uhfvUAmL=?wSW-ZEpP_WLLc~q zZ=w@J9|1cHl0H;I$*?KgS+MDY{$Pvl+^XFK3z9xm zhKR($I}}>xro;GnhCcC)8g>?Be?ny(5MoEWXWMEe1spePQG=X3<6Bj(Ce8g&*VpsRchAi5cw1>z&v`ko)wn6u#0jmH2% zHx{gJz|Comt9(*}&Voxf-UbM|v0xqZ;b=^kD=XitL1#f6bLGDPf@8*3ZT*1!4qW9^ z8gdp~j=A#Fz{oK#*xgKaMpr&#KyV~ptNaRq2n7~wd5~vy<#Psej=L1@doY%WJM9w7 zOq^CV^jJKv9NLI|0=1wO_b61pc!A!dfOv^KQ-c1^gs0*!yS8UF@x}xrA3*1XgqD>r5{ZLNCB6?tm!&(cO3|=$qAzKKtI`4W;o!`rS>K(0 zuBtqh;@sSc<`zV$i=9MO^I|7)(fOWBzHouF%t>6d;zDv&C7cA#Z37}?-3dJvs_G34 zo`ghIegZd9!&BHgimEjR1V?6Y)%gT&p@xHNQ}nI6%s{{;xURaIz+P%>c+GnVs=5pa zj!gKf>j>OV4Z95Y==K>LOz|640|X9H!~VdGuolNY1A`|{q3QsE!_@FvkLwR)RE-%N zOj+-#iV+y5hNEq3E~;h>2#y5YRYwRMr^bfdHjuA6VNkFn=&rhzz)5O&c}V|_Cj9_+ z8x$;ABC5KNzyvj14@Pm+yh~E`kU_yZEE;%*z{AwAr$~zTtO3ChXHoTL0_Ul*le{f5 zg;+IYN@w2W!^FECzBPxKI0 z_LgivsZIrcJ58UvV6GNFZgusN$Gy;V;jgdx$nwWsaUH$7KtJy7951%^;gfM}+Nw+G zqBQGom#DG2O4HQXxRI0R>IMUXBet-*g+Q9cw`1vr5=_@8j;cEh4yG)?R9{HoZfbZH zx5c~`L9?U!3WI|w3%S*=AaH~luH192ubPAf42@LotMvl~35*yS*ub}XhXKJEO-`li zT?CF&!_K`8`3`DaW`(wztO_`2#KTwXv&RYK3SkQtX*r#(jv5?HDH2xeGaMogukYy( z-|7&edd|S$$s%9%F#;E;VIOV{RQ1gU1jpsZt6xnh{5Z8%wUb+Ls_$Vu#koTk2CE+c zddCK8xH#|n>SFcl4GyL(3{^i$U=KAs8>}RrFc=sz6{_D#AUTRV*i*L6j0eIrwp!Nj zF&wa^)K~pM0tcz#r5{@)t^Sw+!I9OU>Q524hZ?s0tIfy9qWqnm>Ms}`I*9eJ{xX4K zY9@?|xW743{Y}FFHzsQGT>{B#+!1H3veV*u1A-$JA0ZA%V3Igr^vh}8|a-R^E<7~ z;Rk~F5)5WvO_9OD6q(nQ5lAw>(=N-)amC-)+^A`4 zIP%8_+&G@A(S6Cc-zmX=4VjKRDGIrhUk+=*>M55AYK|KmOnF1B<`x1eIJwjMd@Q|9 z8r8UyVYnNYYMcUk*9IvQ)2A=72}xmbatF2I zHl&)zwS&4Fu_S5AYW}3zrnr&+o9MdaU+$KWvgYlYrUp(&?-4fhL zl>Qusw(&LJG90jFWwGY_1Wr)HuE)MVS@Z7(1V_A1%`XWguXDFuDzM)$toaXvf+dRu zHGd*-mKs(v`!;0_g(3jah>F!Znx=+Iv@6J>HiMZd&Ph?5+FYO~$)cR(C89N`X~v?V zC>GeX?W$d6nCKx3MYR4yG_rr7 z_IyoKV|Ngk+H~z@1_ML9NG)YFCuweVF;hvLR2){@QxMkBgWd!44K;TWT3JV5L7 zG*xOzTY;mIFr$`onv)b}oaCYdS6^!P84L`mH`E>=knGG!HYupRPDUn!X3It`r8MB6 z5t~v=&go==8deXJ!_`tk0|<@iMlG3=lcXCb;h#ud{Zy&dw@)?$C>rrjwYO@T8oNKq z{8`CbN@swfk>I8FK21|&ZBMJ24Mx5XF$c!PrAL(0+(UYF4<`?eCIhNHYcMb*b*QD3 z=ALe9*pJ!xsPTo7)w40@c2t&Fv}9=bHG{tJ*)%1<6mIl45i1Uo=e(hkO1Rb|JO@ zFeq3O@YQ(;?4^dQd+rZ2)@2z6xKiV*%O{W~$0?qu$;`K|)SzI=RIRHbkf!P>4is$W zTi0Mfa3oTwYax&#g;O?C2;#3sk)GF4asm{MnDM#`HBF6;6wE4I-4zA{Ln4K`R}e@u z{S;4XtAur=nE=tqtgfTX7Q*7^L({bGn1A`|PzitK@QEHAq`Iezf~7>t1hgFj*h#W3Itm^Dp^+G*?hBfx#>OC$`PNYY0UV9^nYwRkni?n=4MeMX1@U}+M-)GR zfySj|&uf|*E>+pT_f_{x1A-%!syfO=?wzEDy#{?7ebW4)in>1;987T?b$=(2T*tk< zjio*L!YAETJ;f1Vp^@z@^Wqv9`*{T4zG_6hDB0Mr>96C7Py&ZO@`_mDE!d z0S+25K=tc2P0a{vzA-5E*BK0q1IaA2ej9-YsF^hKUPJGPxxNxyPo@$~G*j}kJ({Lw znlECaoqBz$X<{6d-Vsex!^OttWVBNsGcb5kZLB{?Acc$fv6W~GVaw1g$2;{DD}aN> zWhm-N0|4lDy}2thH|i;txX+=1x!)!4J2g!Wm#W%A(S-gZnp&$UqyPtv)T-(q)HF3* zTBc8|n?HkNLeF{%D!@b|^RWJLO;cm%VfT?xWLk$m^=~#fm@*IR-$CFAH9_+zc2d>9 z-+gMU9y!`A5ROe8j{vxoX;4Fg=6hxK12 zkmlk2Z0ehne-E*qVhg}%#MsyWK-1J<@Ry}c^*?1!it~U=EWZN!08PUOxT<9RZT;^J z2#%CX>;Ft3g%JR&P-II`~GOCgY?`oIppBQCy?%zc@L0d9X%dwqEXQi}cn z7nL}W_LUe63@Io1DhV8f%3BL*joEurvv5F95<}#p}(#*n|z_f_b6SH^4HT6K=>$C zIZXk?Y1U^>QhjeV7#J>9rcC8Dsq$&wA%RckBnwBr4;luzQYZ6Ko^qP%WT$ygt&KQ+ zpE4jgvY*yRiOOjTDo%6wYby-CFB=e?plAW*DW`+f*yz_JJihN53=D~WeUzh|CTDUQ zN=(vR9S==o?+uNU9>Je$UK*!Ec*Vigl6=1f{vgThweSy1gx26)BD70Ar6K<}mJ4mg zZRx(hYoR^Jk!izveINf#*Q0s$pai82X_}^nRkw*(F&lCW2#y374TS{KG<=X1Lac2= zxq-nGRcNRokW}G88%xTfazm5B!IW6Cp^ZTDRSzZ?%x90rbnw}5o`J!Ww-OsJCXlA{ zgDhQHn`*eqz~G5|8^{|!Nb-Hq7OC9JfDIIegM&tjR1LkFrUoI24&BYS=^H3I0tP9{ z3~$)2X=)HEnD=W||9`(}^pt04d%|LK&~V!l&AQC9cHsKUmuuFFJ6ao#YR!6>vvvFT3mPcy0f4SP1%vU&sAA>e4l zxi!35)7021m)^KQQ>1}R5nwbD^)$R+)703ghj*JbkQoAqMxvgEPiUGN)-L>Y@knUG ztoAgJDFOqHOSvepd3b`FCCWvX2pAd(a~mkCd6-hxhmm=Z!Ra8)pnW1EcAdF_j1t&r zSbI!%*g&=j5SkN7d)M%Srm3+J5$`-}_#=bFa;f)UHM~K$HXh=2poW(jO>rKPCGo~o zppTG7J_3cLdq$znn8(I!gMuX`m&O7DX(B$ts<3)yE{HwJ*xRU!sf}fZhYq3)jnxE_ zCwYX8jn&V_MgxK)mZq_lK(aKCu;Ex^taj47HLf#E^bqsWcoBgl^+(3c%oKamc%^~C zlWh}?*Ah5R4dP(39X5Duq@V#H8VQ0Mw`!Ui8w9%)s8K)O3~?n0ZXD7yHJr=v28Bk_ zWngF|k!cKRni{TpnvA58)DjRHDS0-=HBAk9DZ2aC!->E&zE@2%rcs|89OBD@T;sd} zbj!7lmH__hjrq=K<1Ng9g>os$?Lg0Hv(>wzCv7}M9mo=&*_PDa#@A??8eW*QOQnqu z8xR~>lxuv9K(ZodIB>S1L*tVM1V zr(Y0A!RwhN`t&=4f#K4p|0M7*H8yHq55Ic+EYEs_NjTmZk=x`rb~8HBSCyqxu&Us?va*bvnQ;! zF3&a985~T}yQU@rw^5VSJF^w7X|(~t5xr|Vk3iD9M>!B&{QgzbrG^E*6vvycB5)ry z?5pf1j;0L;1V=no6B*1$N2sx$3SV~CgK@n9!4Xf@w39$G29HL}Gqcrb+G{W{Mw9cb zNuPI=ILPg^2@lVinqU*7V6p!)-lmB>7a%m^zM2x6rUvn{wuZbjw2AT}fM_J=Yr09( z)Xeftn*Ga7loA0$GbcBBm!_%VY5+d&YW9aV-EUB^q!`fjS^|$z!+sK_eN**odV@j1 z5?9&uMgmVzV+(jq_)~s*h~L5}@njEi(>pcXrCS@12lNjXjto~!}*~f z?>ZdPzxkwQl81QIk@T?Xvj)&DYomWO78ujN`4YpJV`6NZz6SI$J@FRrgKqi`F-W~0 zb3MfmHBF6OF|nHUGXsJn?z`#N1d=vBh9@8yV>!e83ALs_7!)km{r`o)-n74%&g%km z_=XR>a0q3Pqh=>u(@W^`INk5#IOU3)W&NeCiFhD98JPB5K2-emD`F!|uCy=KpGBu4 zu{_R&w$^_0V;w^KDbYDgmwOU5wZ(SH-?qdqUE#_9&QrO|?b3>`IrwX|T{>%54XCn7 zV)8fA6)8PCE6U(+)igEiMLCo9uQM1JvVYfq5rGs{pWS9gvUz5f)!%=mfx){zIbHnM z5=ge;ELVS<^{1lp;B@=db)Z7z_ zlgZCO=nL&PO!OF&J0r7nc8nU1qODi=-)KN^B!c!+lyY{08ZQ0PH&Ki^_8&4ZcvAiK z&l5fSx0@JIC^F<-gCaN9sw#0M{jSicrpx(9f~wN-iDx z-)m5?#Bcd2J~>Bz>)aB*<$ub6;E3Pyf11D@)Yy25--_`+V?b~uUh-3Ha*pDqbG#D7 zbxHqo1_MJ%(EjfcND10GRwv$~@BfLxz;LP3F9;-6I>(V!3tqe89g6s#l4Fg=+#^nER0!hctu`jdnVRO0xQ=BJ6V9hxIpCExfL9vfX z^{@EfQ+>+R&co|@!Sf~qsNyBg>+f5?aohUs>n8Q0OY`y zNCeYduVI?CPbABbX8ohNg+W*|*R8Js`lL2-Hk;?KRy1Eo9I}m1N;cnonWm|+*}VPG zfAcF03YKK^&HDG0%|FRLfK6BP7K4Ey9-z68z+P|4wPvcU9;Xz8_9akJ!`r+IB`nWB zRCTWMmY&EO--N#*7zz7k<34;PDjqu&!N2$nX9V9w_03H&7EZ+Dvu$Kw+t;n|xpH3@ z{mm}?odh4&Hp9Ng6}mJgFIv4eYxJMEsM)>M?%R$^0sbVVS>L?U*NZpq=B9n4xcfQ0 zK-fk%=rhdrD}Cli$xGJn%j*6oF4+}NMB0}=6M^y&z9U)Tf8va|pJ@D_e}-th^Zx+I CX))XY literal 0 HcmV?d00001 diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t new file mode 100644 index 0000000000..858cabb61f --- /dev/null +++ b/test/cram/base.t/run.t @@ -0,0 +1,28 @@ + $ cd base + $ cd .. + $ cat $(find . -name '*.odocl') > megaodocl + $ du -sh megaodocl + 5.1M megaodocl + $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null + + $ du -sh *.js + 20M db.js + 16M db_empty_payload.js + 17M db_no_docstring.js + 15M db_no_name.js + 13M db_no_type.js + 6.4M db_only_names.js + $ for f in $(find . -name '*.odocl'); do + > odoc html-generate --with-search --output-dir html $f 2> /dev/null + > done + $ odoc support-files -o html + $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js + $ du -sh html/index.js + 23M html/index.js + $ cp -r html /tmp + $ firefox /tmp/html/index.html diff --git a/test/cram/base.t/shadow_stdlib.odocl b/test/cram/base.t/shadow_stdlib.odocl new file mode 100644 index 0000000000000000000000000000000000000000..fa74a5d40a602ab91a9216cfb697400abc651157 GIT binary patch literal 81028 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 /dev/null - $ pwd - $TESTCASE_ROOT - $ cd .. - $ find . -name '*.odocl' - $ odoc compile-index --binary -I dream/_build/default/_doc/_odocls/playground -I dream/_build/default/_doc/_odocls/dream-pure -I dream/_build/default/_doc/_odocls/hello -o index.odoc_bin - odoc: unknown option '--binary'. - Usage: odoc compile-index [OPTION]… - Try 'odoc compile-index --help' or 'odoc --help' for more information. - [2] - $ sherlodoc_index --format=js --odoc=index.odoc_bin --db=db.js - index: option '--odoc': no 'index.odoc_bin' file or directory - Usage: index [--db=DB] [--format=DB_FORMAT] [--odoc=ODOC_FILE] [OPTION]… - Try 'index --help' for more information. - [124] - $ du -sh db.js - du: cannot access 'db.js': No such file or directory - [1] - $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/playground/page-index.odocl - odoc: FILE.odocl argument: no - 'dream/_build/default/_doc/_odocls/playground/page-index.odocl' file or - directory - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - [2] - $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/dream-pure/page-index.odocl - odoc: FILE.odocl argument: no - 'dream/_build/default/_doc/_odocls/dream-pure/page-index.odocl' file or - directory - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - [2] - $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/dream-pure/dream_pure.odocl - odoc: FILE.odocl argument: no - 'dream/_build/default/_doc/_odocls/dream-pure/dream_pure.odocl' file or - directory - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - [2] - $ odoc html-generate --with-search --output-dir html dream/_build/default/_doc/_odocls/hello/page-index.odocl - odoc: FILE.odocl argument: no - 'dream/_build/default/_doc/_odocls/hello/page-index.odocl' file or - directory - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - [2] - $ ls - html - odig - $ ls dream/_build/default/_doc/_odocls/dream-pure - ls: cannot access 'dream/_build/default/_doc/_odocls/dream-pure': No such file or directory - [2] - $ odoc support-files -o html - $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js - cat: db.js: No such file or directory - cat: ../../../bin/JSherlodoc/main.bc.js: No such file or directory - [1] - $ du -sh html/index.js - 0 html/index.js - $ ls html - fonts - highlight.pack.js - index.js - katex.min.css - katex.min.js - odoc.css - odoc_search.js - $ ls html/dream-pure - ls: cannot access 'html/dream-pure': No such file or directory - [2] - $ cp -r html /tmp - $ xdg-open /tmp/html/dream-pure/index.html diff --git a/test/cram/odoc.t/main.ml b/test/cram/simple.t/main.ml similarity index 100% rename from test/cram/odoc.t/main.ml rename to test/cram/simple.t/main.ml diff --git a/test/cram/odoc.t/page.mld b/test/cram/simple.t/page.mld similarity index 100% rename from test/cram/odoc.t/page.mld rename to test/cram/simple.t/page.mld diff --git a/test/cram/odoc.t/run.t b/test/cram/simple.t/run.t similarity index 100% rename from test/cram/odoc.t/run.t rename to test/cram/simple.t/run.t From bf1befa98aef6032ee84a306bf4daa04873bf20b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 30 May 2023 17:57:05 +0200 Subject: [PATCH 070/285] payloads completely empty (broken) --- bin/JSherlodoc/main.ml | 2 +- lib/db/caches.ml | 107 ++++++++++++++++++++++--------- lib/db/db.ml | 5 +- lib/db/elt.ml | 17 ++--- lib/db/trie.ml | 10 +++ lib/index_lib/load_doc.ml | 119 ++++++++++++++++------------------- lib/query/sort.ml | 9 +-- lib/storage_js/storage_js.ml | 18 ++++++ test/cram/base.t/run.t | 33 +++++++--- test/cram/simple.t/run.t | 2 +- 10 files changed, 193 insertions(+), 129 deletions(-) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index d6baa03336..2061ffab8f 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -5,7 +5,7 @@ let string_of_kind (kind : Db.Elt.kind) = let open Db.Elt in match kind with | Doc -> "doc" - | TypeDecl _ -> "type" + | TypeDecl -> "type" | Module -> "module" | Exception -> "exception" | Class_type -> "class type" diff --git a/lib/db/caches.ml b/lib/db/caches.ml index 643f8f18f9..184d2b4e4f 100644 --- a/lib/db/caches.ml +++ b/lib/db/caches.ml @@ -1,38 +1,87 @@ -module Cache = Cache.Make (struct -type t = string +module String = Cache.Make (struct + type t = string -let copy str = String.init (String.length str) (String.get str) + let copy str = String.init (String.length str) (String.get str) end) -module Cache_list = struct -module H = Hashtbl.Make (struct - type t = char list +module Char_list = struct + module H = Hashtbl.Make (struct + type t = char list - let equal = List.equal Char.equal - let hash = Hashtbl.hash -end) + let equal = List.equal Char.equal + let hash = Hashtbl.hash + end) + + let cache = H.create 128 + + let memo lst = + let rec go lst = + try H.find cache lst + with Not_found -> + let lst = + match lst with + | [] -> [] + | x :: xs -> x :: go xs + in + H.add cache lst lst ; + lst + in + go lst +end + +module String_list = struct + module H = Hashtbl.Make (struct + type t = string list -let cache = H.create 128 - -let memo lst = - let rec go lst = - try H.find cache lst - with Not_found -> - let lst = - match lst with - | [] -> [] - | x :: xs -> x :: go xs - in - H.add cache lst lst ; - lst - in - go lst + let equal = (List.equal Stdlib.String.equal) + let hash = Hashtbl.hash + end) + + let cache = H.create 128 + + let memo lst = + let rec go lst = + try H.find cache lst + with Not_found -> + let lst = List.map String.memo lst in + let lst = + match lst with + | [] -> [] + | x :: xs -> x :: go xs + in + H.add cache lst lst ; + lst + in + go lst end +module Cache_string_list_list = struct + module H = Hashtbl.Make (struct + type t = string list list + + let equal = List.equal (List.equal Stdlib.String.equal) + let hash = Hashtbl.hash + end) -(* - <* for%iter item do *> + let cache = H.create 128 + + let memo lst = + let rec go lst = + try H.find cache lst + with Not_found -> + let lst = List.map String_list.memo lst in + let lst = + match lst with + | [] -> [] + | x :: xs -> x :: go xs + in + H.add cache lst lst ; + lst + in + go lst +end - ... +module Array = Cache.Make( struct +type t = Elt.t array - <* done *> -*) \ No newline at end of file +let copy = Fun.id +end) \ No newline at end of file diff --git a/lib/db/db.ml b/lib/db/db.ml index 428ace2b2f..32bdd0f6ab 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -4,7 +4,6 @@ module Storage_toplevel = Storage module Trie = Trie module Caches = Caches include Types -open Caches let list_of_string s = List.init (String.length s) (String.get s) @@ -134,7 +133,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let ho = Hocc.create 16 in let hs = Hset.create 16 in List.iter - (fun (path, count) -> store ~ho ~hs ~count (Cache_list.memo path) elt) + (fun (path, count) -> store ~ho ~hs ~count (Caches.Char_list.memo path) elt) (regroup_chars paths) let store_chars name elt = @@ -149,7 +148,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct db_names := go !db_names name let store_word word elt = - (word |> list_of_string |> List.rev |> Cache_list.memo |> store_chars) elt + (word |> list_of_string |> List.rev |> Caches.Char_list.memo |> store_chars) elt end module Storage = Storage diff --git a/lib/db/elt.ml b/lib/db/elt.ml index d5f6cf98b7..752932fe21 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -25,7 +25,7 @@ type type_path = string list list type kind = | Doc - | TypeDecl of { type_decl : string } + | TypeDecl | Module | Exception | Class_type @@ -34,18 +34,9 @@ type kind = | TypeExtension | ExtensionConstructor | ModuleType - | Constructor of - { type_ : string - ; type_paths : type_path - } - | Field of - { type_ : string - ; type_paths : type_path - } - | Val of - { type_ : string - ; type_paths : type_path - } + | Constructor of type_path + | Field of type_path + | Val of type_path type package = { name : string diff --git a/lib/db/trie.ml b/lib/db/trie.ml index 96fae376fa..6e3f786881 100644 --- a/lib/db/trie.ml +++ b/lib/db/trie.ml @@ -93,3 +93,13 @@ let rec fold_map merge transform t = | None, opt | opt, None -> opt | Some acc, Some res -> Some (merge acc res)) children leaf + +let rec map_leaf ~f t = + match t with + | Leaf (v, outcome) -> Leaf (v, f outcome) + | Node { leaf; children; summary } -> + let leaf = Option.map f leaf in + let summary = Option.map f summary in + + let children = M.map (map_leaf ~f) children in + Node { leaf; children; summary } diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 97be9b3beb..e6bf287292 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -1,13 +1,13 @@ module Elt = Db.Elt module Db_common = Db -open Db.Caches +module Caches = Db.Caches module Make (Storage : Db.Storage.S) = struct module Types = Db.Types module Db = Db.Make (Storage) module ModuleName = Odoc_model.Names.ModuleName - let clear () = Cache.clear () + let clear () = Caches.String.clear () let rec type_size = function | Odoc_model.Lang.TypeExpr.Var _ -> 1 @@ -35,43 +35,49 @@ module Make (Storage : Db.Storage.S) = struct let fullname = fullname t in tails (String.split_on_char '.' fullname) - let rec paths ~prefix ~sgn = function - | Odoc_model.Lang.TypeExpr.Var _ -> - let poly = Cache.memo "POLY" in - [ poly :: Cache.memo (Types.string_of_sgn sgn) :: prefix ] - | Any -> - let poly = Cache.memo "POLY" in - [ poly :: Cache.memo (Types.string_of_sgn sgn) :: prefix ] - | Arrow (_, a, b) -> - let prefix_left = Cache.memo "->0" :: prefix in - let prefix_right = Cache.memo "->1" :: prefix in - List.rev_append - (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) - (paths ~prefix:prefix_right ~sgn b) - | Constr (name, args) -> - let name = fullname name in - let prefix = - Cache.memo name :: Cache.memo (Types.string_of_sgn sgn) :: prefix - in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = Cache.memo (string_of_int i) :: prefix in - paths ~prefix ~sgn arg) - args - end - | Tuple args -> - rev_concat - @@ List.mapi (fun i arg -> - let prefix = Cache.memo (string_of_int i ^ "*") :: prefix in - paths ~prefix ~sgn arg) - @@ args - | _ -> [] + (** for scoring *) + let rec paths ~prefix ~sgn t = + let r = + match t with + | Odoc_model.Lang.TypeExpr.Var _ -> + let poly = Caches.String.memo "POLY" in + [ poly :: Caches.String.memo (Types.string_of_sgn sgn) :: prefix ] + | Any -> + let poly = Caches.String.memo "POLY" in + [ poly :: Caches.String.memo (Types.string_of_sgn sgn) :: prefix ] + | Arrow (_, a, b) -> + let prefix_left = Caches.String.memo "->0" :: prefix in + let prefix_right = Caches.String.memo "->1" :: prefix in + List.rev_append + (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) + (paths ~prefix:prefix_right ~sgn b) + | Constr (name, args) -> + let name = fullname name in + let prefix = + Caches.String.memo name :: Caches.String.memo (Types.string_of_sgn sgn) :: prefix + in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = Caches.String.memo (string_of_int i) :: prefix in + paths ~prefix ~sgn arg) + args + end + | Tuple args -> + rev_concat + @@ List.mapi (fun i arg -> + let prefix = Caches.String.memo (string_of_int i ^ "*") :: prefix in + paths ~prefix ~sgn arg) + @@ args + | _ -> [] + in + Caches.Cache_string_list_list.memo r + (** for indexing *) let rec type_paths ~prefix ~sgn = function | Odoc_model.Lang.TypeExpr.Var _ -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] @@ -100,6 +106,9 @@ module Make (Storage : Db.Storage.S) = struct | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args | _ -> [] + let type_paths ~prefix ~sgn t = + Caches.Cache_string_list_list.memo (type_paths ~prefix ~sgn t) + let register_doc elt doc_txt = let doc_words = String.split_on_char ' ' doc_txt in List.iter (fun word -> Db.store_word word elt) doc_words @@ -124,22 +133,6 @@ module Make (Storage : Db.Storage.S) = struct TypeExpr.Arrow (Some (Label field_name), field.type_, res)) res fields - let display_constructor_type args res = - let open Odoc_model.Lang in - match args with - | TypeDecl.Constructor.Tuple args -> - let type_ = - match args with - | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) - | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) - | _ -> res - in - Odoc_search.Render.text_of_type type_ - | TypeDecl.Constructor.Record fields -> - let fields = Odoc_search.Render.text_of_record fields in - let res = Odoc_search.Render.text_of_type res in - fields ^ " -> " ^ res - let searchable_type_of_record parent_type type_ = let open Odoc_model.Lang in TypeExpr.Arrow (None, parent_type, type_) @@ -172,30 +165,24 @@ module Make (Storage : Db.Storage.S) = struct 200 let convert_kind (kind : Odoc_search.Entry.extra) = - let open Odoc_search in let open Odoc_search.Entry in match kind with - | TypeDecl typedecl -> - let type_decl = typedecl.txt in - Elt.TypeDecl { type_decl } + | TypeDecl _ -> Elt.TypeDecl | Module -> Elt.ModuleType | Value { value = _; type_ } -> let paths = paths ~prefix:[] ~sgn:Pos type_ in - let type_ = Render.text_of_type type_ in - Val { type_; type_paths = paths } + Val paths | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let type_paths = type_paths ~prefix:[] ~sgn:Pos searchable_type in - let type_ = display_constructor_type args res in - Constructor { type_; type_paths } + let type_paths = paths ~prefix:[] ~sgn:Pos searchable_type in + Constructor type_paths | Field { mutable_ = _; parent_type; type_ } -> let type_paths = type_ |> searchable_type_of_record parent_type |> paths ~prefix:[] ~sgn:Pos in - let type_ = Render.text_of_type type_ in - Field { type_; type_paths } + Field type_paths | Doc _ -> Doc | Exception _ -> Exception | Class_type _ -> Class_type @@ -213,7 +200,7 @@ module Make (Storage : Db.Storage.S) = struct (List.map (fun xs -> let xs = List.concat_map Db_common.list_of_string xs in - Cache_list.memo xs) + Caches.Char_list.memo xs) type_paths) let register_kind ~type_search elt (kind : Odoc_search.Entry.extra) = diff --git a/lib/query/sort.ml b/lib/query/sort.ml index e6aee2a85d..b7bedc2f62 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -190,10 +190,8 @@ module Reasoning = struct let open Elt in match query_type, elt.kind with | [], _ -> None - | ( _ - , ( Elt.Constructor { type_paths; _ } - | Elt.Field { type_paths; _ } - | Elt.Val { type_paths; _ } ) ) -> + | _, (Elt.Constructor type_paths | Elt.Field type_paths | Elt.Val type_paths) + -> Some (Type_distance.v query_type type_paths) | _ -> None @@ -209,11 +207,10 @@ module Reasoning = struct let open Elt in String.starts_with ~prefix:"Stdlib." elt.name - let kind elt = match elt.Elt.kind with | Elt.Doc -> Doc - | Elt.TypeDecl _ -> TypeDecl + | Elt.TypeDecl -> TypeDecl | Elt.Module -> Module | Elt.Exception -> Exception | Elt.Class_type -> Class_type diff --git a/lib/storage_js/storage_js.ml b/lib/storage_js/storage_js.ml index 7c737603ec..ff4a2f1edc 100644 --- a/lib/storage_js/storage_js.ml +++ b/lib/storage_js/storage_js.ml @@ -1,9 +1,27 @@ +open Common + type writer = out_channel let open_out = open_out let close_out = close_out let save ~db t = + let t = + Db.Storage.( + ( Db.Trie.map_leaf + ~f:(fun occs -> + Int.Map.map + (fun _sets -> + (*sets |> Db.Elt.Set.elements |> Array.of_list + |> Db.Caches.Array.memo*) ()) + occs) + t.db + , Db.Trie.map_leaf + ~f:(fun _set -> + (*set |> Db.Elt.Set.elements |> Array.of_list |> Db.Caches.Array.memo*) + ()) + t.db_names )) + in let str = Marshal.to_string t [] in let str = Base64.encode_string str in Printf.fprintf db "function sherlodoc_db () { return %S; }\n%!" str diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 858cabb61f..c9c3a74abd 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -1,5 +1,3 @@ - $ cd base - $ cd .. $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 5.1M megaodocl @@ -10,19 +8,34 @@ $ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null - $ du -sh *.js - 20M db.js - 16M db_empty_payload.js - 17M db_no_docstring.js - 15M db_no_name.js - 13M db_no_type.js - 6.4M db_only_names.js + $ gzip -k db.js + $ gzip -k megaodocl + + $ du -s *.js *.gz + 8424 db.js + 8424 db_empty_payload.js + 7904 db_no_docstring.js + 5744 db_no_name.js + 3168 db_no_type.js + 2648 db_only_names.js + 1288 db.js.gz + 1628 megaodocl.gz + + $ du -sh *.js *.gz + 8.3M db.js + 8.3M db_empty_payload.js + 7.8M db_no_docstring.js + 5.7M db_no_name.js + 3.1M db_no_type.js + 2.6M db_only_names.js + 1.3M db.js.gz + 1.6M megaodocl.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --with-search --output-dir html $f 2> /dev/null > done $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js $ du -sh html/index.js - 23M html/index.js + 13M html/index.js $ cp -r html /tmp $ firefox /tmp/html/index.html diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 975d8e8820..64cf6832f7 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -16,7 +16,7 @@ $ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . page.mld $ sherlodoc_index --format=js --db=db.js *.odocl $ du -sh db.js - 16K db.js + 12K db.js $ odoc html-generate --with-search --output-dir html main.odocl $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html From 8e48c8a11e5c7b026697f099d89f3103b640e964 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 30 May 2023 18:41:00 +0200 Subject: [PATCH 071/285] index uses arrays instead of sets --- lib/db/caches.ml | 15 ++++++++------- lib/db/db.ml | 8 +++++--- lib/db/storage.ml | 2 +- lib/db/storage.mli | 2 +- lib/index_lib/load_doc.ml | 12 +++++++++--- lib/query/query.ml | 2 +- lib/storage_js/storage_js.ml | 27 +++++++++++++++++++-------- test/cram/base.t/run.t | 33 +++++++++++++++++---------------- test/cram/simple.t/run.t | 2 +- 9 files changed, 62 insertions(+), 41 deletions(-) diff --git a/lib/db/caches.ml b/lib/db/caches.ml index 184d2b4e4f..3ad53df311 100644 --- a/lib/db/caches.ml +++ b/lib/db/caches.ml @@ -1,7 +1,7 @@ module String = Cache.Make (struct type t = string - let copy str = String.init (String.length str) (String.get str) + let copy str = String.init (String.length str) (String.get str) end) module Char_list = struct @@ -31,9 +31,9 @@ end module String_list = struct module H = Hashtbl.Make (struct - type t = string list + type t = string list - let equal = (List.equal Stdlib.String.equal) + let equal = List.equal Stdlib.String.equal let hash = Hashtbl.hash end) @@ -54,6 +54,7 @@ module String_list = struct in go lst end + module Cache_string_list_list = struct module H = Hashtbl.Make (struct type t = string list list @@ -80,8 +81,8 @@ module Cache_string_list_list = struct go lst end -module Array = Cache.Make( struct -type t = Elt.t array +module Array = Cache.Make (struct + type t = Elt.t array -let copy = Fun.id -end) \ No newline at end of file + let copy = Fun.id +end) diff --git a/lib/db/db.ml b/lib/db/db.ml index 32bdd0f6ab..50990c7f40 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -74,7 +74,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let export h = load_counter := 0 ; - let t = { Storage_toplevel.db = !db; db_names = !db_names } in + let t = { Storage_toplevel.db_types = !db; db_names = !db_names } in Storage.save ~db:h t ; db := Trie.empty () ; db_names := Trie.empty () @@ -133,7 +133,8 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let ho = Hocc.create 16 in let hs = Hset.create 16 in List.iter - (fun (path, count) -> store ~ho ~hs ~count (Caches.Char_list.memo path) elt) + (fun (path, count) -> + store ~ho ~hs ~count (Caches.Char_list.memo path) elt) (regroup_chars paths) let store_chars name elt = @@ -148,7 +149,8 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct db_names := go !db_names name let store_word word elt = - (word |> list_of_string |> List.rev |> Caches.Char_list.memo |> store_chars) elt + (word |> list_of_string |> List.rev |> Caches.Char_list.memo |> store_chars) + elt end module Storage = Storage diff --git a/lib/db/storage.ml b/lib/db/storage.ml index fa25dee477..10a54142e2 100644 --- a/lib/db/storage.ml +++ b/lib/db/storage.ml @@ -1,5 +1,5 @@ type t = - { db : Types.db + { db_types : Types.db ; db_names : Elt.Set.t Trie.t } diff --git a/lib/db/storage.mli b/lib/db/storage.mli index fa25dee477..10a54142e2 100644 --- a/lib/db/storage.mli +++ b/lib/db/storage.mli @@ -1,5 +1,5 @@ type t = - { db : Types.db + { db_types : Types.db ; db_names : Elt.Set.t Trie.t } diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index e6bf287292..3df1b0e918 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -54,7 +54,9 @@ module Make (Storage : Db.Storage.S) = struct | Constr (name, args) -> let name = fullname name in let prefix = - Caches.String.memo name :: Caches.String.memo (Types.string_of_sgn sgn) :: prefix + Caches.String.memo name + :: Caches.String.memo (Types.string_of_sgn sgn) + :: prefix in begin match args with @@ -63,14 +65,18 @@ module Make (Storage : Db.Storage.S) = struct rev_concat @@ List.mapi (fun i arg -> - let prefix = Caches.String.memo (string_of_int i) :: prefix in + let prefix = + Caches.String.memo (string_of_int i) :: prefix + in paths ~prefix ~sgn arg) args end | Tuple args -> rev_concat @@ List.mapi (fun i arg -> - let prefix = Caches.String.memo (string_of_int i ^ "*") :: prefix in + let prefix = + Caches.String.memo (string_of_int i ^ "*") :: prefix + in paths ~prefix ~sgn arg) @@ args | _ -> [] diff --git a/lib/query/query.ml b/lib/query/query.ml index 36c93cbfa2..c8a71e34e3 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -34,7 +34,7 @@ let collapse_trie_with_poly ~count name t = let find_inter ~shards names = List.fold_left (fun acc shard -> - let db = shard.Storage.db in + let db = shard.Storage.db_types in let r = inter_list @@ List.map diff --git a/lib/storage_js/storage_js.ml b/lib/storage_js/storage_js.ml index ff4a2f1edc..d7b6898a24 100644 --- a/lib/storage_js/storage_js.ml +++ b/lib/storage_js/storage_js.ml @@ -11,15 +11,14 @@ let save ~db t = ( Db.Trie.map_leaf ~f:(fun occs -> Int.Map.map - (fun _sets -> - (*sets |> Db.Elt.Set.elements |> Array.of_list - |> Db.Caches.Array.memo*) ()) + (fun set -> + set |> Db.Elt.Set.elements |> Array.of_list + |> Db.Caches.Array.memo) occs) - t.db + t.db_types , Db.Trie.map_leaf - ~f:(fun _set -> - (*set |> Db.Elt.Set.elements |> Array.of_list |> Db.Caches.Array.memo*) - ()) + ~f:(fun set -> + set |> Db.Elt.Set.elements |> Array.of_list |> Db.Caches.Array.memo) t.db_names )) in let str = Marshal.to_string t [] in @@ -28,4 +27,16 @@ let save ~db t = let load str = let str = Base64.decode_exn str in - [ Marshal.from_string str 0 ] + let db_types, db_names = Marshal.from_string str 0 in + let db_types = + Db.Trie.map_leaf + ~f:(fun occs -> + Int.Map.map (fun arr -> arr |> Array.to_seq |> Db.Elt.Set.of_seq) occs) + db_types + in + let db_names = + Db.Trie.map_leaf + ~f:(fun arr -> arr |> Array.to_seq |> Db.Elt.Set.of_seq) + db_names + in + [ Db.Storage.{ db_types; db_names } ] diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index c9c3a74abd..c2da9e0017 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -12,23 +12,23 @@ $ gzip -k megaodocl $ du -s *.js *.gz - 8424 db.js - 8424 db_empty_payload.js - 7904 db_no_docstring.js - 5744 db_no_name.js - 3168 db_no_type.js - 2648 db_only_names.js - 1288 db.js.gz + 16744 db.js + 12852 db_empty_payload.js + 14876 db_no_docstring.js + 12304 db_no_name.js + 9988 db_no_type.js + 4332 db_only_names.js + 4084 db.js.gz 1628 megaodocl.gz $ du -sh *.js *.gz - 8.3M db.js - 8.3M db_empty_payload.js - 7.8M db_no_docstring.js - 5.7M db_no_name.js - 3.1M db_no_type.js - 2.6M db_only_names.js - 1.3M db.js.gz + 17M db.js + 13M db_empty_payload.js + 15M db_no_docstring.js + 13M db_no_name.js + 9.8M db_no_type.js + 4.3M db_only_names.js + 4.0M db.js.gz 1.6M megaodocl.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --with-search --output-dir html $f 2> /dev/null @@ -36,6 +36,7 @@ $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js $ du -sh html/index.js - 13M html/index.js + $ ls html + 21M html/index.js $ cp -r html /tmp - $ firefox /tmp/html/index.html + $ firefox /tmp/html/base/index.html diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 64cf6832f7..975d8e8820 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -16,7 +16,7 @@ $ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . page.mld $ sherlodoc_index --format=js --db=db.js *.odocl $ du -sh db.js - 12K db.js + 16K db.js $ odoc html-generate --with-search --output-dir html main.odocl $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html From bae317bae40b720aced08516746337c52b46dac7 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 2 Jun 2023 11:50:39 +0200 Subject: [PATCH 072/285] Shares submaps for a big size reduction --- bin/api/{dune => _dune} | 0 bin/index/index.ml | 10 +- lib/common/array.ml | 6 + lib/common/array_map.ml | 46 +++ lib/common/char.ml | 3 + lib/common/map.ml | 549 +++++++++++++++++++++++++ lib/db/cache.ml | 242 ++++++++++- lib/db/cache.mli | 26 +- lib/db/caches.ml | 88 ---- lib/db/db.ml | 93 ++--- lib/db/db.mli | 14 +- lib/db/elt.ml | 36 +- lib/db/storage.ml | 10 +- lib/db/storage.mli | 13 - lib/db/trie_compact.ml | 61 +++ lib/db/{trie.ml => trie_gen.ml} | 45 +- lib/db/types.ml | 10 +- lib/index_lib/index_lib.ml | 5 +- lib/index_lib/index_lib.mli | 1 - lib/index_lib/load_doc.ml | 58 ++- lib/query/query.ml | 8 +- lib/query/query.mli | 2 +- lib/storage_ancient/storage_ancient.ml | 4 +- lib/storage_js/storage_js.ml | 21 +- static/packages.csv | 8 +- test/cram/base.t/run.t | 41 +- test/cram/simple.t/run.t | 7 +- 27 files changed, 1090 insertions(+), 317 deletions(-) rename bin/api/{dune => _dune} (100%) create mode 100644 lib/common/array.ml create mode 100644 lib/common/array_map.ml create mode 100644 lib/common/char.ml create mode 100644 lib/common/map.ml delete mode 100644 lib/db/caches.ml delete mode 100644 lib/db/storage.mli create mode 100644 lib/db/trie_compact.ml rename lib/db/{trie.ml => trie_gen.ml} (64%) diff --git a/bin/api/dune b/bin/api/_dune similarity index 100% rename from bin/api/dune rename to bin/api/_dune diff --git a/bin/index/index.ml b/bin/index/index.ml index 490ae4ec1f..a636081d37 100644 --- a/bin/index/index.ml +++ b/bin/index/index.ml @@ -1,11 +1,11 @@ let main files index_docstring index_name type_search empty_payload db_filename db_format = let index = files |> List.map Fpath.of_string |> List.map Result.get_ok in - let optimize, storage = + let storage = match db_format with - | `ancient -> true, (module Storage_ancient : Db.Storage.S) - | `marshal -> false, (module Storage_marshal : Db.Storage.S) - | `js -> false, (module Storage_js : Db.Storage.S) + | `ancient -> (module Storage_ancient : Db.Storage.S) + | `marshal -> (module Storage_marshal : Db.Storage.S) + | `js -> (module Storage_js : Db.Storage.S) in let add_entries li e = Odoc_search.Entry.entries_of_item e @ li in let index = @@ -20,7 +20,7 @@ let main files index_docstring index_name type_search empty_payload db_filename [] in Index_lib.main ~index_docstring ~index_name ~type_search ~empty_payload ~index - ~db_filename ~optimize storage + ~db_filename storage open Cmdliner diff --git a/lib/common/array.ml b/lib/common/array.ml new file mode 100644 index 0000000000..85db16ba19 --- /dev/null +++ b/lib/common/array.ml @@ -0,0 +1,6 @@ +include Stdlib.Array + +let equal (a : 'a -> 'a -> bool) arr arr' = + length arr = length arr' && for_all2 a arr arr' + +let hash (a : 'a -> int) arr = Hashtbl.hash (map a arr) diff --git a/lib/common/array_map.ml b/lib/common/array_map.ml new file mode 100644 index 0000000000..f16282c941 --- /dev/null +++ b/lib/common/array_map.ml @@ -0,0 +1,46 @@ +module type S = sig + type key + type 'a t + + val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + + val of_seq : (key * 'a) Seq.t -> 'a t + val to_array : 'a t -> (key * 'a) array + val find : key:key -> 'a t -> 'a option + val map : f:('a -> 'b) -> 'a t -> 'b t + val fold : f:(key:key -> acc:'b -> 'a -> 'b) -> init:'b -> 'a t -> 'b +end + +module Make (Key : Map.OrderedType) : S with type key = Key.t = struct + type key = Key.t + type 'a t = (key * 'a) array + + let equal eq_a = + Array.equal (fun (k, v) (k', v') -> Key.compare k k' = 0 && eq_a v v') + + let to_array arr = arr + + let of_seq seq = + let arr = seq |> Array.of_seq in + Array.fast_sort (fun (k, _) (k', _) -> Key.compare k k') arr ; + arr + + let rec find ~key arr lo hi = + if lo = hi + then None + else + let mid = (lo + hi) / 2 in + let key', v = arr.(mid) in + let comp = Key.compare key key' in + if comp = 0 + then Some v + else if comp < 0 + then find ~key arr lo mid + else find ~key arr mid hi + + let find ~key arr = find ~key arr 0 (Array.length arr) + let map ~f arr = Array.map (fun (k, v) -> k, f v) arr + + let fold ~f ~init arr = + Array.fold_left (fun acc (key, v) -> f ~key ~acc v) init arr +end diff --git a/lib/common/char.ml b/lib/common/char.ml new file mode 100644 index 0000000000..b76da69d6c --- /dev/null +++ b/lib/common/char.ml @@ -0,0 +1,3 @@ +include Stdlib.Char +module Map = Map.Make (Stdlib.Char) +module Array_map = Array_map.Make (Stdlib.Char) diff --git a/lib/common/map.ml b/lib/common/map.ml new file mode 100644 index 0000000000..dbe4d029ee --- /dev/null +++ b/lib/common/map.ml @@ -0,0 +1,549 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) +[@@@warning "-9"] +module type OrderedType = + sig + type t + val compare: t -> t -> int + end + +module type S = + sig + type key + type !+'a t = + Empty + | Node of {l:'a t; v:key; d:'a; r:'a t; h:int} + val empty: 'a t + val add: key -> 'a -> 'a t -> 'a t + val add_to_list: key -> 'a -> 'a list t -> 'a list t + val update: key -> ('a option -> 'a option) -> 'a t -> 'a t + val singleton: key -> 'a -> 'a t + val remove: key -> 'a t -> 'a t + val merge: + (key -> 'a option -> 'b option -> 'c option) -> + 'a t -> 'b t -> 'c t + val union: (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t + val cardinal: 'a t -> int + val bindings: 'a t -> (key * 'a) list + val min_binding: 'a t -> (key * 'a) + val min_binding_opt: 'a t -> (key * 'a) option + val max_binding: 'a t -> (key * 'a) + val max_binding_opt: 'a t -> (key * 'a) option + val choose: 'a t -> (key * 'a) + val choose_opt: 'a t -> (key * 'a) option + val find: key -> 'a t -> 'a + val find_opt: key -> 'a t -> 'a option + val find_first: (key -> bool) -> 'a t -> key * 'a + val find_first_opt: (key -> bool) -> 'a t -> (key * 'a) option + val find_last: (key -> bool) -> 'a t -> key * 'a + val find_last_opt: (key -> bool) -> 'a t -> (key * 'a) option + val iter: (key -> 'a -> unit) -> 'a t -> unit + val fold: (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b + val map: ('a -> 'b) -> 'a t -> 'b t + val mapi: (key -> 'a -> 'b) -> 'a t -> 'b t + val filter: (key -> 'a -> bool) -> 'a t -> 'a t + val filter_map: (key -> 'a -> 'b option) -> 'a t -> 'b t + val partition: (key -> 'a -> bool) -> 'a t -> 'a t * 'a t + val split: key -> 'a t -> 'a t * 'a option * 'a t + val is_empty: 'a t -> bool + val mem: key -> 'a t -> bool + val equal: ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + val compare: ('a -> 'a -> int) -> 'a t -> 'a t -> int + val for_all: (key -> 'a -> bool) -> 'a t -> bool + val exists: (key -> 'a -> bool) -> 'a t -> bool + val to_list : 'a t -> (key * 'a) list + val of_list : (key * 'a) list -> 'a t + val to_seq : 'a t -> (key * 'a) Seq.t + val to_rev_seq : 'a t -> (key * 'a) Seq.t + val to_seq_from : key -> 'a t -> (key * 'a) Seq.t + val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t + val of_seq : (key * 'a) Seq.t -> 'a t + end + +module Make(Ord: OrderedType) = struct + + type key = Ord.t + + type 'a t = + Empty + | Node of {l:'a t; v:key; d:'a; r:'a t; h:int} + + let height = function + Empty -> 0 + | Node {h} -> h + + let create l x d r = + let hl = height l and hr = height r in + Node{l; v=x; d; r; h=(if hl >= hr then hl + 1 else hr + 1)} + + let singleton x d = Node{l=Empty; v=x; d; r=Empty; h=1} + + let bal l x d r = + let hl = match l with Empty -> 0 | Node {h} -> h in + let hr = match r with Empty -> 0 | Node {h} -> h in + if hl > hr + 2 then begin + match l with + Empty -> invalid_arg "Map.bal" + | Node{l=ll; v=lv; d=ld; r=lr} -> + if height ll >= height lr then + create ll lv ld (create lr x d r) + else begin + match lr with + Empty -> invalid_arg "Map.bal" + | Node{l=lrl; v=lrv; d=lrd; r=lrr}-> + create (create ll lv ld lrl) lrv lrd (create lrr x d r) + end + end else if hr > hl + 2 then begin + match r with + Empty -> invalid_arg "Map.bal" + | Node{l=rl; v=rv; d=rd; r=rr} -> + if height rr >= height rl then + create (create l x d rl) rv rd rr + else begin + match rl with + Empty -> invalid_arg "Map.bal" + | Node{l=rll; v=rlv; d=rld; r=rlr} -> + create (create l x d rll) rlv rld (create rlr rv rd rr) + end + end else + Node{l; v=x; d; r; h=(if hl >= hr then hl + 1 else hr + 1)} + + let empty = Empty + + let is_empty = function Empty -> true | _ -> false + + let rec add x data = function + Empty -> + Node{l=Empty; v=x; d=data; r=Empty; h=1} + | Node {l; v; d; r; h} as m -> + let c = Ord.compare x v in + if c = 0 then + if d == data then m else Node{l; v=x; d=data; r; h} + else if c < 0 then + let ll = add x data l in + if l == ll then m else bal ll v d r + else + let rr = add x data r in + if r == rr then m else bal l v d rr + + let rec find x = function + Empty -> + raise Not_found + | Node {l; v; d; r} -> + let c = Ord.compare x v in + if c = 0 then d + else find x (if c < 0 then l else r) + + let rec find_first_aux v0 d0 f = function + Empty -> + (v0, d0) + | Node {l; v; d; r} -> + if f v then + find_first_aux v d f l + else + find_first_aux v0 d0 f r + + let rec find_first f = function + Empty -> + raise Not_found + | Node {l; v; d; r} -> + if f v then + find_first_aux v d f l + else + find_first f r + + let rec find_first_opt_aux v0 d0 f = function + Empty -> + Some (v0, d0) + | Node {l; v; d; r} -> + if f v then + find_first_opt_aux v d f l + else + find_first_opt_aux v0 d0 f r + + let rec find_first_opt f = function + Empty -> + None + | Node {l; v; d; r} -> + if f v then + find_first_opt_aux v d f l + else + find_first_opt f r + + let rec find_last_aux v0 d0 f = function + Empty -> + (v0, d0) + | Node {l; v; d; r} -> + if f v then + find_last_aux v d f r + else + find_last_aux v0 d0 f l + + let rec find_last f = function + Empty -> + raise Not_found + | Node {l; v; d; r} -> + if f v then + find_last_aux v d f r + else + find_last f l + + let rec find_last_opt_aux v0 d0 f = function + Empty -> + Some (v0, d0) + | Node {l; v; d; r} -> + if f v then + find_last_opt_aux v d f r + else + find_last_opt_aux v0 d0 f l + + let rec find_last_opt f = function + Empty -> + None + | Node {l; v; d; r} -> + if f v then + find_last_opt_aux v d f r + else + find_last_opt f l + + let rec find_opt x = function + Empty -> + None + | Node {l; v; d; r} -> + let c = Ord.compare x v in + if c = 0 then Some d + else find_opt x (if c < 0 then l else r) + + let rec mem x = function + Empty -> + false + | Node {l; v; r} -> + let c = Ord.compare x v in + c = 0 || mem x (if c < 0 then l else r) + + let rec min_binding = function + Empty -> raise Not_found + | Node {l=Empty; v; d} -> (v, d) + | Node {l} -> min_binding l + + let rec min_binding_opt = function + Empty -> None + | Node {l=Empty; v; d} -> Some (v, d) + | Node {l}-> min_binding_opt l + + let rec max_binding = function + Empty -> raise Not_found + | Node {v; d; r=Empty} -> (v, d) + | Node {r} -> max_binding r + + let rec max_binding_opt = function + Empty -> None + | Node {v; d; r=Empty} -> Some (v, d) + | Node {r} -> max_binding_opt r + + let rec remove_min_binding = function + Empty -> invalid_arg "Map.remove_min_elt" + | Node {l=Empty; r} -> r + | Node {l; v; d; r} -> bal (remove_min_binding l) v d r + + let merge t1 t2 = + match (t1, t2) with + (Empty, t) -> t + | (t, Empty) -> t + | (_, _) -> + let (x, d) = min_binding t2 in + bal t1 x d (remove_min_binding t2) + + let rec remove x = function + Empty -> + Empty + | (Node {l; v; d; r} as m) -> + let c = Ord.compare x v in + if c = 0 then merge l r + else if c < 0 then + let ll = remove x l in if l == ll then m else bal ll v d r + else + let rr = remove x r in if r == rr then m else bal l v d rr + + let rec update x f = function + Empty -> + begin match f None with + | None -> Empty + | Some data -> Node{l=Empty; v=x; d=data; r=Empty; h=1} + end + | Node {l; v; d; r; h} as m -> + let c = Ord.compare x v in + if c = 0 then begin + match f (Some d) with + | None -> merge l r + | Some data -> + if d == data then m else Node{l; v=x; d=data; r; h} + end else if c < 0 then + let ll = update x f l in + if l == ll then m else bal ll v d r + else + let rr = update x f r in + if r == rr then m else bal l v d rr + + let add_to_list x data m = + let add = function None -> Some [data] | Some l -> Some (data :: l) in + update x add m + + let rec iter f = function + Empty -> () + | Node {l; v; d; r} -> + iter f l; f v d; iter f r + + let rec map f = function + Empty -> + Empty + | Node {l; v; d; r; h} -> + let l' = map f l in + let d' = f d in + let r' = map f r in + Node{l=l'; v; d=d'; r=r'; h} + + let rec mapi f = function + Empty -> + Empty + | Node {l; v; d; r; h} -> + let l' = mapi f l in + let d' = f v d in + let r' = mapi f r in + Node{l=l'; v; d=d'; r=r'; h} + + let rec fold f m accu = + match m with + Empty -> accu + | Node {l; v; d; r} -> + fold f r (f v d (fold f l accu)) + + let rec for_all p = function + Empty -> true + | Node {l; v; d; r} -> p v d && for_all p l && for_all p r + + let rec exists p = function + Empty -> false + | Node {l; v; d; r} -> p v d || exists p l || exists p r + + (* Beware: those two functions assume that the added k is *strictly* + smaller (or bigger) than all the present keys in the tree; it + does not test for equality with the current min (or max) key. + + Indeed, they are only used during the "join" operation which + respects this precondition. + *) + + let rec add_min_binding k x = function + | Empty -> singleton k x + | Node {l; v; d; r} -> + bal (add_min_binding k x l) v d r + + let rec add_max_binding k x = function + | Empty -> singleton k x + | Node {l; v; d; r} -> + bal l v d (add_max_binding k x r) + + (* Same as create and bal, but no assumptions are made on the + relative heights of l and r. *) + + let rec join l v d r = + match (l, r) with + (Empty, _) -> add_min_binding v d r + | (_, Empty) -> add_max_binding v d l + | (Node{l=ll; v=lv; d=ld; r=lr; h=lh}, + Node{l=rl; v=rv; d=rd; r=rr; h=rh}) -> + if lh > rh + 2 then bal ll lv ld (join lr v d r) else + if rh > lh + 2 then bal (join l v d rl) rv rd rr else + create l v d r + + (* Merge two trees l and r into one. + All elements of l must precede the elements of r. + No assumption on the heights of l and r. *) + + let concat t1 t2 = + match (t1, t2) with + (Empty, t) -> t + | (t, Empty) -> t + | (_, _) -> + let (x, d) = min_binding t2 in + join t1 x d (remove_min_binding t2) + + let concat_or_join t1 v d t2 = + match d with + | Some d -> join t1 v d t2 + | None -> concat t1 t2 + + let rec split x = function + Empty -> + (Empty, None, Empty) + | Node {l; v; d; r} -> + let c = Ord.compare x v in + if c = 0 then (l, Some d, r) + else if c < 0 then + let (ll, pres, rl) = split x l in (ll, pres, join rl v d r) + else + let (lr, pres, rr) = split x r in (join l v d lr, pres, rr) + + let rec merge f s1 s2 = + match (s1, s2) with + (Empty, Empty) -> Empty + | (Node {l=l1; v=v1; d=d1; r=r1; h=h1}, _) when h1 >= height s2 -> + let (l2, d2, r2) = split v1 s2 in + concat_or_join (merge f l1 l2) v1 (f v1 (Some d1) d2) (merge f r1 r2) + | (_, Node {l=l2; v=v2; d=d2; r=r2}) -> + let (l1, d1, r1) = split v2 s1 in + concat_or_join (merge f l1 l2) v2 (f v2 d1 (Some d2)) (merge f r1 r2) + | _ -> + assert false + + let rec union f s1 s2 = + match (s1, s2) with + | (Empty, s) | (s, Empty) -> s + | (Node {l=l1; v=v1; d=d1; r=r1; h=h1}, + Node {l=l2; v=v2; d=d2; r=r2; h=h2}) -> + if h1 >= h2 then + let (l2, d2, r2) = split v1 s2 in + let l = union f l1 l2 and r = union f r1 r2 in + match d2 with + | None -> join l v1 d1 r + | Some d2 -> concat_or_join l v1 (f v1 d1 d2) r + else + let (l1, d1, r1) = split v2 s1 in + let l = union f l1 l2 and r = union f r1 r2 in + match d1 with + | None -> join l v2 d2 r + | Some d1 -> concat_or_join l v2 (f v2 d1 d2) r + + let rec filter p = function + Empty -> Empty + | Node {l; v; d; r} as m -> + (* call [p] in the expected left-to-right order *) + let l' = filter p l in + let pvd = p v d in + let r' = filter p r in + if pvd then if l==l' && r==r' then m else join l' v d r' + else concat l' r' + + let rec filter_map f = function + Empty -> Empty + | Node {l; v; d; r} -> + (* call [f] in the expected left-to-right order *) + let l' = filter_map f l in + let fvd = f v d in + let r' = filter_map f r in + begin match fvd with + | Some d' -> join l' v d' r' + | None -> concat l' r' + end + + let rec partition p = function + Empty -> (Empty, Empty) + | Node {l; v; d; r} -> + (* call [p] in the expected left-to-right order *) + let (lt, lf) = partition p l in + let pvd = p v d in + let (rt, rf) = partition p r in + if pvd + then (join lt v d rt, concat lf rf) + else (concat lt rt, join lf v d rf) + + type 'a enumeration = End | More of key * 'a * 'a t * 'a enumeration + + let rec cons_enum m e = + match m with + Empty -> e + | Node {l; v; d; r} -> cons_enum l (More(v, d, r, e)) + + let compare cmp m1 m2 = + let rec compare_aux e1 e2 = + match (e1, e2) with + (End, End) -> 0 + | (End, _) -> -1 + | (_, End) -> 1 + | (More(v1, d1, r1, e1), More(v2, d2, r2, e2)) -> + let c = Ord.compare v1 v2 in + if c <> 0 then c else + let c = cmp d1 d2 in + if c <> 0 then c else + compare_aux (cons_enum r1 e1) (cons_enum r2 e2) + in compare_aux (cons_enum m1 End) (cons_enum m2 End) + + let equal cmp m1 m2 = + let rec equal_aux e1 e2 = + match (e1, e2) with + (End, End) -> true + | (End, _) -> false + | (_, End) -> false + | (More(v1, d1, r1, e1), More(v2, d2, r2, e2)) -> + Ord.compare v1 v2 = 0 && cmp d1 d2 && + equal_aux (cons_enum r1 e1) (cons_enum r2 e2) + in equal_aux (cons_enum m1 End) (cons_enum m2 End) + + let rec cardinal = function + Empty -> 0 + | Node {l; r} -> cardinal l + 1 + cardinal r + + let rec bindings_aux accu = function + Empty -> accu + | Node {l; v; d; r} -> bindings_aux ((v, d) :: bindings_aux accu r) l + + let bindings s = + bindings_aux [] s + + let choose = min_binding + + let choose_opt = min_binding_opt + + let to_list = bindings + let of_list bs = List.fold_left (fun m (k, v) -> add k v m) empty bs + + let add_seq i m = + Seq.fold_left (fun m (k,v) -> add k v m) m i + + let of_seq i = add_seq i empty + + let rec seq_of_enum_ c () = match c with + | End -> Seq.Nil + | More (k,v,t,rest) -> Seq.Cons ((k,v), seq_of_enum_ (cons_enum t rest)) + + let to_seq m = + seq_of_enum_ (cons_enum m End) + + let rec snoc_enum s e = + match s with + Empty -> e + | Node{l; v; d; r} -> snoc_enum r (More(v, d, l, e)) + + let rec rev_seq_of_enum_ c () = match c with + | End -> Seq.Nil + | More (k,v,t,rest) -> + Seq.Cons ((k,v), rev_seq_of_enum_ (snoc_enum t rest)) + + let to_rev_seq c = + rev_seq_of_enum_ (snoc_enum c End) + + let to_seq_from low m = + let rec aux low m c = match m with + | Empty -> c + | Node {l; v; d; r; _} -> + begin match Ord.compare v low with + | 0 -> More (v, d, r, c) + | n when n<0 -> aux low r c + | _ -> aux low l (More (v, d, r, c)) + end + in + seq_of_enum_ (aux low m End) +end \ No newline at end of file diff --git a/lib/db/cache.ml b/lib/db/cache.ml index a5fb176b2a..3f1d98253d 100644 --- a/lib/db/cache.ml +++ b/lib/db/cache.ml @@ -1,24 +1,250 @@ -module type S = sig +open Common + +let clears = ref [] +let clear () = Common.List.iter (fun f -> f ()) !clears + +module type Elt = sig type t - val copy : t -> t + val equal : t -> t -> bool + val hash : t -> int + val sub : memo:(t -> t) -> t -> t end -module Make (Element : S) = struct +module type Memo = sig + type t + + val equal : t -> t -> bool + val hash : t -> int + val memo : t -> t +end + +module Make (Element : Elt) : Memo with type t = Element.t = struct + type t = Element.t + + let equal = Element.equal + let hash = Element.hash + module H = Hashtbl.Make (struct type t = Element.t - let equal = ( = ) - let hash = Hashtbl.hash + let equal = Element.equal + let hash = Element.hash end) let cache = H.create 16 - let clear () = H.clear cache + let () = clears := (fun () -> H.clear cache) :: !clears - let memo str = + let rec memo str = try H.find cache str with Not_found -> - let str = Element.copy str in + let str = Element.sub ~memo str in H.add cache str str ; str end + +module Make_sub_only (Element : Elt) : Memo with type t = Element.t = struct + type t = Element.t + + let equal = ( = ) + let hash = Hashtbl.hash + let rec memo str = Element.sub ~memo str +end + +(** This module does not use {!Make} because it does not actually cache anything, + its just here for composition. *) +module Char = struct + type t = char + + let equal = Char.equal + let hash = Hashtbl.hash + let memo c = c + + module Map = Char.Map + module Array_map = Char.Array_map +end + +module String = Make (struct + type t = string + + let hash = Hashtbl.hash + let equal = String.equal + let sub ~memo:_ str = String.init (String.length str) (String.get str) +end) + +module List (A : Memo) = Make (struct + type t = A.t list + + let hash li = li |> List.map A.hash |> Hashtbl.hash + let equal = List.equal A.equal + + let rec sub ~memo lst = + match lst with + | [] -> [] + | x :: xs -> A.memo x :: memo (sub ~memo xs) +end) + +module Array (A : Memo) = Make (struct + type t = A.t array + + let equal = Array.equal A.equal + let hash = Array.hash A.hash + let sub ~memo:_ arr = arr +end) + +module Char_list = List (Char) +module String_list = List (String) +module String_list_list = List (String_list) + +module Elt = struct + include Make (struct + include Elt + + let sub ~memo:_ { name; kind; has_doc; pkg; json_display } = + let name = String.memo name in + let json_display = String.memo json_display in + { name; kind; has_doc; pkg; json_display } + end) + + module Set = Elt.Set +end + +module Elt_array = Array (Elt) + +module Set (A : Memo) (S : Set.S with type elt = A.t) = Make (struct + type t = S.t + + let equal = S.equal + + let hash m = + m |> S.elements |> Common.List.map (fun v -> A.hash v) |> Hashtbl.hash + + let sub ~memo:_ = S.map A.memo +end) + +module Map (A : Memo) (M : Map.S) = Make (struct + type t = A.t M.t + + let equal = M.equal A.equal + + let hash m = + m |> M.bindings + |> Common.List.map (fun (k, v) -> k, A.hash v) + |> Hashtbl.hash + + let sub ~memo m = match m with + M.Empty -> M.Empty + | M.Node {l; v; d; r; h} -> + let l = memo l in + let r = memo r in + let d = A.memo d in + M.Node {l; v; d; r; h} +end) + +module Array_map (A : Memo) (M : Array_map.S) = Make (struct + type t = A.t M.t + + let equal = M.equal A.equal + + let hash m = + m |> M.to_array + |> Common.Array.map (fun (k, v) -> k, A.hash v) + |> Hashtbl.hash + + let sub ~memo:_ m = M.map ~f:A.memo m +end) + +module Elt_set = Set (Elt) (Elt.Set) + +module Option (A : Memo) = Make (struct + type t = A.t option + + let equal = Option.equal A.equal + + let hash opt = + match opt with + | None -> Hashtbl.hash None + | Some a -> Hashtbl.hash (Some (A.hash a)) + + let sub ~memo:_ opt = + match opt with + | Some a -> Some (A.memo a) + | None -> None +end) + +module Elt_set_option = Option (Elt_set) +module Char_map (A : Memo) = Map (A) (Char.Map) +module Int_map (A : Memo) = Map (A) (Int.Map) +module Char_array_map (A : Memo) = Array_map (A) (Char.Array_map) +module Elt_array_occ = Int_map(Elt_array) +module Elt_set_occ = Int_map (Elt_set) +module Elt_set_char_map = Char_map (Elt_set) + +module Trie_gen (A : Memo) : Memo with type t = A.t Trie_gen.t = struct + module rec M : (Memo with type t = A.t Trie_gen.t) = Make_sub_only (struct + module Map = Char_map (A) + module Option = Option (A) + + type t = A.t Trie_gen.t + + let equal = ( = ) + + let hash trie = + let open Trie_gen in + match trie with + | Leaf _ -> Hashtbl.hash trie + | Node { leaf; children } -> + Hashtbl.hash (Hashtbl.hash leaf, Children.hash children) + + let sub ~memo:_ trie = + let open Trie_gen in + match trie with + | Leaf (chars, elts) -> Leaf (Char_list.memo chars, A.memo elts) + | Node { leaf; children } -> + let leaf = Option.memo leaf in + let children = Children.memo children in + Node { leaf; children } + end) + + and Children : (Memo with type t = A.t Trie_gen.t Char.Map.t) = Char_map (M) + + include M +end + +module Trie_compact (A : Memo) : Memo with type t = A.t Trie_compact.t = struct + module rec M : (Memo with type t = A.t Trie_compact.t) = Make_sub_only (struct + module Map = Char_map (A) + module Option = Option (A) + + type t = A.t Trie_compact.t + + let equal = ( = ) + + let hash trie = + let open Trie_compact in + match trie with + | Leaf _ -> Hashtbl.hash trie + | Node { leaf; children } -> + Hashtbl.hash (Hashtbl.hash leaf, Children.hash children) + + let sub ~memo:_ trie = + let open Trie_compact in + match trie with + | Leaf (chars, elts) -> Leaf (String.memo chars, A.memo elts) + | Node { leaf; children } -> + let leaf = Option.memo leaf in + let children = Children.memo children in + Node { leaf; children } + end) + + and Children : (Memo with type t = A.t Trie_compact.t Char.Array_map.t) = + Char_array_map (M) + + include M +end + +module Elt_set_trie_gen = Trie_gen (Elt_set) +module Elt_set_occ_trie_gen = Trie_gen (Elt_set_occ) + +module Elt_array_trie_gen = Trie_gen (Elt_array) +module Elt_array_occ_trie_gen = Trie_gen (Elt_array_occ) \ No newline at end of file diff --git a/lib/db/cache.mli b/lib/db/cache.mli index a8186687de..74b2e9c4a1 100644 --- a/lib/db/cache.mli +++ b/lib/db/cache.mli @@ -1,13 +1,23 @@ -module type S = sig +open Common + +val clear : unit -> unit + +module type Memo = sig type t - val copy : t -> t + val equal : t -> t -> bool + val hash : t -> int + val memo : t -> t end -module Make : functor (Element : S) -> sig - module H : Hashtbl.S with type key = Element.t +module String : Memo with type t = string +module Char_list : Memo with type t = char list +module String_list : Memo with type t = string list +module String_list_list : Memo with type t = string list list +module Elt_array : Memo with type t = Elt.t array +module Elt_set_trie_gen : Memo with type t = Elt.Set.t Trie_gen.t +module Elt_set_occ_trie_gen : Memo with type t = Elt.Set.t Int.Map.t Trie_gen.t +module Elt_array_trie_gen : Memo with type t = Elt.t Array.t Trie_gen.t - val cache : Element.t H.t - val clear : unit -> unit - val memo : H.key -> Element.t -end +module Elt_array_occ_trie_gen : + Memo with type t = Elt.t Array.t Int.Map.t Trie_gen.t diff --git a/lib/db/caches.ml b/lib/db/caches.ml deleted file mode 100644 index 3ad53df311..0000000000 --- a/lib/db/caches.ml +++ /dev/null @@ -1,88 +0,0 @@ -module String = Cache.Make (struct - type t = string - - let copy str = String.init (String.length str) (String.get str) -end) - -module Char_list = struct - module H = Hashtbl.Make (struct - type t = char list - - let equal = List.equal Char.equal - let hash = Hashtbl.hash - end) - - let cache = H.create 128 - - let memo lst = - let rec go lst = - try H.find cache lst - with Not_found -> - let lst = - match lst with - | [] -> [] - | x :: xs -> x :: go xs - in - H.add cache lst lst ; - lst - in - go lst -end - -module String_list = struct - module H = Hashtbl.Make (struct - type t = string list - - let equal = List.equal Stdlib.String.equal - let hash = Hashtbl.hash - end) - - let cache = H.create 128 - - let memo lst = - let rec go lst = - try H.find cache lst - with Not_found -> - let lst = List.map String.memo lst in - let lst = - match lst with - | [] -> [] - | x :: xs -> x :: go xs - in - H.add cache lst lst ; - lst - in - go lst -end - -module Cache_string_list_list = struct - module H = Hashtbl.Make (struct - type t = string list list - - let equal = List.equal (List.equal Stdlib.String.equal) - let hash = Hashtbl.hash - end) - - let cache = H.create 128 - - let memo lst = - let rec go lst = - try H.find cache lst - with Not_found -> - let lst = List.map String_list.memo lst in - let lst = - match lst with - | [] -> [] - | x :: xs -> x :: go xs - in - H.add cache lst lst ; - lst - in - go lst -end - -module Array = Cache.Make (struct - type t = Elt.t array - - let copy = Fun.id -end) diff --git a/lib/db/db.ml b/lib/db/db.ml index 50990c7f40..02fe06cdc5 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -1,18 +1,44 @@ +open Common module Elt = Elt module Types = Types module Storage_toplevel = Storage -module Trie = Trie -module Caches = Caches +module Trie = Trie_gen +module Trie_gen = Trie_gen +module Trie_compact = Trie_compact +module Cache = Cache include Types +module Occ = Int.Map + +let compact db = + let open Types in + let { db_types; db_names } = db in + let db_types = + Trie_gen.map_leaf + ~f:(fun occs -> + Int.Map.map + (fun set -> + set |> Elt.Set.elements |> Array.of_list |> Cache.Elt_array.memo) + occs) + db_types + in + let db_names = + Trie_gen.map_leaf + ~f:(fun set -> + set |> Elt.Set.elements |> Array.of_list |> Cache.Elt_array.memo) + db_names + in + + let db_types = Cache.Elt_array_occ_trie_gen.memo db_types in + let db_names = Cache.Elt_array_trie_gen.memo db_names in + { db_types; db_names } let list_of_string s = List.init (String.length s) (String.get s) module type S = sig type writer - val optimize : unit -> unit val export : writer -> unit - val store_type : Elt.t -> char list list -> unit + val store_type_paths : Elt.t -> string list list -> unit val store_word : string -> Elt.t -> unit val load_counter : int ref end @@ -21,7 +47,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct type writer = Storage.writer let load_counter = ref 0 - let db = ref (Trie.empty ()) + let db_types = ref (Trie.empty ()) let db_names = ref (Trie.empty ()) module Hset2 = Hashtbl.Make (struct @@ -38,45 +64,12 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let equal (a, b) (a', b') = a == a' && b == b' end) - let elt_set_union ~hs a b = - try Hset2.find hs (a, b) - with Not_found -> - let r = Elt.Set.union a b in - Hset2.add hs (a, b) r ; - Hset2.add hs (b, a) r ; - r - - let occ_merge ~hs a b = - if a == b - then a - else - Occ.merge - (fun _ ox oy -> - match ox, oy with - | Some x, Some y -> Some (elt_set_union ~hs x y) - | opt, None | None, opt -> opt) - a b - - let occ_merge ~ho ~hs a b = - try Hocc2.find ho (a, b) - with Not_found -> - let r = occ_merge ~hs a b in - Hocc2.add ho (a, b) r ; - Hocc2.add ho (b, a) r ; - r - - let optimize () = - let ho = Hocc2.create 16 in - let hs = Hset2.create 16 in - let (_ : Elt.Set.t Occ.t option) = Trie.summarize (occ_merge ~ho ~hs) !db in - let (_ : Elt.Set.t option) = Trie.summarize (elt_set_union ~hs) !db_names in - () - let export h = load_counter := 0 ; - let t = { Storage_toplevel.db_types = !db; db_names = !db_names } in - Storage.save ~db:h t ; - db := Trie.empty () ; + let db = { db_types = !db_types; db_names = !db_names } in + let db = compact db in + Storage.save ~db:h db ; + db_types := Trie.empty () ; db_names := Trie.empty () module Hset = Hashtbl.Make (struct @@ -127,16 +120,24 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let db = Trie.add name (candidates_add ~ho ~hs elt ~count) db in go db next in - db := go !db name + db_types := go !db_types name - let store_type elt paths = + let store_type_paths elt paths = let ho = Hocc.create 16 in let hs = Hset.create 16 in List.iter (fun (path, count) -> - store ~ho ~hs ~count (Caches.Char_list.memo path) elt) + store ~ho ~hs ~count (Cache.Char_list.memo path) elt) (regroup_chars paths) + let store_type_paths elt paths = + store_type_paths elt + (List.map + (fun xs -> + let xs = List.concat_map list_of_string xs in + xs) + paths) + let store_chars name elt = let hs = Hset.create 16 in let rec go db = function @@ -149,7 +150,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct db_names := go !db_names name let store_word word elt = - (word |> list_of_string |> List.rev |> Caches.Char_list.memo |> store_chars) + (word |> list_of_string |> List.rev |> Cache.Char_list.memo |> store_chars) elt end diff --git a/lib/db/db.mli b/lib/db/db.mli index a5e7362e7f..210546d234 100644 --- a/lib/db/db.mli +++ b/lib/db/db.mli @@ -1,17 +1,23 @@ +open Common module Elt = Elt module Types = Types module Storage = Storage -module Trie = Trie -module Caches = Caches +module Trie_compact = Trie_compact +module Trie_gen = Trie_gen +module Cache = Cache + +type 'a t = 'a Types.t = + { db_types : 'a Int.Map.t Trie_gen.t + ; db_names : 'a Trie_gen.t + } val list_of_string : string -> char list module type S = sig type writer - val optimize : unit -> unit val export : writer -> unit - val store_type : Elt.t -> char list list -> unit + val store_type_paths : Elt.t -> string list list -> unit val store_word : string -> Elt.t -> unit val load_counter : int ref end diff --git a/lib/db/elt.ml b/lib/db/elt.ml index 752932fe21..d30a9af51c 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -71,6 +71,11 @@ end include T +let equal a b = compare a b = 0 +let hash : t -> int = Hashtbl.hash + +module Set = Set.Make (T) + let pkg_link { pkg; _ } = let open Option.O in let+ { name; version } = pkg in @@ -86,4 +91,33 @@ let link t = let+ pkg_link = pkg_link t in pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name -module Set = Set.Make (T) +module Kind = struct + type t = kind + + let doc = Doc + let type_decl = TypeDecl + let module_ = Module + let exception_ = Exception + let class_type = Class_type + let method_ = Method + let class_ = Class + let type_extension = TypeExtension + let extension_constructor = ExtensionConstructor + let module_type = ModuleType + let constructor type_path = Constructor type_path + let field type_path = Field type_path + let val_ type_path = Val type_path +end + +module Package = struct + type t = package + + let v ~name ~version = let version = version in + + { name; version } +end + +let v ~name ~kind ~has_doc ?(pkg = None) ~json_display () = + let name = name in + let json_display = json_display in + { name; kind; has_doc; pkg; json_display } diff --git a/lib/db/storage.ml b/lib/db/storage.ml index 10a54142e2..a7453725fc 100644 --- a/lib/db/storage.ml +++ b/lib/db/storage.ml @@ -1,13 +1,11 @@ -type t = - { db_types : Types.db - ; db_names : Elt.Set.t Trie.t - } + +type 'a db = 'a Types.t module type S = sig type writer val open_out : string -> writer - val save : db:writer -> t -> unit + val save : db:writer -> Elt.t array db -> unit val close_out : writer -> unit - val load : string -> t list + val load : string -> Elt.Set.t db list end diff --git a/lib/db/storage.mli b/lib/db/storage.mli deleted file mode 100644 index 10a54142e2..0000000000 --- a/lib/db/storage.mli +++ /dev/null @@ -1,13 +0,0 @@ -type t = - { db_types : Types.db - ; db_names : Elt.Set.t Trie.t - } - -module type S = sig - type writer - - val open_out : string -> writer - val save : db:writer -> t -> unit - val close_out : writer -> unit - val load : string -> t list -end diff --git a/lib/db/trie_compact.ml b/lib/db/trie_compact.ml new file mode 100644 index 0000000000..3ebab14392 --- /dev/null +++ b/lib/db/trie_compact.ml @@ -0,0 +1,61 @@ +open Common +module M = Char.Array_map + +type 'a t = + | Leaf of string * 'a + | Node of + { leaf : 'a option + ; children : 'a t M.t + } + +let empty () = Node { leaf = None; children = M.of_seq Seq.empty } +let string_of_list li = li |> List.to_seq |> String.of_seq + +let rec of_trie_gen trie_gen = + match trie_gen with + | Trie_gen.Leaf (chars, elt) -> Leaf (string_of_list chars, elt) + | Trie_gen.Node { leaf; children } -> + Node + { leaf + ; children = + children |> Char.Map.to_seq |> Char.Array_map.of_seq + |> Char.Array_map.map ~f:of_trie_gen + } + +let rec find ?(i = 0) path t = + match t, path with + | _, [] -> t + | Node node, p :: path -> begin + match M.find ~key:p node.children with + | Some child -> find path child + | None -> t + end + | Leaf (chars, _outcome), y :: ys when i < String.length chars && chars.[i] = y + -> + find ~i:(i + 1) ys t + | _ -> t + +let rec fold_map merge transform t = + match t with + | Leaf (_, outcome) -> Some (transform outcome) + | Node { leaf; children; _ } -> + let leaf = + match leaf with + | None -> None + | Some leaf -> Some (transform leaf) + in + M.fold + ~f:(fun ~key:_ ~acc child -> + let res = fold_map merge transform child in + match acc, res with + | None, opt | opt, None -> opt + | Some acc, Some res -> Some (merge acc res)) + ~init:leaf children + +let rec map_leaf ~f t = + match t with + | Leaf (v, outcome) -> Leaf (v, f outcome) + | Node { leaf; children } -> + let leaf = Option.map f leaf in + let children = M.map ~f:(map_leaf ~f) children in + Node { leaf; children } diff --git a/lib/db/trie.ml b/lib/db/trie_gen.ml similarity index 64% rename from lib/db/trie.ml rename to lib/db/trie_gen.ml index 6e3f786881..bd297d3161 100644 --- a/lib/db/trie.ml +++ b/lib/db/trie_gen.ml @@ -1,14 +1,14 @@ -module M = Map.Make (Char) +open Common +module M = Char.Map type 'a t = | Leaf of char list * 'a | Node of { leaf : 'a option - ; mutable summary : 'a option ; children : 'a t M.t } -let empty () = Node { leaf = None; summary = None; children = M.empty } +let empty () = Node { leaf = None; children = M.empty } let rec add path leaf t = match t, path with @@ -26,7 +26,6 @@ let rec add path leaf t = else Node { leaf = None - ; summary = None ; children = M.singleton x (add ys leaf (Leaf (xs, outcome))) } | Leaf (x :: xs, outcome), y :: ys -> @@ -34,18 +33,14 @@ let rec add path leaf t = let children = M.add y (Leaf (ys, leaf None)) @@ M.singleton x (Leaf (xs, outcome)) in - Node { leaf = None; summary = None; children } + Node { leaf = None; children } | Leaf ([], outcome), [] -> Leaf ([], leaf (Some outcome)) | Leaf ([], outcome), y :: ys -> Node - { leaf = Some outcome - ; summary = None - ; children = M.singleton y (Leaf (ys, leaf None)) - } + { leaf = Some outcome; children = M.singleton y (Leaf (ys, leaf None)) } | Leaf (y :: ys, outcome), [] -> Node { leaf = Some (leaf None) - ; summary = None ; children = M.singleton y (Leaf (ys, outcome)) } @@ -60,26 +55,9 @@ let rec find path t = | Leaf (x :: xs, outcome), y :: ys when x = y -> find ys (Leaf (xs, outcome)) | _ -> t -let rec summarize fn t = - match t with - | Leaf (_, outcome) -> Some outcome - | Node ({ leaf; children; _ } as it) -> - let sum = - M.fold - (fun _ c acc -> - let res = summarize fn c in - match acc, res with - | None, opt | opt, None -> opt - | Some acc, Some res -> Some (fn acc res)) - children leaf - in - it.summary <- sum ; - sum - let rec fold_map merge transform t = match t with - | Leaf (_, outcome) | Node { summary = Some outcome; _ } -> - Some (transform outcome) + | Leaf (_, outcome) -> Some (transform outcome) | Node { leaf; children; _ } -> let leaf = match leaf with @@ -87,8 +65,8 @@ let rec fold_map merge transform t = | Some leaf -> Some (transform leaf) in M.fold - (fun _ c acc -> - let res = fold_map merge transform c in + (fun _ child acc -> + let res = fold_map merge transform child in match acc, res with | None, opt | opt, None -> opt | Some acc, Some res -> Some (merge acc res)) @@ -97,9 +75,8 @@ let rec fold_map merge transform t = let rec map_leaf ~f t = match t with | Leaf (v, outcome) -> Leaf (v, f outcome) - | Node { leaf; children; summary } -> + | Node { leaf; children } -> let leaf = Option.map f leaf in - let summary = Option.map f summary in - let children = M.map (map_leaf ~f) children in - Node { leaf; children; summary } + Node { leaf; children } + diff --git a/lib/db/types.ml b/lib/db/types.ml index 734721bcc4..393bcada54 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -16,11 +16,6 @@ let regroup_chars lst = Char_list_map.add s (count + 1) acc) Char_list_map.empty lst -module Occ = Int.Map - -type candidates = Elt.Set.t Occ.t -type db = candidates Trie.t - type sgn = | Pos | Neg @@ -35,3 +30,8 @@ let sgn_not = function | Pos -> Neg | Neg -> Pos | Unknown -> Unknown + +type 'a t = + { db_types : 'a Int.Map.t Trie_gen.t + ; db_names : 'a Trie_gen.t + } diff --git a/lib/index_lib/index_lib.ml b/lib/index_lib/index_lib.ml index f4e72d42a3..02c0e72f1f 100644 --- a/lib/index_lib/index_lib.ml +++ b/lib/index_lib/index_lib.ml @@ -1,16 +1,17 @@ module Storage = Db.Storage let main ~index_docstring ~index_name ~type_search ~empty_payload ~index - ~db_filename ~optimize storage = + ~db_filename storage = + print_endline "Index_lib.main" ; let module Storage = (val storage : Storage.S) in let module Load_doc = Load_doc.Make (Storage) in let module Db = Load_doc.Db in let h = Storage.open_out db_filename in let flush () = - if optimize then Db.optimize () ; Load_doc.clear () ; Db.export h in Load_doc.run ~index_docstring ~index_name ~type_search ~empty_payload ~index ; + print_endline "doc loaded" ; flush () ; Storage.close_out h diff --git a/lib/index_lib/index_lib.mli b/lib/index_lib/index_lib.mli index 43778502ba..1d2730ace3 100644 --- a/lib/index_lib/index_lib.mli +++ b/lib/index_lib/index_lib.mli @@ -5,6 +5,5 @@ val main : -> empty_payload:bool -> index:Odoc_search.Entry.t list -> db_filename:string - -> optimize:bool -> (module Db.Storage.S) -> unit diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 3df1b0e918..0284df94e3 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -1,13 +1,13 @@ module Elt = Db.Elt module Db_common = Db -module Caches = Db.Caches +module Cache = Db.Cache module Make (Storage : Db.Storage.S) = struct module Types = Db.Types module Db = Db.Make (Storage) module ModuleName = Odoc_model.Names.ModuleName - let clear () = Caches.String.clear () + let clear () = Cache.clear () let rec type_size = function | Odoc_model.Lang.TypeExpr.Var _ -> 1 @@ -40,24 +40,20 @@ module Make (Storage : Db.Storage.S) = struct let r = match t with | Odoc_model.Lang.TypeExpr.Var _ -> - let poly = Caches.String.memo "POLY" in - [ poly :: Caches.String.memo (Types.string_of_sgn sgn) :: prefix ] + let poly = "POLY" in + [ poly :: Types.string_of_sgn sgn :: prefix ] | Any -> - let poly = Caches.String.memo "POLY" in - [ poly :: Caches.String.memo (Types.string_of_sgn sgn) :: prefix ] + let poly = "POLY" in + [ poly :: Types.string_of_sgn sgn :: prefix ] | Arrow (_, a, b) -> - let prefix_left = Caches.String.memo "->0" :: prefix in - let prefix_right = Caches.String.memo "->1" :: prefix in + let prefix_left = "->0" :: prefix in + let prefix_right = "->1" :: prefix in List.rev_append (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) (paths ~prefix:prefix_right ~sgn b) | Constr (name, args) -> let name = fullname name in - let prefix = - Caches.String.memo name - :: Caches.String.memo (Types.string_of_sgn sgn) - :: prefix - in + let prefix = name :: Types.string_of_sgn sgn :: prefix in begin match args with | [] -> [ prefix ] @@ -65,23 +61,19 @@ module Make (Storage : Db.Storage.S) = struct rev_concat @@ List.mapi (fun i arg -> - let prefix = - Caches.String.memo (string_of_int i) :: prefix - in + let prefix = string_of_int i :: prefix in paths ~prefix ~sgn arg) args end | Tuple args -> rev_concat @@ List.mapi (fun i arg -> - let prefix = - Caches.String.memo (string_of_int i ^ "*") :: prefix - in + let prefix = (string_of_int i ^ "*") :: prefix in paths ~prefix ~sgn arg) @@ args | _ -> [] in - Caches.Cache_string_list_list.memo r + Cache.String_list_list.memo r (** for indexing *) let rec type_paths ~prefix ~sgn = function @@ -113,7 +105,7 @@ module Make (Storage : Db.Storage.S) = struct | _ -> [] let type_paths ~prefix ~sgn t = - Caches.Cache_string_list_list.memo (type_paths ~prefix ~sgn t) + Cache.String_list_list.memo (type_paths ~prefix ~sgn t) let register_doc elt doc_txt = let doc_words = String.split_on_char ' ' doc_txt in @@ -177,18 +169,18 @@ module Make (Storage : Db.Storage.S) = struct | Module -> Elt.ModuleType | Value { value = _; type_ } -> let paths = paths ~prefix:[] ~sgn:Pos type_ in - Val paths + Elt.Kind.val_ paths | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in let type_paths = paths ~prefix:[] ~sgn:Pos searchable_type in - Constructor type_paths + Elt.Kind.constructor type_paths | Field { mutable_ = _; parent_type; type_ } -> let type_paths = type_ |> searchable_type_of_record parent_type |> paths ~prefix:[] ~sgn:Pos in - Field type_paths + Elt.Kind.field type_paths | Doc _ -> Doc | Exception _ -> Exception | Class_type _ -> Class_type @@ -200,14 +192,7 @@ module Make (Storage : Db.Storage.S) = struct let register_type_expr elt type_ = let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in - (* let str = String.concat "|" (List.concat_map (fun li -> ";" :: li) type_paths) in - print_endline str; *) - Db.store_type elt - (List.map - (fun xs -> - let xs = List.concat_map Db_common.list_of_string xs in - Caches.Char_list.memo xs) - type_paths) + Db.store_type_paths elt type_paths let register_kind ~type_search elt (kind : Odoc_search.Entry.extra) = let open Odoc_search.Entry in @@ -260,13 +245,15 @@ module Make (Storage : Db.Storage.S) = struct | Doc _ -> Pretty.prefixname id | _ -> full_name in + let name = name in let json_display = if empty_payload - then "" - else entry |> Json_display.of_entry |> Odoc_html.Json.to_string + then "" + else + entry |> Json_display.of_entry |> Odoc_html.Json.to_string in let has_doc = doc.txt <> "" in - let elt = Elt.{ name; kind = kind'; pkg = None; json_display; has_doc } in + let elt = Elt.v ~name ~kind:kind' ~json_display ~has_doc () in if index_docstring then register_doc elt doc.txt ; (if index_name then @@ -278,6 +265,7 @@ module Make (Storage : Db.Storage.S) = struct module Resolver = Odoc_odoc.Resolver let run ~index_docstring ~index_name ~type_search ~empty_payload ~index = + print_endline "loading doc !" ; List.iter (register_entry ~index_docstring ~index_name ~type_search ~empty_payload) index diff --git a/lib/query/query.ml b/lib/query/query.ml index c8a71e34e3..173fdccb0d 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -1,9 +1,11 @@ +open Common module Parser = Query_parser module Succ = Succ module Sort = Sort module Storage = Db.Storage -module Trie = Db.Trie +module Trie = Db.Trie_gen open Db.Types +module Occ = Int.Map let inter_list xs = List.fold_left Succ.inter Succ.all xs @@ -34,7 +36,7 @@ let collapse_trie_with_poly ~count name t = let find_inter ~shards names = List.fold_left (fun acc shard -> - let db = shard.Storage.db_types in + let db = shard.db_types in let r = inter_list @@ List.map @@ -54,7 +56,7 @@ let find_names ~shards names = in List.fold_left (fun acc shard -> - let db_names = shard.Storage.db_names in + let db_names = shard.db_names in let candidates = List.map (fun name -> diff --git a/lib/query/query.mli b/lib/query/query.mli index 4419273552..ec382c69a0 100644 --- a/lib/query/query.mli +++ b/lib/query/query.mli @@ -8,4 +8,4 @@ type t = ; limit : int } -val api : shards:Db.Storage.t list -> t -> string * Db.Elt.t list +val api : shards:Db.Elt.Set.t Db.t list -> t -> string * Db.Elt.t list diff --git a/lib/storage_ancient/storage_ancient.ml b/lib/storage_ancient/storage_ancient.ml index cf2f8f6a81..b244f992ea 100644 --- a/lib/storage_ancient/storage_ancient.ml +++ b/lib/storage_ancient/storage_ancient.ml @@ -12,13 +12,13 @@ let open_out filename = let ancient = Ancient.attach handle base_addr in { write_shard = 0; ancient } -let save ~db (t : Storage.t) = +let save ~db (t : Elt.t array Db.t) = ignore (Ancient.share db.ancient db.write_shard t) ; db.write_shard <- db.write_shard + 1 let close_out db = Ancient.detach db.ancient -type reader = { shards : Storage.t array } +type reader = { shards : Elt.Set.t Db.t array } let load_shard md shard = match Ancient.get md shard with diff --git a/lib/storage_js/storage_js.ml b/lib/storage_js/storage_js.ml index d7b6898a24..b001f88aa0 100644 --- a/lib/storage_js/storage_js.ml +++ b/lib/storage_js/storage_js.ml @@ -6,21 +6,6 @@ let open_out = open_out let close_out = close_out let save ~db t = - let t = - Db.Storage.( - ( Db.Trie.map_leaf - ~f:(fun occs -> - Int.Map.map - (fun set -> - set |> Db.Elt.Set.elements |> Array.of_list - |> Db.Caches.Array.memo) - occs) - t.db_types - , Db.Trie.map_leaf - ~f:(fun set -> - set |> Db.Elt.Set.elements |> Array.of_list |> Db.Caches.Array.memo) - t.db_names )) - in let str = Marshal.to_string t [] in let str = Base64.encode_string str in Printf.fprintf db "function sherlodoc_db () { return %S; }\n%!" str @@ -29,14 +14,14 @@ let load str = let str = Base64.decode_exn str in let db_types, db_names = Marshal.from_string str 0 in let db_types = - Db.Trie.map_leaf + Db.Trie_gen.map_leaf ~f:(fun occs -> Int.Map.map (fun arr -> arr |> Array.to_seq |> Db.Elt.Set.of_seq) occs) db_types in let db_names = - Db.Trie.map_leaf + Db.Trie_gen.map_leaf ~f:(fun arr -> arr |> Array.to_seq |> Db.Elt.Set.of_seq) db_names in - [ Db.Storage.{ db_types; db_names } ] + [ Db.{ db_types; db_names } ] diff --git a/static/packages.csv b/static/packages.csv index 8c91066bd1..be30b8b128 100644 --- a/static/packages.csv +++ b/static/packages.csv @@ -735,8 +735,8 @@ crypto x509 "Public Key Infrastructure (RFC 5280, PKCS) purely in OCaml" crypto xoshiro "Xoshiro PRNGs as drop-in replacements for Stdlib.Random" crypto xxhash "Bindings for xxHash, an extremely fast hash algorithm" crypto zxcvbn "Bindings for the zxcvbn password strength estimation library" -data aches "Caches (bounded-size stores) for in-memory values and for resources" -data aches-lwt "Caches (bounded-size stores) for Lwt promises" +data aches "Cache (bounded-size stores) for in-memory values and for resources" +data aches-lwt "Cache (bounded-size stores) for Lwt promises" data agrep "String searching with errors" data agrid "Adjustable grid (two dimensional array) library" data aliases "In memory indexes" @@ -921,7 +921,7 @@ data lascar "A library for manipulating Labeled Transition Systems in OCaml" data lazy-trie "Implementation of lazy prefix trees" data lockfree "Lock-free data structures for multicore OCaml" data lru-cache "A simple implementation of a LRU cache." -data lru "Scalable LRU caches" +data lru "Scalable LRU Cache" data memcpy "Safe and efficient copying between blocks of memory." data memo "Memoïzation library" data minivpt "Minimalist vantage point tree implementation in OCaml." @@ -957,7 +957,7 @@ data res "RES - Library for resizable, contiguous datastructures" data rfsm "A toolset for describing and simulating StateChart-like state diagrams" data rhythm "Data Structures and Algorithms implemented in Reason" data ringo "Bounded-length collections" -data ringo-lwt "Lwt-wrappers for Ringo caches" +data ringo-lwt "Lwt-wrappers for Ringo Cache" data roman "Manipulate roman numerals (ocaml.org dune/opam tutorial)" data rope "Ropes (\"heavyweight strings\")" data safa "Symbolic Algorithms for Finite Automata" diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index c2da9e0017..90ac1926c0 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -1,42 +1,21 @@ - $ cat $(find . -name '*.odocl') > megaodocl - $ du -sh megaodocl - 5.1M megaodocl - $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null - $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null - $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null - $ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -name '*.odocl') 2> /dev/null - $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null +wwwwwwwwwwwwwww - $ gzip -k db.js - $ gzip -k megaodocl - $ du -s *.js *.gz - 16744 db.js - 12852 db_empty_payload.js - 14876 db_no_docstring.js - 12304 db_no_name.js - 9988 db_no_type.js - 4332 db_only_names.js - 4084 db.js.gz - 1628 megaodocl.gz - - $ du -sh *.js *.gz - 17M db.js - 13M db_empty_payload.js - 15M db_no_docstring.js - 13M db_no_name.js - 9.8M db_no_type.js - 4.3M db_only_names.js - 4.0M db.js.gz - 1.6M megaodocl.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --with-search --output-dir html $f 2> /dev/null > done $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js $ du -sh html/index.js + 13M html/index.js $ ls html - 21M html/index.js + base + fonts + highlight.pack.js + index.js + katex.min.css + katex.min.js + odoc.css + odoc_search.js $ cp -r html /tmp $ firefox /tmp/html/base/index.html diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 975d8e8820..18a398fc3e 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -15,14 +15,17 @@ $ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . page-page.odocl page.mld $ sherlodoc_index --format=js --db=db.js *.odocl + Index_lib.main + loading doc ! + doc loaded $ du -sh db.js - 16K db.js + 12K db.js $ odoc html-generate --with-search --output-dir html main.odocl $ odoc html-generate --with-search --output-dir html page-page.odocl $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js $ du -sh html/index.js - 4.0M html/index.js + 4.1M html/index.js $ cp -r html /tmp $ firefox /tmp/html/Main/index.html From 19ce128700555ff43c346845ae6ba36582972857 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 2 Jun 2023 19:14:39 +0200 Subject: [PATCH 073/285] Uses the browser's decompress api Format for previous commit A bit of cleanup --- bin/JSherlodoc/dune | 2 +- bin/JSherlodoc/main.ml | 102 ++- lib/common/array_map.ml | 1 - lib/common/map.ml | 1065 ++++++++++++++++--------------- lib/common/set.ml | 638 ++++++++++++++++++ lib/db/cache.ml | 90 ++- lib/db/cache.mli | 10 +- lib/db/db.ml | 13 +- lib/db/db.mli | 7 +- lib/db/storage.ml | 1 - lib/db/{trie_gen.ml => trie.ml} | 1 - lib/db/trie_compact.ml | 61 -- lib/db/types.ml | 4 +- lib/index_lib/index_lib.ml | 2 +- lib/index_lib/load_doc.ml | 5 +- lib/query/query.ml | 2 +- lib/storage_js/dune | 2 +- lib/storage_js/storage_js.ml | 48 +- test/cram/base.t/run.t | 37 +- test/cram/simple.t/run.t | 64 +- 20 files changed, 1448 insertions(+), 707 deletions(-) create mode 100644 lib/common/set.ml rename lib/db/{trie_gen.ml => trie.ml} (99%) delete mode 100644 lib/db/trie_compact.ml diff --git a/bin/JSherlodoc/dune b/bin/JSherlodoc/dune index 6257027f04..8e863dabfe 100644 --- a/bin/JSherlodoc/dune +++ b/bin/JSherlodoc/dune @@ -1,4 +1,4 @@ (executable (name main) (modes js) - (libraries common tyxml query storage_js brr)) + (libraries common tyxml query storage_js brr checkseum.ocaml)) diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 2061ffab8f..70b67be471 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -1,6 +1,3 @@ -let db = - lazy (Storage_js.load Jv.(to_string @@ call global "sherlodoc_db" [||])) - let string_of_kind (kind : Db.Elt.kind) = let open Db.Elt in match kind with @@ -18,18 +15,103 @@ let string_of_kind (kind : Db.Elt.kind) = | Field _ -> "field" | Val _ -> "val" +let print_error e = + let open Jv.Error in + Printf.eprintf "Error : %s %s\n%s%!" + (Jstr.to_string @@ name e) + (Jstr.to_string @@ message e) + (Jstr.to_string @@ stack e) + +let new_ cl = Jv.(new' (get global cl)) + +let stream_of_string str = + let str = + str |> Brr.Tarray.of_binary_jstr |> Result.get_ok |> Brr.Tarray.to_jv + in + let stream = + new_ "ReadableStream" + Jv. + [| obj + [| ( "start" + , callback ~arity:1 (fun controller -> + let _ = call controller "enqueue" [| str |] in + let _ = call controller "close" [||] in + ()) ) + |] + |] + in + stream + +let don't_wait_for fut = Fut.await fut Fun.id + +let string_of_stream stream = + print_endline "string_of_stream" ; + let buffer = Buffer.create 128 in + let append str = + Buffer.add_string buffer (str |> Brr.Tarray.of_jv |> Brr.Tarray.to_string) + in + let open Jv in + let reader = call stream "getReader" [||] in + + let open Fut.Syntax in + let rec read_step obj = + let done_ = get obj "done" |> to_bool in + let str = get obj "value" in + if not done_ + then ( + append str ; + read ()) + else Fut.return () + and read () : unit Fut.t = + let read = call reader "read" [||] in + let promise = Fut.of_promise ~ok:Fun.id read in + Fut.bind promise (function + | Ok v -> + (* print_endline "Ok v" ; *) + read_step v + | Error e -> + print_endline "error in string_of_stream" ; + print_error e ; + Fut.return ()) + in + let+ () = read () in + let r = Buffer.contents buffer in + (* Printf.printf "Inflated to size %i\n%!" (String.length r) ; *) + r + +let inflate str = + (* print_endline "inflating" ; *) + let dekompressor = + Jv.(new_ "DecompressionStream" [| of_string "deflate" |]) + in + let str = Jv.(call global "atob" [| str |]) |> Jv.to_jstr in + (* Printf.printf "String has size %i\n%!" (str |> Jstr.length) ; *) + let stream = stream_of_string str in + let decompressed_stream = Jv.call stream "pipeThrough" [| dekompressor |] in + string_of_stream decompressed_stream + +let db = + Jv.(inflate @@ call global "sherlodoc_db" [||]) |> Fut.map Storage_js.load + let search message = + don't_wait_for + @@ + let open Fut.Syntax in + let+ db = db in let query = Jv.get message "data" in let query = query |> Jv.to_jstr |> Jstr.to_string in let _pretty_query, results = - Query.(api ~shards:(Lazy.force db) { query; packages = []; limit = 50 }) + Query.(api ~shards:db { query; packages = []; limit = 50 }) + in + let _ = + Jv.(apply (get global "postMessage")) + [| Jv.of_list + (fun Db.Elt.{ json_display; _ } -> + json_display |> Jstr.of_string |> Brr.Json.decode |> Result.get_ok) + results + |] in - Jv.(apply (get global "postMessage")) - [| Jv.of_list - (fun Db.Elt.{ json_display; _ } -> - json_display |> Jstr.of_string |> Brr.Json.decode |> Result.get_ok) - results - |] + () let main () = let module J' = Jstr in diff --git a/lib/common/array_map.ml b/lib/common/array_map.ml index f16282c941..d32c07562c 100644 --- a/lib/common/array_map.ml +++ b/lib/common/array_map.ml @@ -3,7 +3,6 @@ module type S = sig type 'a t val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool - val of_seq : (key * 'a) Seq.t -> 'a t val to_array : 'a t -> (key * 'a) array val find : key:key -> 'a t -> 'a option diff --git a/lib/common/map.ml b/lib/common/map.ml index dbe4d029ee..0e9b2db8d1 100644 --- a/lib/common/map.ml +++ b/lib/common/map.ml @@ -13,537 +13,542 @@ (* *) (**************************************************************************) [@@@warning "-9"] -module type OrderedType = - sig - type t - val compare: t -> t -> int - end - -module type S = - sig - type key - type !+'a t = - Empty - | Node of {l:'a t; v:key; d:'a; r:'a t; h:int} - val empty: 'a t - val add: key -> 'a -> 'a t -> 'a t - val add_to_list: key -> 'a -> 'a list t -> 'a list t - val update: key -> ('a option -> 'a option) -> 'a t -> 'a t - val singleton: key -> 'a -> 'a t - val remove: key -> 'a t -> 'a t - val merge: - (key -> 'a option -> 'b option -> 'c option) -> - 'a t -> 'b t -> 'c t - val union: (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t - val cardinal: 'a t -> int - val bindings: 'a t -> (key * 'a) list - val min_binding: 'a t -> (key * 'a) - val min_binding_opt: 'a t -> (key * 'a) option - val max_binding: 'a t -> (key * 'a) - val max_binding_opt: 'a t -> (key * 'a) option - val choose: 'a t -> (key * 'a) - val choose_opt: 'a t -> (key * 'a) option - val find: key -> 'a t -> 'a - val find_opt: key -> 'a t -> 'a option - val find_first: (key -> bool) -> 'a t -> key * 'a - val find_first_opt: (key -> bool) -> 'a t -> (key * 'a) option - val find_last: (key -> bool) -> 'a t -> key * 'a - val find_last_opt: (key -> bool) -> 'a t -> (key * 'a) option - val iter: (key -> 'a -> unit) -> 'a t -> unit - val fold: (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b - val map: ('a -> 'b) -> 'a t -> 'b t - val mapi: (key -> 'a -> 'b) -> 'a t -> 'b t - val filter: (key -> 'a -> bool) -> 'a t -> 'a t - val filter_map: (key -> 'a -> 'b option) -> 'a t -> 'b t - val partition: (key -> 'a -> bool) -> 'a t -> 'a t * 'a t - val split: key -> 'a t -> 'a t * 'a option * 'a t - val is_empty: 'a t -> bool - val mem: key -> 'a t -> bool - val equal: ('a -> 'a -> bool) -> 'a t -> 'a t -> bool - val compare: ('a -> 'a -> int) -> 'a t -> 'a t -> int - val for_all: (key -> 'a -> bool) -> 'a t -> bool - val exists: (key -> 'a -> bool) -> 'a t -> bool - val to_list : 'a t -> (key * 'a) list - val of_list : (key * 'a) list -> 'a t - val to_seq : 'a t -> (key * 'a) Seq.t - val to_rev_seq : 'a t -> (key * 'a) Seq.t - val to_seq_from : key -> 'a t -> (key * 'a) Seq.t - val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t - val of_seq : (key * 'a) Seq.t -> 'a t - end - -module Make(Ord: OrderedType) = struct - - type key = Ord.t - - type 'a t = - Empty - | Node of {l:'a t; v:key; d:'a; r:'a t; h:int} - - let height = function - Empty -> 0 - | Node {h} -> h - - let create l x d r = - let hl = height l and hr = height r in - Node{l; v=x; d; r; h=(if hl >= hr then hl + 1 else hr + 1)} - - let singleton x d = Node{l=Empty; v=x; d; r=Empty; h=1} - - let bal l x d r = - let hl = match l with Empty -> 0 | Node {h} -> h in - let hr = match r with Empty -> 0 | Node {h} -> h in - if hl > hr + 2 then begin - match l with - Empty -> invalid_arg "Map.bal" - | Node{l=ll; v=lv; d=ld; r=lr} -> - if height ll >= height lr then - create ll lv ld (create lr x d r) - else begin - match lr with - Empty -> invalid_arg "Map.bal" - | Node{l=lrl; v=lrv; d=lrd; r=lrr}-> - create (create ll lv ld lrl) lrv lrd (create lrr x d r) - end - end else if hr > hl + 2 then begin - match r with - Empty -> invalid_arg "Map.bal" - | Node{l=rl; v=rv; d=rd; r=rr} -> - if height rr >= height rl then - create (create l x d rl) rv rd rr - else begin - match rl with - Empty -> invalid_arg "Map.bal" - | Node{l=rll; v=rlv; d=rld; r=rlr} -> - create (create l x d rll) rlv rld (create rlr rv rd rr) - end - end else - Node{l; v=x; d; r; h=(if hl >= hr then hl + 1 else hr + 1)} - - let empty = Empty - - let is_empty = function Empty -> true | _ -> false - - let rec add x data = function - Empty -> - Node{l=Empty; v=x; d=data; r=Empty; h=1} - | Node {l; v; d; r; h} as m -> - let c = Ord.compare x v in - if c = 0 then - if d == data then m else Node{l; v=x; d=data; r; h} - else if c < 0 then - let ll = add x data l in - if l == ll then m else bal ll v d r - else - let rr = add x data r in - if r == rr then m else bal l v d rr - - let rec find x = function - Empty -> - raise Not_found - | Node {l; v; d; r} -> - let c = Ord.compare x v in - if c = 0 then d - else find x (if c < 0 then l else r) - - let rec find_first_aux v0 d0 f = function - Empty -> - (v0, d0) - | Node {l; v; d; r} -> - if f v then - find_first_aux v d f l - else - find_first_aux v0 d0 f r - - let rec find_first f = function - Empty -> - raise Not_found - | Node {l; v; d; r} -> - if f v then - find_first_aux v d f l - else - find_first f r - - let rec find_first_opt_aux v0 d0 f = function - Empty -> - Some (v0, d0) - | Node {l; v; d; r} -> - if f v then - find_first_opt_aux v d f l - else - find_first_opt_aux v0 d0 f r - - let rec find_first_opt f = function - Empty -> - None - | Node {l; v; d; r} -> - if f v then - find_first_opt_aux v d f l - else - find_first_opt f r - - let rec find_last_aux v0 d0 f = function - Empty -> - (v0, d0) - | Node {l; v; d; r} -> - if f v then - find_last_aux v d f r - else - find_last_aux v0 d0 f l - - let rec find_last f = function - Empty -> - raise Not_found - | Node {l; v; d; r} -> - if f v then - find_last_aux v d f r - else - find_last f l - - let rec find_last_opt_aux v0 d0 f = function - Empty -> - Some (v0, d0) - | Node {l; v; d; r} -> - if f v then - find_last_opt_aux v d f r - else - find_last_opt_aux v0 d0 f l - - let rec find_last_opt f = function - Empty -> - None - | Node {l; v; d; r} -> - if f v then - find_last_opt_aux v d f r - else - find_last_opt f l - - let rec find_opt x = function - Empty -> - None - | Node {l; v; d; r} -> - let c = Ord.compare x v in - if c = 0 then Some d - else find_opt x (if c < 0 then l else r) - - let rec mem x = function - Empty -> - false - | Node {l; v; r} -> - let c = Ord.compare x v in - c = 0 || mem x (if c < 0 then l else r) - - let rec min_binding = function - Empty -> raise Not_found - | Node {l=Empty; v; d} -> (v, d) - | Node {l} -> min_binding l - - let rec min_binding_opt = function - Empty -> None - | Node {l=Empty; v; d} -> Some (v, d) - | Node {l}-> min_binding_opt l - - let rec max_binding = function - Empty -> raise Not_found - | Node {v; d; r=Empty} -> (v, d) - | Node {r} -> max_binding r - - let rec max_binding_opt = function - Empty -> None - | Node {v; d; r=Empty} -> Some (v, d) - | Node {r} -> max_binding_opt r - - let rec remove_min_binding = function - Empty -> invalid_arg "Map.remove_min_elt" - | Node {l=Empty; r} -> r - | Node {l; v; d; r} -> bal (remove_min_binding l) v d r - - let merge t1 t2 = - match (t1, t2) with - (Empty, t) -> t - | (t, Empty) -> t - | (_, _) -> - let (x, d) = min_binding t2 in - bal t1 x d (remove_min_binding t2) - - let rec remove x = function - Empty -> - Empty - | (Node {l; v; d; r} as m) -> - let c = Ord.compare x v in - if c = 0 then merge l r - else if c < 0 then - let ll = remove x l in if l == ll then m else bal ll v d r - else - let rr = remove x r in if r == rr then m else bal l v d rr - let rec update x f = function - Empty -> - begin match f None with - | None -> Empty - | Some data -> Node{l=Empty; v=x; d=data; r=Empty; h=1} +module type OrderedType = sig + type t + + val compare : t -> t -> int +end + +module type S = sig + type key + + type !+'a t = + | Empty + | Node of + { l : 'a t + ; v : key + ; d : 'a + ; r : 'a t + ; h : int + } + + val empty : 'a t + val add : key -> 'a -> 'a t -> 'a t + val add_to_list : key -> 'a -> 'a list t -> 'a list t + val update : key -> ('a option -> 'a option) -> 'a t -> 'a t + val singleton : key -> 'a -> 'a t + val remove : key -> 'a t -> 'a t + + val merge : + (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t + + val union : (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t + val cardinal : 'a t -> int + val bindings : 'a t -> (key * 'a) list + val min_binding : 'a t -> key * 'a + val min_binding_opt : 'a t -> (key * 'a) option + val max_binding : 'a t -> key * 'a + val max_binding_opt : 'a t -> (key * 'a) option + val choose : 'a t -> key * 'a + val choose_opt : 'a t -> (key * 'a) option + val find : key -> 'a t -> 'a + val find_opt : key -> 'a t -> 'a option + val find_first : (key -> bool) -> 'a t -> key * 'a + val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option + val find_last : (key -> bool) -> 'a t -> key * 'a + val find_last_opt : (key -> bool) -> 'a t -> (key * 'a) option + val iter : (key -> 'a -> unit) -> 'a t -> unit + val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b + val map : ('a -> 'b) -> 'a t -> 'b t + val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t + val filter : (key -> 'a -> bool) -> 'a t -> 'a t + val filter_map : (key -> 'a -> 'b option) -> 'a t -> 'b t + val partition : (key -> 'a -> bool) -> 'a t -> 'a t * 'a t + val split : key -> 'a t -> 'a t * 'a option * 'a t + val is_empty : 'a t -> bool + val mem : key -> 'a t -> bool + val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int + val for_all : (key -> 'a -> bool) -> 'a t -> bool + val exists : (key -> 'a -> bool) -> 'a t -> bool + val to_list : 'a t -> (key * 'a) list + val of_list : (key * 'a) list -> 'a t + val to_seq : 'a t -> (key * 'a) Seq.t + val to_rev_seq : 'a t -> (key * 'a) Seq.t + val to_seq_from : key -> 'a t -> (key * 'a) Seq.t + val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t + val of_seq : (key * 'a) Seq.t -> 'a t +end + +module Make (Ord : OrderedType) = struct + type key = Ord.t + + type 'a t = + | Empty + | Node of + { l : 'a t + ; v : key + ; d : 'a + ; r : 'a t + ; h : int + } + + let height = function + | Empty -> 0 + | Node { h } -> h + + let create l x d r = + let hl = height l and hr = height r in + Node { l; v = x; d; r; h = (if hl >= hr then hl + 1 else hr + 1) } + + let singleton x d = Node { l = Empty; v = x; d; r = Empty; h = 1 } + + let bal l x d r = + let hl = + match l with + | Empty -> 0 + | Node { h } -> h + in + let hr = + match r with + | Empty -> 0 + | Node { h } -> h + in + if hl > hr + 2 + then begin + match l with + | Empty -> invalid_arg "Map.bal" + | Node { l = ll; v = lv; d = ld; r = lr } -> + if height ll >= height lr + then create ll lv ld (create lr x d r) + else begin + match lr with + | Empty -> invalid_arg "Map.bal" + | Node { l = lrl; v = lrv; d = lrd; r = lrr } -> + create (create ll lv ld lrl) lrv lrd (create lrr x d r) end - | Node {l; v; d; r; h} as m -> - let c = Ord.compare x v in - if c = 0 then begin - match f (Some d) with - | None -> merge l r - | Some data -> - if d == data then m else Node{l; v=x; d=data; r; h} - end else if c < 0 then - let ll = update x f l in - if l == ll then m else bal ll v d r - else - let rr = update x f r in - if r == rr then m else bal l v d rr - - let add_to_list x data m = - let add = function None -> Some [data] | Some l -> Some (data :: l) in - update x add m - - let rec iter f = function - Empty -> () - | Node {l; v; d; r} -> - iter f l; f v d; iter f r - - let rec map f = function - Empty -> - Empty - | Node {l; v; d; r; h} -> - let l' = map f l in - let d' = f d in - let r' = map f r in - Node{l=l'; v; d=d'; r=r'; h} - - let rec mapi f = function - Empty -> - Empty - | Node {l; v; d; r; h} -> - let l' = mapi f l in - let d' = f v d in - let r' = mapi f r in - Node{l=l'; v; d=d'; r=r'; h} - - let rec fold f m accu = - match m with - Empty -> accu - | Node {l; v; d; r} -> - fold f r (f v d (fold f l accu)) - - let rec for_all p = function - Empty -> true - | Node {l; v; d; r} -> p v d && for_all p l && for_all p r - - let rec exists p = function - Empty -> false - | Node {l; v; d; r} -> p v d || exists p l || exists p r - - (* Beware: those two functions assume that the added k is *strictly* - smaller (or bigger) than all the present keys in the tree; it - does not test for equality with the current min (or max) key. - - Indeed, they are only used during the "join" operation which - respects this precondition. - *) - - let rec add_min_binding k x = function - | Empty -> singleton k x - | Node {l; v; d; r} -> - bal (add_min_binding k x l) v d r - - let rec add_max_binding k x = function - | Empty -> singleton k x - | Node {l; v; d; r} -> - bal l v d (add_max_binding k x r) - - (* Same as create and bal, but no assumptions are made on the - relative heights of l and r. *) - - let rec join l v d r = - match (l, r) with - (Empty, _) -> add_min_binding v d r - | (_, Empty) -> add_max_binding v d l - | (Node{l=ll; v=lv; d=ld; r=lr; h=lh}, - Node{l=rl; v=rv; d=rd; r=rr; h=rh}) -> - if lh > rh + 2 then bal ll lv ld (join lr v d r) else - if rh > lh + 2 then bal (join l v d rl) rv rd rr else - create l v d r - - (* Merge two trees l and r into one. - All elements of l must precede the elements of r. - No assumption on the heights of l and r. *) - - let concat t1 t2 = - match (t1, t2) with - (Empty, t) -> t - | (t, Empty) -> t - | (_, _) -> - let (x, d) = min_binding t2 in - join t1 x d (remove_min_binding t2) - - let concat_or_join t1 v d t2 = - match d with - | Some d -> join t1 v d t2 - | None -> concat t1 t2 - - let rec split x = function - Empty -> - (Empty, None, Empty) - | Node {l; v; d; r} -> - let c = Ord.compare x v in - if c = 0 then (l, Some d, r) - else if c < 0 then - let (ll, pres, rl) = split x l in (ll, pres, join rl v d r) - else - let (lr, pres, rr) = split x r in (join l v d lr, pres, rr) - - let rec merge f s1 s2 = - match (s1, s2) with - (Empty, Empty) -> Empty - | (Node {l=l1; v=v1; d=d1; r=r1; h=h1}, _) when h1 >= height s2 -> - let (l2, d2, r2) = split v1 s2 in - concat_or_join (merge f l1 l2) v1 (f v1 (Some d1) d2) (merge f r1 r2) - | (_, Node {l=l2; v=v2; d=d2; r=r2}) -> - let (l1, d1, r1) = split v2 s1 in - concat_or_join (merge f l1 l2) v2 (f v2 d1 (Some d2)) (merge f r1 r2) - | _ -> - assert false - - let rec union f s1 s2 = - match (s1, s2) with - | (Empty, s) | (s, Empty) -> s - | (Node {l=l1; v=v1; d=d1; r=r1; h=h1}, - Node {l=l2; v=v2; d=d2; r=r2; h=h2}) -> - if h1 >= h2 then - let (l2, d2, r2) = split v1 s2 in - let l = union f l1 l2 and r = union f r1 r2 in - match d2 with - | None -> join l v1 d1 r - | Some d2 -> concat_or_join l v1 (f v1 d1 d2) r - else - let (l1, d1, r1) = split v2 s1 in - let l = union f l1 l2 and r = union f r1 r2 in - match d1 with - | None -> join l v2 d2 r - | Some d1 -> concat_or_join l v2 (f v2 d1 d2) r - - let rec filter p = function - Empty -> Empty - | Node {l; v; d; r} as m -> - (* call [p] in the expected left-to-right order *) - let l' = filter p l in - let pvd = p v d in - let r' = filter p r in - if pvd then if l==l' && r==r' then m else join l' v d r' - else concat l' r' - - let rec filter_map f = function - Empty -> Empty - | Node {l; v; d; r} -> - (* call [f] in the expected left-to-right order *) - let l' = filter_map f l in - let fvd = f v d in - let r' = filter_map f r in - begin match fvd with - | Some d' -> join l' v d' r' - | None -> concat l' r' + end + else if hr > hl + 2 + then begin + match r with + | Empty -> invalid_arg "Map.bal" + | Node { l = rl; v = rv; d = rd; r = rr } -> + if height rr >= height rl + then create (create l x d rl) rv rd rr + else begin + match rl with + | Empty -> invalid_arg "Map.bal" + | Node { l = rll; v = rlv; d = rld; r = rlr } -> + create (create l x d rll) rlv rld (create rlr rv rd rr) end - - let rec partition p = function - Empty -> (Empty, Empty) - | Node {l; v; d; r} -> - (* call [p] in the expected left-to-right order *) - let (lt, lf) = partition p l in - let pvd = p v d in - let (rt, rf) = partition p r in - if pvd - then (join lt v d rt, concat lf rf) - else (concat lt rt, join lf v d rf) - - type 'a enumeration = End | More of key * 'a * 'a t * 'a enumeration - - let rec cons_enum m e = - match m with - Empty -> e - | Node {l; v; d; r} -> cons_enum l (More(v, d, r, e)) - - let compare cmp m1 m2 = - let rec compare_aux e1 e2 = - match (e1, e2) with - (End, End) -> 0 - | (End, _) -> -1 - | (_, End) -> 1 - | (More(v1, d1, r1, e1), More(v2, d2, r2, e2)) -> - let c = Ord.compare v1 v2 in - if c <> 0 then c else + end + else Node { l; v = x; d; r; h = (if hl >= hr then hl + 1 else hr + 1) } + + let empty = Empty + + let is_empty = function + | Empty -> true + | _ -> false + + let rec add x data = function + | Empty -> Node { l = Empty; v = x; d = data; r = Empty; h = 1 } + | Node { l; v; d; r; h } as m -> + let c = Ord.compare x v in + if c = 0 + then if d == data then m else Node { l; v = x; d = data; r; h } + else if c < 0 + then + let ll = add x data l in + if l == ll then m else bal ll v d r + else + let rr = add x data r in + if r == rr then m else bal l v d rr + + let rec find x = function + | Empty -> raise Not_found + | Node { l; v; d; r } -> + let c = Ord.compare x v in + if c = 0 then d else find x (if c < 0 then l else r) + + let rec find_first_aux v0 d0 f = function + | Empty -> v0, d0 + | Node { l; v; d; r } -> + if f v then find_first_aux v d f l else find_first_aux v0 d0 f r + + let rec find_first f = function + | Empty -> raise Not_found + | Node { l; v; d; r } -> + if f v then find_first_aux v d f l else find_first f r + + let rec find_first_opt_aux v0 d0 f = function + | Empty -> Some (v0, d0) + | Node { l; v; d; r } -> + if f v then find_first_opt_aux v d f l else find_first_opt_aux v0 d0 f r + + let rec find_first_opt f = function + | Empty -> None + | Node { l; v; d; r } -> + if f v then find_first_opt_aux v d f l else find_first_opt f r + + let rec find_last_aux v0 d0 f = function + | Empty -> v0, d0 + | Node { l; v; d; r } -> + if f v then find_last_aux v d f r else find_last_aux v0 d0 f l + + let rec find_last f = function + | Empty -> raise Not_found + | Node { l; v; d; r } -> + if f v then find_last_aux v d f r else find_last f l + + let rec find_last_opt_aux v0 d0 f = function + | Empty -> Some (v0, d0) + | Node { l; v; d; r } -> + if f v then find_last_opt_aux v d f r else find_last_opt_aux v0 d0 f l + + let rec find_last_opt f = function + | Empty -> None + | Node { l; v; d; r } -> + if f v then find_last_opt_aux v d f r else find_last_opt f l + + let rec find_opt x = function + | Empty -> None + | Node { l; v; d; r } -> + let c = Ord.compare x v in + if c = 0 then Some d else find_opt x (if c < 0 then l else r) + + let rec mem x = function + | Empty -> false + | Node { l; v; r } -> + let c = Ord.compare x v in + c = 0 || mem x (if c < 0 then l else r) + + let rec min_binding = function + | Empty -> raise Not_found + | Node { l = Empty; v; d } -> v, d + | Node { l } -> min_binding l + + let rec min_binding_opt = function + | Empty -> None + | Node { l = Empty; v; d } -> Some (v, d) + | Node { l } -> min_binding_opt l + + let rec max_binding = function + | Empty -> raise Not_found + | Node { v; d; r = Empty } -> v, d + | Node { r } -> max_binding r + + let rec max_binding_opt = function + | Empty -> None + | Node { v; d; r = Empty } -> Some (v, d) + | Node { r } -> max_binding_opt r + + let rec remove_min_binding = function + | Empty -> invalid_arg "Map.remove_min_elt" + | Node { l = Empty; r } -> r + | Node { l; v; d; r } -> bal (remove_min_binding l) v d r + + let merge t1 t2 = + match t1, t2 with + | Empty, t -> t + | t, Empty -> t + | _, _ -> + let x, d = min_binding t2 in + bal t1 x d (remove_min_binding t2) + + let rec remove x = function + | Empty -> Empty + | Node { l; v; d; r } as m -> + let c = Ord.compare x v in + if c = 0 + then merge l r + else if c < 0 + then + let ll = remove x l in + if l == ll then m else bal ll v d r + else + let rr = remove x r in + if r == rr then m else bal l v d rr + + let rec update x f = function + | Empty -> begin + match f None with + | None -> Empty + | Some data -> Node { l = Empty; v = x; d = data; r = Empty; h = 1 } + end + | Node { l; v; d; r; h } as m -> + let c = Ord.compare x v in + if c = 0 + then begin + match f (Some d) with + | None -> merge l r + | Some data -> + if d == data then m else Node { l; v = x; d = data; r; h } + end + else if c < 0 + then + let ll = update x f l in + if l == ll then m else bal ll v d r + else + let rr = update x f r in + if r == rr then m else bal l v d rr + + let add_to_list x data m = + let add = function + | None -> Some [ data ] + | Some l -> Some (data :: l) + in + update x add m + + let rec iter f = function + | Empty -> () + | Node { l; v; d; r } -> + iter f l ; + f v d ; + iter f r + + let rec map f = function + | Empty -> Empty + | Node { l; v; d; r; h } -> + let l' = map f l in + let d' = f d in + let r' = map f r in + Node { l = l'; v; d = d'; r = r'; h } + + let rec mapi f = function + | Empty -> Empty + | Node { l; v; d; r; h } -> + let l' = mapi f l in + let d' = f v d in + let r' = mapi f r in + Node { l = l'; v; d = d'; r = r'; h } + + let rec fold f m accu = + match m with + | Empty -> accu + | Node { l; v; d; r } -> fold f r (f v d (fold f l accu)) + + let rec for_all p = function + | Empty -> true + | Node { l; v; d; r } -> p v d && for_all p l && for_all p r + + let rec exists p = function + | Empty -> false + | Node { l; v; d; r } -> p v d || exists p l || exists p r + + (* Beware: those two functions assume that the added k is *strictly* + smaller (or bigger) than all the present keys in the tree; it + does not test for equality with the current min (or max) key. + + Indeed, they are only used during the "join" operation which + respects this precondition. + *) + + let rec add_min_binding k x = function + | Empty -> singleton k x + | Node { l; v; d; r } -> bal (add_min_binding k x l) v d r + + let rec add_max_binding k x = function + | Empty -> singleton k x + | Node { l; v; d; r } -> bal l v d (add_max_binding k x r) + + (* Same as create and bal, but no assumptions are made on the + relative heights of l and r. *) + + let rec join l v d r = + match l, r with + | Empty, _ -> add_min_binding v d r + | _, Empty -> add_max_binding v d l + | ( Node { l = ll; v = lv; d = ld; r = lr; h = lh } + , Node { l = rl; v = rv; d = rd; r = rr; h = rh } ) -> + if lh > rh + 2 + then bal ll lv ld (join lr v d r) + else if rh > lh + 2 + then bal (join l v d rl) rv rd rr + else create l v d r + + (* Merge two trees l and r into one. + All elements of l must precede the elements of r. + No assumption on the heights of l and r. *) + + let concat t1 t2 = + match t1, t2 with + | Empty, t -> t + | t, Empty -> t + | _, _ -> + let x, d = min_binding t2 in + join t1 x d (remove_min_binding t2) + + let concat_or_join t1 v d t2 = + match d with + | Some d -> join t1 v d t2 + | None -> concat t1 t2 + + let rec split x = function + | Empty -> Empty, None, Empty + | Node { l; v; d; r } -> + let c = Ord.compare x v in + if c = 0 + then l, Some d, r + else if c < 0 + then + let ll, pres, rl = split x l in + ll, pres, join rl v d r + else + let lr, pres, rr = split x r in + join l v d lr, pres, rr + + let rec merge f s1 s2 = + match s1, s2 with + | Empty, Empty -> Empty + | Node { l = l1; v = v1; d = d1; r = r1; h = h1 }, _ when h1 >= height s2 -> + let l2, d2, r2 = split v1 s2 in + concat_or_join (merge f l1 l2) v1 (f v1 (Some d1) d2) (merge f r1 r2) + | _, Node { l = l2; v = v2; d = d2; r = r2 } -> + let l1, d1, r1 = split v2 s1 in + concat_or_join (merge f l1 l2) v2 (f v2 d1 (Some d2)) (merge f r1 r2) + | _ -> assert false + + let rec union f s1 s2 = + match s1, s2 with + | Empty, s | s, Empty -> s + | ( Node { l = l1; v = v1; d = d1; r = r1; h = h1 } + , Node { l = l2; v = v2; d = d2; r = r2; h = h2 } ) -> ( + if h1 >= h2 + then + let l2, d2, r2 = split v1 s2 in + let l = union f l1 l2 and r = union f r1 r2 in + match d2 with + | None -> join l v1 d1 r + | Some d2 -> concat_or_join l v1 (f v1 d1 d2) r + else + let l1, d1, r1 = split v2 s1 in + let l = union f l1 l2 and r = union f r1 r2 in + match d1 with + | None -> join l v2 d2 r + | Some d1 -> concat_or_join l v2 (f v2 d1 d2) r) + + let rec filter p = function + | Empty -> Empty + | Node { l; v; d; r } as m -> + (* call [p] in the expected left-to-right order *) + let l' = filter p l in + let pvd = p v d in + let r' = filter p r in + if pvd + then if l == l' && r == r' then m else join l' v d r' + else concat l' r' + + let rec filter_map f = function + | Empty -> Empty + | Node { l; v; d; r } -> + (* call [f] in the expected left-to-right order *) + let l' = filter_map f l in + let fvd = f v d in + let r' = filter_map f r in + begin + match fvd with + | Some d' -> join l' v d' r' + | None -> concat l' r' + end + + let rec partition p = function + | Empty -> Empty, Empty + | Node { l; v; d; r } -> + (* call [p] in the expected left-to-right order *) + let lt, lf = partition p l in + let pvd = p v d in + let rt, rf = partition p r in + if pvd + then join lt v d rt, concat lf rf + else concat lt rt, join lf v d rf + + type 'a enumeration = + | End + | More of key * 'a * 'a t * 'a enumeration + + let rec cons_enum m e = + match m with + | Empty -> e + | Node { l; v; d; r } -> cons_enum l (More (v, d, r, e)) + + let compare cmp m1 m2 = + let rec compare_aux e1 e2 = + match e1, e2 with + | End, End -> 0 + | End, _ -> -1 + | _, End -> 1 + | More (v1, d1, r1, e1), More (v2, d2, r2, e2) -> + let c = Ord.compare v1 v2 in + if c <> 0 + then c + else let c = cmp d1 d2 in - if c <> 0 then c else - compare_aux (cons_enum r1 e1) (cons_enum r2 e2) - in compare_aux (cons_enum m1 End) (cons_enum m2 End) - - let equal cmp m1 m2 = - let rec equal_aux e1 e2 = - match (e1, e2) with - (End, End) -> true - | (End, _) -> false - | (_, End) -> false - | (More(v1, d1, r1, e1), More(v2, d2, r2, e2)) -> - Ord.compare v1 v2 = 0 && cmp d1 d2 && - equal_aux (cons_enum r1 e1) (cons_enum r2 e2) - in equal_aux (cons_enum m1 End) (cons_enum m2 End) - - let rec cardinal = function - Empty -> 0 - | Node {l; r} -> cardinal l + 1 + cardinal r - - let rec bindings_aux accu = function - Empty -> accu - | Node {l; v; d; r} -> bindings_aux ((v, d) :: bindings_aux accu r) l - - let bindings s = - bindings_aux [] s - - let choose = min_binding - - let choose_opt = min_binding_opt - - let to_list = bindings - let of_list bs = List.fold_left (fun m (k, v) -> add k v m) empty bs - - let add_seq i m = - Seq.fold_left (fun m (k,v) -> add k v m) m i - - let of_seq i = add_seq i empty - - let rec seq_of_enum_ c () = match c with - | End -> Seq.Nil - | More (k,v,t,rest) -> Seq.Cons ((k,v), seq_of_enum_ (cons_enum t rest)) - - let to_seq m = - seq_of_enum_ (cons_enum m End) - - let rec snoc_enum s e = - match s with - Empty -> e - | Node{l; v; d; r} -> snoc_enum r (More(v, d, l, e)) - - let rec rev_seq_of_enum_ c () = match c with - | End -> Seq.Nil - | More (k,v,t,rest) -> - Seq.Cons ((k,v), rev_seq_of_enum_ (snoc_enum t rest)) - - let to_rev_seq c = - rev_seq_of_enum_ (snoc_enum c End) - - let to_seq_from low m = - let rec aux low m c = match m with - | Empty -> c - | Node {l; v; d; r; _} -> - begin match Ord.compare v low with - | 0 -> More (v, d, r, c) - | n when n<0 -> aux low r c - | _ -> aux low l (More (v, d, r, c)) - end - in - seq_of_enum_ (aux low m End) -end \ No newline at end of file + if c <> 0 + then c + else compare_aux (cons_enum r1 e1) (cons_enum r2 e2) + in + compare_aux (cons_enum m1 End) (cons_enum m2 End) + + let equal cmp m1 m2 = + let rec equal_aux e1 e2 = + match e1, e2 with + | End, End -> true + | End, _ -> false + | _, End -> false + | More (v1, d1, r1, e1), More (v2, d2, r2, e2) -> + Ord.compare v1 v2 = 0 + && cmp d1 d2 + && equal_aux (cons_enum r1 e1) (cons_enum r2 e2) + in + equal_aux (cons_enum m1 End) (cons_enum m2 End) + + let rec cardinal = function + | Empty -> 0 + | Node { l; r } -> cardinal l + 1 + cardinal r + + let rec bindings_aux accu = function + | Empty -> accu + | Node { l; v; d; r } -> bindings_aux ((v, d) :: bindings_aux accu r) l + + let bindings s = bindings_aux [] s + let choose = min_binding + let choose_opt = min_binding_opt + let to_list = bindings + let of_list bs = List.fold_left (fun m (k, v) -> add k v m) empty bs + let add_seq i m = Seq.fold_left (fun m (k, v) -> add k v m) m i + let of_seq i = add_seq i empty + + let rec seq_of_enum_ c () = + match c with + | End -> Seq.Nil + | More (k, v, t, rest) -> Seq.Cons ((k, v), seq_of_enum_ (cons_enum t rest)) + + let to_seq m = seq_of_enum_ (cons_enum m End) + + let rec snoc_enum s e = + match s with + | Empty -> e + | Node { l; v; d; r } -> snoc_enum r (More (v, d, l, e)) + + let rec rev_seq_of_enum_ c () = + match c with + | End -> Seq.Nil + | More (k, v, t, rest) -> + Seq.Cons ((k, v), rev_seq_of_enum_ (snoc_enum t rest)) + + let to_rev_seq c = rev_seq_of_enum_ (snoc_enum c End) + + let to_seq_from low m = + let rec aux low m c = + match m with + | Empty -> c + | Node { l; v; d; r; _ } -> begin + match Ord.compare v low with + | 0 -> More (v, d, r, c) + | n when n < 0 -> aux low r c + | _ -> aux low l (More (v, d, r, c)) + end + in + seq_of_enum_ (aux low m End) +end diff --git a/lib/common/set.ml b/lib/common/set.ml new file mode 100644 index 0000000000..a427c722c5 --- /dev/null +++ b/lib/common/set.ml @@ -0,0 +1,638 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) +[@@@warning "-9"] + +(* Sets over ordered types *) + +module type OrderedType = sig + type t + + val compare : t -> t -> int +end + +module type S = sig + type elt + + type t = + | Empty + | Node of + { l : t + ; v : elt + ; r : t + ; h : int + } + + val empty : t + val add : elt -> t -> t + val singleton : elt -> t + val remove : elt -> t -> t + val union : t -> t -> t + val inter : t -> t -> t + val disjoint : t -> t -> bool + val diff : t -> t -> t + val cardinal : t -> int + val elements : t -> elt list + val min_elt : t -> elt + val min_elt_opt : t -> elt option + val max_elt : t -> elt + val max_elt_opt : t -> elt option + val choose : t -> elt + val choose_opt : t -> elt option + val find : elt -> t -> elt + val find_opt : elt -> t -> elt option + val find_first : (elt -> bool) -> t -> elt + val find_first_opt : (elt -> bool) -> t -> elt option + val find_last : (elt -> bool) -> t -> elt + val find_last_opt : (elt -> bool) -> t -> elt option + val iter : (elt -> unit) -> t -> unit + val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a + val map : (elt -> elt) -> t -> t + val filter : (elt -> bool) -> t -> t + val filter_map : (elt -> elt option) -> t -> t + val partition : (elt -> bool) -> t -> t * t + val split : elt -> t -> t * bool * t + val is_empty : t -> bool + val mem : elt -> t -> bool + val equal : t -> t -> bool + val compare : t -> t -> int + val subset : t -> t -> bool + val for_all : (elt -> bool) -> t -> bool + val exists : (elt -> bool) -> t -> bool + val to_list : t -> elt list + val of_list : elt list -> t + val to_seq_from : elt -> t -> elt Seq.t + val to_seq : t -> elt Seq.t + val to_rev_seq : t -> elt Seq.t + val add_seq : elt Seq.t -> t -> t + val of_seq : elt Seq.t -> t +end + +module Make (Ord : OrderedType) = struct + type elt = Ord.t + + type t = + | Empty + | Node of + { l : t + ; v : elt + ; r : t + ; h : int + } + + (* Sets are represented by balanced binary trees (the heights of the + children differ by at most 2 *) + + let height = function + | Empty -> 0 + | Node { h } -> h + + (* Creates a new node with left son l, value v and right son r. + We must have all elements of l < v < all elements of r. + l and r must be balanced and | height l - height r | <= 2. + Inline expansion of height for better speed. *) + + let create l v r = + let hl = + match l with + | Empty -> 0 + | Node { h } -> h + in + let hr = + match r with + | Empty -> 0 + | Node { h } -> h + in + Node { l; v; r; h = (if hl >= hr then hl + 1 else hr + 1) } + + (* Same as create, but performs one step of rebalancing if necessary. + Assumes l and r balanced and | height l - height r | <= 3. + Inline expansion of create for better speed in the most frequent case + where no rebalancing is required. *) + + let bal l v r = + let hl = + match l with + | Empty -> 0 + | Node { h } -> h + in + let hr = + match r with + | Empty -> 0 + | Node { h } -> h + in + if hl > hr + 2 + then begin + match l with + | Empty -> invalid_arg "Set.bal" + | Node { l = ll; v = lv; r = lr } -> + if height ll >= height lr + then create ll lv (create lr v r) + else begin + match lr with + | Empty -> invalid_arg "Set.bal" + | Node { l = lrl; v = lrv; r = lrr } -> + create (create ll lv lrl) lrv (create lrr v r) + end + end + else if hr > hl + 2 + then begin + match r with + | Empty -> invalid_arg "Set.bal" + | Node { l = rl; v = rv; r = rr } -> + if height rr >= height rl + then create (create l v rl) rv rr + else begin + match rl with + | Empty -> invalid_arg "Set.bal" + | Node { l = rll; v = rlv; r = rlr } -> + create (create l v rll) rlv (create rlr rv rr) + end + end + else Node { l; v; r; h = (if hl >= hr then hl + 1 else hr + 1) } + + (* Insertion of one element *) + + let rec add x = function + | Empty -> Node { l = Empty; v = x; r = Empty; h = 1 } + | Node { l; v; r } as t -> + let c = Ord.compare x v in + if c = 0 + then t + else if c < 0 + then + let ll = add x l in + if l == ll then t else bal ll v r + else + let rr = add x r in + if r == rr then t else bal l v rr + + let singleton x = Node { l = Empty; v = x; r = Empty; h = 1 } + + (* Beware: those two functions assume that the added v is *strictly* + smaller (or bigger) than all the present elements in the tree; it + does not test for equality with the current min (or max) element. + Indeed, they are only used during the "join" operation which + respects this precondition. + *) + + let rec add_min_element x = function + | Empty -> singleton x + | Node { l; v; r } -> bal (add_min_element x l) v r + + let rec add_max_element x = function + | Empty -> singleton x + | Node { l; v; r } -> bal l v (add_max_element x r) + + (* Same as create and bal, but no assumptions are made on the + relative heights of l and r. *) + + let rec join l v r = + match l, r with + | Empty, _ -> add_min_element v r + | _, Empty -> add_max_element v l + | ( Node { l = ll; v = lv; r = lr; h = lh } + , Node { l = rl; v = rv; r = rr; h = rh } ) -> + if lh > rh + 2 + then bal ll lv (join lr v r) + else if rh > lh + 2 + then bal (join l v rl) rv rr + else create l v r + + (* Smallest and greatest element of a set *) + + let rec min_elt = function + | Empty -> raise Not_found + | Node { l = Empty; v } -> v + | Node { l } -> min_elt l + + let rec min_elt_opt = function + | Empty -> None + | Node { l = Empty; v } -> Some v + | Node { l } -> min_elt_opt l + + let rec max_elt = function + | Empty -> raise Not_found + | Node { v; r = Empty } -> v + | Node { r } -> max_elt r + + let rec max_elt_opt = function + | Empty -> None + | Node { v; r = Empty } -> Some v + | Node { r } -> max_elt_opt r + + (* Remove the smallest element of the given set *) + + let rec remove_min_elt = function + | Empty -> invalid_arg "Set.remove_min_elt" + | Node { l = Empty; r } -> r + | Node { l; v; r } -> bal (remove_min_elt l) v r + + (* Merge two trees l and r into one. + All elements of l must precede the elements of r. + Assume | height l - height r | <= 2. *) + + let merge t1 t2 = + match t1, t2 with + | Empty, t -> t + | t, Empty -> t + | _, _ -> bal t1 (min_elt t2) (remove_min_elt t2) + + (* Merge two trees l and r into one. + All elements of l must precede the elements of r. + No assumption on the heights of l and r. *) + + let concat t1 t2 = + match t1, t2 with + | Empty, t -> t + | t, Empty -> t + | _, _ -> join t1 (min_elt t2) (remove_min_elt t2) + + (* Splitting. split x s returns a triple (l, present, r) where + - l is the set of elements of s that are < x + - r is the set of elements of s that are > x + - present is false if s contains no element equal to x, + or true if s contains an element equal to x. *) + + let rec split x = function + | Empty -> Empty, false, Empty + | Node { l; v; r } -> + let c = Ord.compare x v in + if c = 0 + then l, true, r + else if c < 0 + then + let ll, pres, rl = split x l in + ll, pres, join rl v r + else + let lr, pres, rr = split x r in + join l v lr, pres, rr + + (* Implementation of the set operations *) + + let empty = Empty + + let is_empty = function + | Empty -> true + | _ -> false + + let rec mem x = function + | Empty -> false + | Node { l; v; r } -> + let c = Ord.compare x v in + c = 0 || mem x (if c < 0 then l else r) + + let rec remove x = function + | Empty -> Empty + | Node { l; v; r } as t -> + let c = Ord.compare x v in + if c = 0 + then merge l r + else if c < 0 + then + let ll = remove x l in + if l == ll then t else bal ll v r + else + let rr = remove x r in + if r == rr then t else bal l v rr + + let rec union s1 s2 = + match s1, s2 with + | Empty, t2 -> t2 + | t1, Empty -> t1 + | ( Node { l = l1; v = v1; r = r1; h = h1 } + , Node { l = l2; v = v2; r = r2; h = h2 } ) -> + if h1 >= h2 + then + if h2 = 1 + then add v2 s1 + else begin + let l2, _, r2 = split v1 s2 in + join (union l1 l2) v1 (union r1 r2) + end + else if h1 = 1 + then add v1 s2 + else begin + let l1, _, r1 = split v2 s1 in + join (union l1 l2) v2 (union r1 r2) + end + + let rec inter s1 s2 = + match s1, s2 with + | Empty, _ -> Empty + | _, Empty -> Empty + | Node { l = l1; v = v1; r = r1 }, t2 -> ( + match split v1 t2 with + | l2, false, r2 -> concat (inter l1 l2) (inter r1 r2) + | l2, true, r2 -> join (inter l1 l2) v1 (inter r1 r2)) + + (* Same as split, but compute the left and right subtrees + only if the pivot element is not in the set. The right subtree + is computed on demand. *) + + type split_bis = + | Found + | NotFound of t * (unit -> t) + + let rec split_bis x = function + | Empty -> NotFound (Empty, fun () -> Empty) + | Node { l; v; r; _ } -> ( + let c = Ord.compare x v in + if c = 0 + then Found + else if c < 0 + then + match split_bis x l with + | Found -> Found + | NotFound (ll, rl) -> NotFound (ll, fun () -> join (rl ()) v r) + else + match split_bis x r with + | Found -> Found + | NotFound (lr, rr) -> NotFound (join l v lr, rr)) + + let rec disjoint s1 s2 = + match s1, s2 with + | Empty, _ | _, Empty -> true + | Node { l = l1; v = v1; r = r1 }, t2 -> ( + if s1 == s2 + then false + else + match split_bis v1 t2 with + | NotFound (l2, r2) -> disjoint l1 l2 && disjoint r1 (r2 ()) + | Found -> false) + + let rec diff s1 s2 = + match s1, s2 with + | Empty, _ -> Empty + | t1, Empty -> t1 + | Node { l = l1; v = v1; r = r1 }, t2 -> ( + match split v1 t2 with + | l2, false, r2 -> join (diff l1 l2) v1 (diff r1 r2) + | l2, true, r2 -> concat (diff l1 l2) (diff r1 r2)) + + type enumeration = + | End + | More of elt * t * enumeration + + let rec cons_enum s e = + match s with + | Empty -> e + | Node { l; v; r } -> cons_enum l (More (v, r, e)) + + let rec compare_aux e1 e2 = + match e1, e2 with + | End, End -> 0 + | End, _ -> -1 + | _, End -> 1 + | More (v1, r1, e1), More (v2, r2, e2) -> + let c = Ord.compare v1 v2 in + if c <> 0 then c else compare_aux (cons_enum r1 e1) (cons_enum r2 e2) + + let compare s1 s2 = compare_aux (cons_enum s1 End) (cons_enum s2 End) + let equal s1 s2 = compare s1 s2 = 0 + + let rec subset s1 s2 = + match s1, s2 with + | Empty, _ -> true + | _, Empty -> false + | Node { l = l1; v = v1; r = r1 }, (Node { l = l2; v = v2; r = r2 } as t2) + -> + let c = Ord.compare v1 v2 in + if c = 0 + then subset l1 l2 && subset r1 r2 + else if c < 0 + then + subset (Node { l = l1; v = v1; r = Empty; h = 0 }) l2 && subset r1 t2 + else + subset (Node { l = Empty; v = v1; r = r1; h = 0 }) r2 && subset l1 t2 + + let rec iter f = function + | Empty -> () + | Node { l; v; r } -> + iter f l ; + f v ; + iter f r + + let rec fold f s accu = + match s with + | Empty -> accu + | Node { l; v; r } -> fold f r (f v (fold f l accu)) + + let rec for_all p = function + | Empty -> true + | Node { l; v; r } -> p v && for_all p l && for_all p r + + let rec exists p = function + | Empty -> false + | Node { l; v; r } -> p v || exists p l || exists p r + + let rec filter p = function + | Empty -> Empty + | Node { l; v; r } as t -> + (* call [p] in the expected left-to-right order *) + let l' = filter p l in + let pv = p v in + let r' = filter p r in + if pv + then if l == l' && r == r' then t else join l' v r' + else concat l' r' + + let rec partition p = function + | Empty -> Empty, Empty + | Node { l; v; r } -> + (* call [p] in the expected left-to-right order *) + let lt, lf = partition p l in + let pv = p v in + let rt, rf = partition p r in + if pv then join lt v rt, concat lf rf else concat lt rt, join lf v rf + + let rec cardinal = function + | Empty -> 0 + | Node { l; r } -> cardinal l + 1 + cardinal r + + let rec elements_aux accu = function + | Empty -> accu + | Node { l; v; r } -> elements_aux (v :: elements_aux accu r) l + + let elements s = elements_aux [] s + let choose = min_elt + let choose_opt = min_elt_opt + + let rec find x = function + | Empty -> raise Not_found + | Node { l; v; r } -> + let c = Ord.compare x v in + if c = 0 then v else find x (if c < 0 then l else r) + + let rec find_first_aux v0 f = function + | Empty -> v0 + | Node { l; v; r } -> + if f v then find_first_aux v f l else find_first_aux v0 f r + + let rec find_first f = function + | Empty -> raise Not_found + | Node { l; v; r } -> if f v then find_first_aux v f l else find_first f r + + let rec find_first_opt_aux v0 f = function + | Empty -> Some v0 + | Node { l; v; r } -> + if f v then find_first_opt_aux v f l else find_first_opt_aux v0 f r + + let rec find_first_opt f = function + | Empty -> None + | Node { l; v; r } -> + if f v then find_first_opt_aux v f l else find_first_opt f r + + let rec find_last_aux v0 f = function + | Empty -> v0 + | Node { l; v; r } -> + if f v then find_last_aux v f r else find_last_aux v0 f l + + let rec find_last f = function + | Empty -> raise Not_found + | Node { l; v; r } -> if f v then find_last_aux v f r else find_last f l + + let rec find_last_opt_aux v0 f = function + | Empty -> Some v0 + | Node { l; v; r } -> + if f v then find_last_opt_aux v f r else find_last_opt_aux v0 f l + + let rec find_last_opt f = function + | Empty -> None + | Node { l; v; r } -> + if f v then find_last_opt_aux v f r else find_last_opt f l + + let rec find_opt x = function + | Empty -> None + | Node { l; v; r } -> + let c = Ord.compare x v in + if c = 0 then Some v else find_opt x (if c < 0 then l else r) + + let try_join l v r = + (* [join l v r] can only be called when (elements of l < v < + elements of r); use [try_join l v r] when this property may + not hold, but you hope it does hold in the common case *) + if (l = Empty || Ord.compare (max_elt l) v < 0) + && (r = Empty || Ord.compare v (min_elt r) < 0) + then join l v r + else union l (add v r) + + let rec map f = function + | Empty -> Empty + | Node { l; v; r } as t -> + (* enforce left-to-right evaluation order *) + let l' = map f l in + let v' = f v in + let r' = map f r in + if l == l' && v == v' && r == r' then t else try_join l' v' r' + + let try_concat t1 t2 = + match t1, t2 with + | Empty, t -> t + | t, Empty -> t + | _, _ -> try_join t1 (min_elt t2) (remove_min_elt t2) + + let rec filter_map f = function + | Empty -> Empty + | Node { l; v; r } as t -> + (* enforce left-to-right evaluation order *) + let l' = filter_map f l in + let v' = f v in + let r' = filter_map f r in + begin + match v' with + | Some v' -> + if l == l' && v == v' && r == r' then t else try_join l' v' r' + | None -> try_concat l' r' + end + + let of_sorted_list l = + let rec sub n l = + match n, l with + | 0, l -> Empty, l + | 1, x0 :: l -> Node { l = Empty; v = x0; r = Empty; h = 1 }, l + | 2, x0 :: x1 :: l -> + ( Node + { l = Node { l = Empty; v = x0; r = Empty; h = 1 } + ; v = x1 + ; r = Empty + ; h = 2 + } + , l ) + | 3, x0 :: x1 :: x2 :: l -> + ( Node + { l = Node { l = Empty; v = x0; r = Empty; h = 1 } + ; v = x1 + ; r = Node { l = Empty; v = x2; r = Empty; h = 1 } + ; h = 2 + } + , l ) + | n, l -> ( + let nl = n / 2 in + let left, l = sub nl l in + match l with + | [] -> assert false + | mid :: l -> + let right, l = sub (n - nl - 1) l in + create left mid right, l) + in + fst (sub (List.length l) l) + + let to_list = elements + + let of_list l = + match l with + | [] -> empty + | [ x0 ] -> singleton x0 + | [ x0; x1 ] -> add x1 (singleton x0) + | [ x0; x1; x2 ] -> add x2 (add x1 (singleton x0)) + | [ x0; x1; x2; x3 ] -> add x3 (add x2 (add x1 (singleton x0))) + | [ x0; x1; x2; x3; x4 ] -> add x4 (add x3 (add x2 (add x1 (singleton x0)))) + | _ -> of_sorted_list (List.sort_uniq Ord.compare l) + + let add_seq i m = Seq.fold_left (fun s x -> add x s) m i + let of_seq i = add_seq i empty + + let rec seq_of_enum_ c () = + match c with + | End -> Seq.Nil + | More (x, t, rest) -> Seq.Cons (x, seq_of_enum_ (cons_enum t rest)) + + let to_seq c = seq_of_enum_ (cons_enum c End) + + let rec snoc_enum s e = + match s with + | Empty -> e + | Node { l; v; r } -> snoc_enum r (More (v, l, e)) + + let rec rev_seq_of_enum_ c () = + match c with + | End -> Seq.Nil + | More (x, t, rest) -> Seq.Cons (x, rev_seq_of_enum_ (snoc_enum t rest)) + + let to_rev_seq c = rev_seq_of_enum_ (snoc_enum c End) + + let to_seq_from low s = + let rec aux low s c = + match s with + | Empty -> c + | Node { l; r; v; _ } -> begin + match Ord.compare v low with + | 0 -> More (v, r, c) + | n when n < 0 -> aux low r c + | _ -> aux low l (More (v, r, c)) + end + in + seq_of_enum_ (aux low s End) +end diff --git a/lib/db/cache.ml b/lib/db/cache.ml index 3f1d98253d..6d92a24cb6 100644 --- a/lib/db/cache.ml +++ b/lib/db/cache.ml @@ -89,7 +89,7 @@ module Array (A : Memo) = Make (struct let equal = Array.equal A.equal let hash = Array.hash A.hash - let sub ~memo:_ arr = arr + let sub ~memo:_ arr = Array.map A.memo arr end) module Char_list = List (Char) @@ -119,7 +119,14 @@ module Set (A : Memo) (S : Set.S with type elt = A.t) = Make (struct let hash m = m |> S.elements |> Common.List.map (fun v -> A.hash v) |> Hashtbl.hash - let sub ~memo:_ = S.map A.memo + let sub ~memo set = + match set with + | S.Empty -> S.Empty + | S.Node { l; v; r; h } -> + let l = memo l in + let v = A.memo v in + let r = memo r in + S.Node { l; v; r; h } end) module Map (A : Memo) (M : Map.S) = Make (struct @@ -132,13 +139,14 @@ module Map (A : Memo) (M : Map.S) = Make (struct |> Common.List.map (fun (k, v) -> k, A.hash v) |> Hashtbl.hash - let sub ~memo m = match m with - M.Empty -> M.Empty - | M.Node {l; v; d; r; h} -> + let sub ~memo m = + match m with + | M.Empty -> M.Empty + | M.Node { l; v; d; r; h } -> let l = memo l in let r = memo r in let d = A.memo d in - M.Node {l; v; d; r; h} + M.Node { l; v; d; r; h } end) module Array_map (A : Memo) (M : Array_map.S) = Make (struct @@ -176,75 +184,49 @@ module Elt_set_option = Option (Elt_set) module Char_map (A : Memo) = Map (A) (Char.Map) module Int_map (A : Memo) = Map (A) (Int.Map) module Char_array_map (A : Memo) = Array_map (A) (Char.Array_map) -module Elt_array_occ = Int_map(Elt_array) +module Elt_array_occ = Int_map (Elt_array) module Elt_set_occ = Int_map (Elt_set) module Elt_set_char_map = Char_map (Elt_set) -module Trie_gen (A : Memo) : Memo with type t = A.t Trie_gen.t = struct - module rec M : (Memo with type t = A.t Trie_gen.t) = Make_sub_only (struct - module Map = Char_map (A) - module Option = Option (A) +module Trie (A : Memo) : Memo with type t = A.t Trie.t = struct + module A_option = Option (A) - type t = A.t Trie_gen.t + module rec M : (Memo with type t = A.t Trie.t) = Make_sub_only (struct + type t = A.t Trie.t - let equal = ( = ) + let equal t1 t2 = + (*( = )*) + let open Trie in + match t1, t2 with + | Leaf (chars, elt), Leaf (chars', elt') -> + Char_list.equal chars chars' && A.equal elt elt' + | Node { leaf; children }, Node { leaf = leaf'; children = children' } -> + A_option.equal leaf leaf' && Children.equal children children' + | _ -> false let hash trie = - let open Trie_gen in + let open Trie in match trie with | Leaf _ -> Hashtbl.hash trie | Node { leaf; children } -> Hashtbl.hash (Hashtbl.hash leaf, Children.hash children) let sub ~memo:_ trie = - let open Trie_gen in + let open Trie in match trie with | Leaf (chars, elts) -> Leaf (Char_list.memo chars, A.memo elts) | Node { leaf; children } -> - let leaf = Option.memo leaf in + let leaf = A_option.memo leaf in let children = Children.memo children in Node { leaf; children } end) - and Children : (Memo with type t = A.t Trie_gen.t Char.Map.t) = Char_map (M) + and Children : (Memo with type t = A.t Trie.t Char.Map.t) = Char_map (M) include M end -module Trie_compact (A : Memo) : Memo with type t = A.t Trie_compact.t = struct - module rec M : (Memo with type t = A.t Trie_compact.t) = Make_sub_only (struct - module Map = Char_map (A) - module Option = Option (A) - - type t = A.t Trie_compact.t - - let equal = ( = ) - - let hash trie = - let open Trie_compact in - match trie with - | Leaf _ -> Hashtbl.hash trie - | Node { leaf; children } -> - Hashtbl.hash (Hashtbl.hash leaf, Children.hash children) - - let sub ~memo:_ trie = - let open Trie_compact in - match trie with - | Leaf (chars, elts) -> Leaf (String.memo chars, A.memo elts) - | Node { leaf; children } -> - let leaf = Option.memo leaf in - let children = Children.memo children in - Node { leaf; children } - end) - - and Children : (Memo with type t = A.t Trie_compact.t Char.Array_map.t) = - Char_array_map (M) - - include M -end - -module Elt_set_trie_gen = Trie_gen (Elt_set) -module Elt_set_occ_trie_gen = Trie_gen (Elt_set_occ) - -module Elt_array_trie_gen = Trie_gen (Elt_array) -module Elt_array_occ_trie_gen = Trie_gen (Elt_array_occ) \ No newline at end of file +module Elt_set_trie = Trie (Elt_set) +module Elt_set_occ_trie = Trie (Elt_set_occ) +module Elt_array_trie = Trie (Elt_array) +module Elt_array_occ_trie = Trie (Elt_array_occ) diff --git a/lib/db/cache.mli b/lib/db/cache.mli index 74b2e9c4a1..9b8995b0de 100644 --- a/lib/db/cache.mli +++ b/lib/db/cache.mli @@ -15,9 +15,7 @@ module Char_list : Memo with type t = char list module String_list : Memo with type t = string list module String_list_list : Memo with type t = string list list module Elt_array : Memo with type t = Elt.t array -module Elt_set_trie_gen : Memo with type t = Elt.Set.t Trie_gen.t -module Elt_set_occ_trie_gen : Memo with type t = Elt.Set.t Int.Map.t Trie_gen.t -module Elt_array_trie_gen : Memo with type t = Elt.t Array.t Trie_gen.t - -module Elt_array_occ_trie_gen : - Memo with type t = Elt.t Array.t Int.Map.t Trie_gen.t +module Elt_set_trie : Memo with type t = Elt.Set.t Trie.t +module Elt_set_occ_trie : Memo with type t = Elt.Set.t Int.Map.t Trie.t +module Elt_array_trie : Memo with type t = Elt.t Array.t Trie.t +module Elt_array_occ_trie : Memo with type t = Elt.t Array.t Int.Map.t Trie.t diff --git a/lib/db/db.ml b/lib/db/db.ml index 02fe06cdc5..5ee62699e1 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -2,9 +2,7 @@ open Common module Elt = Elt module Types = Types module Storage_toplevel = Storage -module Trie = Trie_gen -module Trie_gen = Trie_gen -module Trie_compact = Trie_compact +module Trie = Trie module Cache = Cache include Types module Occ = Int.Map @@ -13,7 +11,7 @@ let compact db = let open Types in let { db_types; db_names } = db in let db_types = - Trie_gen.map_leaf + Trie.map_leaf ~f:(fun occs -> Int.Map.map (fun set -> @@ -22,14 +20,13 @@ let compact db = db_types in let db_names = - Trie_gen.map_leaf + Trie.map_leaf ~f:(fun set -> set |> Elt.Set.elements |> Array.of_list |> Cache.Elt_array.memo) db_names in - - let db_types = Cache.Elt_array_occ_trie_gen.memo db_types in - let db_names = Cache.Elt_array_trie_gen.memo db_names in + let db_types = Cache.Elt_array_occ_trie.memo db_types in + let db_names = Cache.Elt_array_trie.memo db_names in { db_types; db_names } let list_of_string s = List.init (String.length s) (String.get s) diff --git a/lib/db/db.mli b/lib/db/db.mli index 210546d234..608d301ebd 100644 --- a/lib/db/db.mli +++ b/lib/db/db.mli @@ -2,13 +2,12 @@ open Common module Elt = Elt module Types = Types module Storage = Storage -module Trie_compact = Trie_compact -module Trie_gen = Trie_gen +module Trie = Trie module Cache = Cache type 'a t = 'a Types.t = - { db_types : 'a Int.Map.t Trie_gen.t - ; db_names : 'a Trie_gen.t + { db_types : 'a Int.Map.t Trie.t + ; db_names : 'a Trie.t } val list_of_string : string -> char list diff --git a/lib/db/storage.ml b/lib/db/storage.ml index a7453725fc..079330300d 100644 --- a/lib/db/storage.ml +++ b/lib/db/storage.ml @@ -1,4 +1,3 @@ - type 'a db = 'a Types.t module type S = sig diff --git a/lib/db/trie_gen.ml b/lib/db/trie.ml similarity index 99% rename from lib/db/trie_gen.ml rename to lib/db/trie.ml index bd297d3161..b9802b51fc 100644 --- a/lib/db/trie_gen.ml +++ b/lib/db/trie.ml @@ -79,4 +79,3 @@ let rec map_leaf ~f t = let leaf = Option.map f leaf in let children = M.map (map_leaf ~f) children in Node { leaf; children } - diff --git a/lib/db/trie_compact.ml b/lib/db/trie_compact.ml deleted file mode 100644 index 3ebab14392..0000000000 --- a/lib/db/trie_compact.ml +++ /dev/null @@ -1,61 +0,0 @@ -open Common -module M = Char.Array_map - -type 'a t = - | Leaf of string * 'a - | Node of - { leaf : 'a option - ; children : 'a t M.t - } - -let empty () = Node { leaf = None; children = M.of_seq Seq.empty } -let string_of_list li = li |> List.to_seq |> String.of_seq - -let rec of_trie_gen trie_gen = - match trie_gen with - | Trie_gen.Leaf (chars, elt) -> Leaf (string_of_list chars, elt) - | Trie_gen.Node { leaf; children } -> - Node - { leaf - ; children = - children |> Char.Map.to_seq |> Char.Array_map.of_seq - |> Char.Array_map.map ~f:of_trie_gen - } - -let rec find ?(i = 0) path t = - match t, path with - | _, [] -> t - | Node node, p :: path -> begin - match M.find ~key:p node.children with - | Some child -> find path child - | None -> t - end - | Leaf (chars, _outcome), y :: ys when i < String.length chars && chars.[i] = y - -> - find ~i:(i + 1) ys t - | _ -> t - -let rec fold_map merge transform t = - match t with - | Leaf (_, outcome) -> Some (transform outcome) - | Node { leaf; children; _ } -> - let leaf = - match leaf with - | None -> None - | Some leaf -> Some (transform leaf) - in - M.fold - ~f:(fun ~key:_ ~acc child -> - let res = fold_map merge transform child in - match acc, res with - | None, opt | opt, None -> opt - | Some acc, Some res -> Some (merge acc res)) - ~init:leaf children - -let rec map_leaf ~f t = - match t with - | Leaf (v, outcome) -> Leaf (v, f outcome) - | Node { leaf; children } -> - let leaf = Option.map f leaf in - let children = M.map ~f:(map_leaf ~f) children in - Node { leaf; children } diff --git a/lib/db/types.ml b/lib/db/types.ml index 393bcada54..21b54422f2 100644 --- a/lib/db/types.ml +++ b/lib/db/types.ml @@ -32,6 +32,6 @@ let sgn_not = function | Unknown -> Unknown type 'a t = - { db_types : 'a Int.Map.t Trie_gen.t - ; db_names : 'a Trie_gen.t + { db_types : 'a Int.Map.t Trie.t + ; db_names : 'a Trie.t } diff --git a/lib/index_lib/index_lib.ml b/lib/index_lib/index_lib.ml index 02c0e72f1f..5a06729f72 100644 --- a/lib/index_lib/index_lib.ml +++ b/lib/index_lib/index_lib.ml @@ -2,7 +2,7 @@ module Storage = Db.Storage let main ~index_docstring ~index_name ~type_search ~empty_payload ~index ~db_filename storage = - print_endline "Index_lib.main" ; + print_endline "Index_lib.main" ; let module Storage = (val storage : Storage.S) in let module Load_doc = Load_doc.Make (Storage) in let module Db = Load_doc.Db in diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 0284df94e3..d1b877f148 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -248,9 +248,8 @@ module Make (Storage : Db.Storage.S) = struct let name = name in let json_display = if empty_payload - then "" - else - entry |> Json_display.of_entry |> Odoc_html.Json.to_string + then "" + else entry |> Json_display.of_entry |> Odoc_html.Json.to_string in let has_doc = doc.txt <> "" in let elt = Elt.v ~name ~kind:kind' ~json_display ~has_doc () in diff --git a/lib/query/query.ml b/lib/query/query.ml index 173fdccb0d..817ac697b4 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -3,7 +3,7 @@ module Parser = Query_parser module Succ = Succ module Sort = Sort module Storage = Db.Storage -module Trie = Db.Trie_gen +module Trie = Db.Trie open Db.Types module Occ = Int.Map diff --git a/lib/storage_js/dune b/lib/storage_js/dune index 0a445d85c9..62e1488500 100644 --- a/lib/storage_js/dune +++ b/lib/storage_js/dune @@ -1,3 +1,3 @@ (library (name storage_js) - (libraries db base64)) + (libraries db base64 bigstringaf decompress.zl)) diff --git a/lib/storage_js/storage_js.ml b/lib/storage_js/storage_js.ml index b001f88aa0..927c22d6d8 100644 --- a/lib/storage_js/storage_js.ml +++ b/lib/storage_js/storage_js.ml @@ -5,22 +5,64 @@ type writer = out_channel let open_out = open_out let close_out = close_out +let deflate_string ?(level = 4) str = + let i = De.bigstring_create De.io_buffer_size in + let o = De.bigstring_create De.io_buffer_size in + let w = De.Lz77.make_window ~bits:15 in + let q = De.Queue.create 0x1000 in + let r = Buffer.create 0x1000 in + let p = ref 0 in + let refill buf = + let len = min (String.length str - !p) De.io_buffer_size in + Bigstringaf.blit_from_string str ~src_off:!p buf ~dst_off:0 ~len ; + p := !p + len ; + len + in + let flush buf len = + let str = Bigstringaf.substring buf ~off:0 ~len in + Buffer.add_string r str + in + Zl.Higher.compress ~level ~dynamic:true ~w ~q ~refill ~flush i o ; + Buffer.contents r + +let _inflate_string str = + let i = De.bigstring_create De.io_buffer_size in + let o = De.bigstring_create De.io_buffer_size in + let allocate bits = De.make_window ~bits in + let r = Buffer.create 0x1000 in + let p = ref 0 in + let refill buf = + let len = min (String.length str - !p) De.io_buffer_size in + Bigstringaf.blit_from_string str ~src_off:!p buf ~dst_off:0 ~len ; + p := !p + len ; + len + in + let flush buf len = + let str = Bigstringaf.substring buf ~off:0 ~len in + Buffer.add_string r str + in + match Zl.Higher.uncompress ~allocate ~refill ~flush i o with + | Ok () -> Ok (Buffer.contents r) + | Error _ as err -> err + let save ~db t = let str = Marshal.to_string t [] in + let str = deflate_string str in let str = Base64.encode_string str in Printf.fprintf db "function sherlodoc_db () { return %S; }\n%!" str let load str = - let str = Base64.decode_exn str in + (* let str = Base64.decode_exn str in + let str = inflate_string str |> Result.get_ok in *) let db_types, db_names = Marshal.from_string str 0 in let db_types = - Db.Trie_gen.map_leaf + Db.Trie.map_leaf ~f:(fun occs -> Int.Map.map (fun arr -> arr |> Array.to_seq |> Db.Elt.Set.of_seq) occs) db_types in let db_names = - Db.Trie_gen.map_leaf + Db.Trie.map_leaf ~f:(fun arr -> arr |> Array.to_seq |> Db.Elt.Set.of_seq) db_names in diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 90ac1926c0..8b8fb31087 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -1,4 +1,35 @@ -wwwwwwwwwwwwwww + $ cat $(find . -name '*.odocl') > megaodocl + $ du -sh megaodocl + 5.1M megaodocl + $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null + Index_lib.main + loading doc ! + doc loaded + + real 0m16.433s + user 0m16.294s + sys 0m0.100s + $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null + Index_lib.main + loading doc ! + doc loaded +$ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null + + $ gzip -k db.js + $ gzip -k db_marshal.bin + gzip: db_marshal.bin: No such file or directory + [1] + + $ gzip -k megaodocl + + $ du -s *.js *.gz + 3056 db.js + 2296 db.js.gz + 1628 megaodocl.gz $ for f in $(find . -name '*.odocl'); do @@ -6,8 +37,9 @@ wwwwwwwwwwwwwww > done $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js + $ cp sherlodoc_db.bin html $ du -sh html/index.js - 13M html/index.js + 7.9M html/index.js $ ls html base fonts @@ -17,5 +49,6 @@ wwwwwwwwwwwwwww katex.min.js odoc.css odoc_search.js + sherlodoc_db.bin $ cp -r html /tmp $ firefox /tmp/html/base/index.html diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 18a398fc3e..7b593dea85 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -3,29 +3,59 @@ $ odoc compile -I . page.mld $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc -$ cp /home/emile/.opam/sherlodoc/var/cache/odig/odoc/dream/**.odocl . - $ ls - main.cmi - main.cmo - main.cmt - main.ml - main.odoc - main.odocl - page-page.odoc - page-page.odocl - page.mld - $ sherlodoc_index --format=js --db=db.js *.odocl + $ cat $(find . -name '*.odocl') > megaodocl + $ du -sh megaodocl + 8.0K megaodocl + $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main loading doc ! doc loaded - $ du -sh db.js - 12K db.js - $ odoc html-generate --with-search --output-dir html main.odocl - $ odoc html-generate --with-search --output-dir html page-page.odocl + + real 0m0.010s + user 0m0.004s + sys 0m0.006s + $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null + Index_lib.main + loading doc ! + doc loaded +$ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null + + $ gzip -k db.js + $ gzip -k db_marshal.bin + gzip: db_marshal.bin: No such file or directory + [1] + + $ gzip -k megaodocl + + $ du -s *.js *.gz + 8 db.js + 4 db.js.gz + 4 megaodocl.gz + + + $ for f in $(find . -name '*.odocl'); do + > odoc html-generate --with-search --output-dir html $f 2> /dev/null + > done $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js + $ cp sherlodoc_db.bin html $ du -sh html/index.js - 4.1M html/index.js + 4.9M html/index.js + $ ls html + Main + fonts + highlight.pack.js + index.js + katex.min.css + katex.min.js + odoc.css + odoc_search.js + page.html + sherlodoc_db.bin $ cp -r html /tmp $ firefox /tmp/html/Main/index.html From 4d02477f4966e3f9ae057e3b5d533a62d30c7755 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 5 Jun 2023 10:59:07 +0200 Subject: [PATCH 074/285] Query uses arrays. --- lib/common/array.ml | 2 +- lib/db/db.ml | 40 ++++++++++++++++---------- lib/db/db.mli | 9 ++++++ lib/db/elt.ml | 1 - lib/db/storage.ml | 2 +- lib/index_lib/load_doc.ml | 1 - lib/query/query.ml | 12 ++++---- lib/query/query.mli | 2 +- lib/query/succ.ml | 5 ++++ lib/storage_ancient/storage_ancient.ml | 2 +- lib/storage_js/storage_js.ml | 36 +---------------------- test/cram/base.t/run.t | 17 +++++------ test/cram/simple.t/run.t | 9 +----- 13 files changed, 60 insertions(+), 78 deletions(-) diff --git a/lib/common/array.ml b/lib/common/array.ml index 85db16ba19..3161b2f923 100644 --- a/lib/common/array.ml +++ b/lib/common/array.ml @@ -1,6 +1,6 @@ include Stdlib.Array let equal (a : 'a -> 'a -> bool) arr arr' = - length arr = length arr' && for_all2 a arr arr' + if arr == arr' then true else length arr = length arr' && for_all2 a arr arr' let hash (a : 'a -> int) arr = Hashtbl.hash (map a arr) diff --git a/lib/db/db.ml b/lib/db/db.ml index 5ee62699e1..2a7e6bff5f 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -7,24 +7,34 @@ module Cache = Cache include Types module Occ = Int.Map +let trie_with_array trie = + Trie.map_leaf + ~f:(fun set -> + set |> Elt.Set.to_seq |> Array.of_seq |> Cache.Elt_array.memo) + trie + +let trie_with_set trie = + Trie.map_leaf ~f:(fun arr -> arr |> Array.to_seq |> Elt.Set.of_seq) trie + +let trie_with_array_occ trie = + Trie.map_leaf + ~f:(fun occs -> + occs + |> Int.Map.map (fun set -> + set |> Elt.Set.to_seq |> Array.of_seq |> Cache.Elt_array.memo)) + trie + +let trie_with_set_occ trie = + Trie.map_leaf + ~f:(fun occs -> + occs |> Int.Map.map (fun arr -> arr |> Array.to_seq |> Elt.Set.of_seq)) + trie + let compact db = let open Types in let { db_types; db_names } = db in - let db_types = - Trie.map_leaf - ~f:(fun occs -> - Int.Map.map - (fun set -> - set |> Elt.Set.elements |> Array.of_list |> Cache.Elt_array.memo) - occs) - db_types - in - let db_names = - Trie.map_leaf - ~f:(fun set -> - set |> Elt.Set.elements |> Array.of_list |> Cache.Elt_array.memo) - db_names - in + let db_types = trie_with_array_occ db_types in + let db_names = trie_with_array db_names in let db_types = Cache.Elt_array_occ_trie.memo db_types in let db_names = Cache.Elt_array_trie.memo db_names in { db_types; db_names } diff --git a/lib/db/db.mli b/lib/db/db.mli index 608d301ebd..5396a61e41 100644 --- a/lib/db/db.mli +++ b/lib/db/db.mli @@ -5,6 +5,15 @@ module Storage = Storage module Trie = Trie module Cache = Cache +val trie_with_array : Elt.Set.t Trie.t -> Elt.t array Trie.t +val trie_with_set : Elt.t array Trie.t -> Elt.Set.t Trie.t + +val trie_with_array_occ : + Elt.Set.t Int.Map.t Trie.t -> Elt.t array Int.Map.t Trie.t + +val trie_with_set_occ : + Elt.t array Int.Map.t Trie.t -> Elt.Set.t Int.Map.t Trie.t + type 'a t = 'a Types.t = { db_types : 'a Int.Map.t Trie.t ; db_names : 'a Trie.t diff --git a/lib/db/elt.ml b/lib/db/elt.ml index d30a9af51c..6be7ba4b72 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -118,6 +118,5 @@ module Package = struct end let v ~name ~kind ~has_doc ?(pkg = None) ~json_display () = - let name = name in let json_display = json_display in { name; kind; has_doc; pkg; json_display } diff --git a/lib/db/storage.ml b/lib/db/storage.ml index 079330300d..0bc896f65b 100644 --- a/lib/db/storage.ml +++ b/lib/db/storage.ml @@ -6,5 +6,5 @@ module type S = sig val open_out : string -> writer val save : db:writer -> Elt.t array db -> unit val close_out : writer -> unit - val load : string -> Elt.Set.t db list + val load : string -> Elt.t array db list end diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index d1b877f148..5fad19e5a7 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -245,7 +245,6 @@ module Make (Storage : Db.Storage.S) = struct | Doc _ -> Pretty.prefixname id | _ -> full_name in - let name = name in let json_display = if empty_payload then "" diff --git a/lib/query/query.ml b/lib/query/query.ml index 817ac697b4..0689461924 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -11,7 +11,7 @@ let inter_list xs = List.fold_left Succ.inter Succ.all xs let collapse_count ~count occs = Occ.fold - (fun k x acc -> if k < count then acc else Succ.union (Succ.of_set x) acc) + (fun k x acc -> if k < count then acc else Succ.union (Succ.of_array x) acc) occs Succ.empty let collapse_trie ~count t = @@ -20,7 +20,7 @@ let collapse_trie ~count t = | Some occ -> occ let collapse_triechar t = - match Trie.fold_map Succ.union Succ.of_set t with + match Trie.fold_map Succ.union Succ.of_array t with | None -> Succ.empty | Some s -> s @@ -42,13 +42,13 @@ let find_inter ~shards names = @@ List.map (fun (name, count) -> let name' = List.concat_map Db.list_of_string name in - collapse_trie_with_poly ~count name @@ Trie.find name' db) + db |> Trie.find name' |> collapse_trie_with_poly ~count name) (regroup names) in Succ.union acc r) Succ.empty shards -let find_names ~shards names = +let find_names ~(shards : Db.Elt.t array Db.t list) names = let names = List.map (fun n -> List.rev (Db.list_of_string (String.lowercase_ascii n))) @@ -74,7 +74,7 @@ type t = ; limit : int } -let search ~shards query_name query_typ = +let search ~(shards : Db.Elt.t array Db.t list) query_name query_typ = let results_name = find_names ~shards query_name in let results = match query_typ with @@ -95,7 +95,7 @@ let match_packages ~packages results = | [] -> results | _ -> Seq.filter (match_packages ~packages) results -let api ~shards params = +let api ~(shards : Db.Elt.t array Db.t list) params = let query_name, query_typ, query_typ_arrow, pretty = Parser.of_string params.query in diff --git a/lib/query/query.mli b/lib/query/query.mli index ec382c69a0..bf553e4b68 100644 --- a/lib/query/query.mli +++ b/lib/query/query.mli @@ -8,4 +8,4 @@ type t = ; limit : int } -val api : shards:Db.Elt.Set.t Db.t list -> t -> string * Db.Elt.t list +val api : shards:Db.Elt.t array Db.t list -> t -> string * Db.Elt.t list diff --git a/lib/query/succ.ml b/lib/query/succ.ml index 97d932df22..7039f842d0 100644 --- a/lib/query/succ.ml +++ b/lib/query/succ.ml @@ -20,6 +20,11 @@ let of_set s = then empty else { cardinal = Elt.Set.cardinal s; s = Set s } +let of_array arr = + let li = Array.to_list arr in + let set = Elt.Set.of_list li in + of_set set + let inter a b = match a.s, b.s with | Empty, _ | _, Empty -> empty diff --git a/lib/storage_ancient/storage_ancient.ml b/lib/storage_ancient/storage_ancient.ml index b244f992ea..efccde6e4d 100644 --- a/lib/storage_ancient/storage_ancient.ml +++ b/lib/storage_ancient/storage_ancient.ml @@ -18,7 +18,7 @@ let save ~db (t : Elt.t array Db.t) = let close_out db = Ancient.detach db.ancient -type reader = { shards : Elt.Set.t Db.t array } +type reader = { shards : Elt.t array Db.t array } let load_shard md shard = match Ancient.get md shard with diff --git a/lib/storage_js/storage_js.ml b/lib/storage_js/storage_js.ml index 927c22d6d8..ce278a6573 100644 --- a/lib/storage_js/storage_js.ml +++ b/lib/storage_js/storage_js.ml @@ -1,5 +1,3 @@ -open Common - type writer = out_channel let open_out = open_out @@ -25,26 +23,6 @@ let deflate_string ?(level = 4) str = Zl.Higher.compress ~level ~dynamic:true ~w ~q ~refill ~flush i o ; Buffer.contents r -let _inflate_string str = - let i = De.bigstring_create De.io_buffer_size in - let o = De.bigstring_create De.io_buffer_size in - let allocate bits = De.make_window ~bits in - let r = Buffer.create 0x1000 in - let p = ref 0 in - let refill buf = - let len = min (String.length str - !p) De.io_buffer_size in - Bigstringaf.blit_from_string str ~src_off:!p buf ~dst_off:0 ~len ; - p := !p + len ; - len - in - let flush buf len = - let str = Bigstringaf.substring buf ~off:0 ~len in - Buffer.add_string r str - in - match Zl.Higher.uncompress ~allocate ~refill ~flush i o with - | Ok () -> Ok (Buffer.contents r) - | Error _ as err -> err - let save ~db t = let str = Marshal.to_string t [] in let str = deflate_string str in @@ -54,16 +32,4 @@ let save ~db t = let load str = (* let str = Base64.decode_exn str in let str = inflate_string str |> Result.get_ok in *) - let db_types, db_names = Marshal.from_string str 0 in - let db_types = - Db.Trie.map_leaf - ~f:(fun occs -> - Int.Map.map (fun arr -> arr |> Array.to_seq |> Db.Elt.Set.of_seq) occs) - db_types - in - let db_names = - Db.Trie.map_leaf - ~f:(fun arr -> arr |> Array.to_seq |> Db.Elt.Set.of_seq) - db_names - in - [ Db.{ db_types; db_names } ] + [ Marshal.from_string str 0 ] diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 8b8fb31087..aa4d88cee7 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -6,10 +6,10 @@ loading doc ! doc loaded - real 0m16.433s - user 0m16.294s - sys 0m0.100s - $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null + real 0m15.087s + user 0m14.968s + sys 0m0.076s + $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null Index_lib.main loading doc ! doc loaded @@ -21,15 +21,15 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k db.js $ gzip -k db_marshal.bin - gzip: db_marshal.bin: No such file or directory - [1] $ gzip -k megaodocl - $ du -s *.js *.gz + $ du -s *.js *.gz *.bin 3056 db.js 2296 db.js.gz + 2180 db_marshal.bin.gz 1628 megaodocl.gz + 6716 db_marshal.bin $ for f in $(find . -name '*.odocl'); do @@ -38,6 +38,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ odoc support-files -o html $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js $ cp sherlodoc_db.bin html + cp: cannot stat 'sherlodoc_db.bin': No such file or directory + [1] $ du -sh html/index.js 7.9M html/index.js $ ls html @@ -49,6 +51,5 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr katex.min.js odoc.css odoc_search.js - sherlodoc_db.bin $ cp -r html /tmp $ firefox /tmp/html/base/index.html diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 7b593dea85..1eca26f169 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -6,14 +6,10 @@ $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 8.0K megaodocl - $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main loading doc ! doc loaded - - real 0m0.010s - user 0m0.004s - sys 0m0.006s $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null Index_lib.main loading doc ! @@ -25,9 +21,6 @@ $ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -n $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null $ gzip -k db.js - $ gzip -k db_marshal.bin - gzip: db_marshal.bin: No such file or directory - [1] $ gzip -k megaodocl From 61c2b83f692ef83ff609f9a05998fcc80899e00a Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 5 Jun 2023 16:18:59 +0200 Subject: [PATCH 075/285] Query arrays directly --- bin/JSherlodoc/main.ml | 1 + dune-project | 3 +- lib/common/array.ml | 74 +++++++++++++++++++++++++++++++ lib/common/common.ml | 11 +++++ lib/common/common_.ml | 4 ++ lib/db/elt.ml | 5 +++ lib/index_lib/load_doc.ml | 24 ---------- lib/query/query.ml | 7 +++ lib/query/succ.ml | 26 +++++------ sherlodoc.opam | 1 + test/unit/dune | 3 ++ test/unit/test.ml | 93 +++++++++++++++++++++++++++++++++++++++ 12 files changed, 211 insertions(+), 41 deletions(-) create mode 100644 lib/common/common.ml create mode 100644 lib/common/common_.ml create mode 100644 test/unit/dune create mode 100644 test/unit/test.ml diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 70b67be471..38d2fdc9e3 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -103,6 +103,7 @@ let search message = let _pretty_query, results = Query.(api ~shards:db { query; packages = []; limit = 50 }) in + Printf.printf "Got %i results\n%!" (List.length results) ; let _ = Jv.(apply (get global "postMessage")) [| Jv.of_list diff --git a/dune-project b/dune-project index 97b5461d42..83ab1e943a 100644 --- a/dune-project +++ b/dune-project @@ -28,4 +28,5 @@ (odoc (= 2.1.0)) opam-core - tyxml)) + tyxml + (alcotest :with-test))) diff --git a/lib/common/array.ml b/lib/common/array.ml index 3161b2f923..10557551ca 100644 --- a/lib/common/array.ml +++ b/lib/common/array.ml @@ -1,6 +1,80 @@ +open Common_ include Stdlib.Array let equal (a : 'a -> 'a -> bool) arr arr' = if arr == arr' then true else length arr = length arr' && for_all2 a arr arr' let hash (a : 'a -> int) arr = Hashtbl.hash (map a arr) + +let rec succ_ge ~compare elt arr lo hi = + let elt_lo = get arr lo in + if ge ~compare elt_lo elt + then elt_lo + else if lo = hi + then (* in that case, above branch should have been triggered *) + assert false + else if lo = hi - 1 + then ( + let elt_hi = get arr hi in + assert (ge ~compare elt_hi elt) ; + elt_hi) + else + let mid = (lo + hi) / 2 in + let elt' = get arr mid in + let comp = compare elt' elt in + if comp = 0 + then elt' + else if comp > 0 + then succ_ge ~compare elt arr lo mid + else succ_ge ~compare elt arr mid hi + +let succ_ge ~compare elt arr = + if length arr = 0 + then None + else + let lo = 0 and hi = length arr in + if not (ge ~compare (get arr (hi - 1)) elt) + then None + else Some (succ_ge ~compare elt arr lo hi) + +let rec succ_gt ~compare elt arr lo hi = + let elt_lo = get arr lo in + if gt ~compare elt_lo elt + then elt_lo + else if lo = hi + then (* in that case, above branch should have been triggered *) + assert false + else if lo = hi - 1 + then ( + (* lo is already checked above *) + let elt_hi = get arr hi in + assert (gt ~compare elt_hi elt) ; + elt_hi) + else + let mid = (lo + hi) / 2 in + let elt' = get arr mid in + let comp = compare elt' elt in + if comp = 0 + then get arr (mid + 1) + else if comp > 0 + then succ_gt ~compare elt arr lo mid + else succ_gt ~compare elt arr mid hi + +let succ_gt ~compare elt arr = + if length arr = 0 + then None + else + let lo = 0 and hi = length arr in + if not (gt ~compare (get arr (hi - 1)) elt) + then None + else Some (succ_gt ~compare elt arr lo hi) + +let succ_gt_exn ~compare elt arr = + match succ_gt ~compare elt arr with + | None -> raise Not_found + | Some v -> v + +let succ_ge_exn ~compare elt arr = + match succ_ge ~compare elt arr with + | None -> raise Not_found + | Some v -> v diff --git a/lib/common/common.ml b/lib/common/common.ml new file mode 100644 index 0000000000..2da92646f0 --- /dev/null +++ b/lib/common/common.ml @@ -0,0 +1,11 @@ +include Common_ +module Array = Array +module Char_list_map = Char_list_map +module Char = Char +module Int = Int +module List = List +module Map = Map +module Option = Option +module Set = Set +module String_list_map = String_list_map +module Array_map = Array_map (* todo delete *) diff --git a/lib/common/common_.ml b/lib/common/common_.ml new file mode 100644 index 0000000000..96b079b2da --- /dev/null +++ b/lib/common/common_.ml @@ -0,0 +1,4 @@ +let le ~compare v v' = compare v v' <= 0 +let lt ~compare v v' = compare v v' < 0 +let ge ~compare v v' = compare v v' >= 0 +let gt ~compare v v' = compare v v' > 0 diff --git a/lib/db/elt.ml b/lib/db/elt.ml index 6be7ba4b72..e40625a0b2 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -72,6 +72,11 @@ end include T let equal a b = compare a b = 0 +let ( = ) = equal +let ( < ) e e' = compare e e' < 0 +let ( <= ) e e' = compare e e' <= 0 +let ( > ) e e' = compare e e' > 0 +let ( >= ) e e' = compare e e' >= 0 let hash : t -> int = Hashtbl.hash module Set = Set.Make (T) diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 5fad19e5a7..f392b7fde6 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -135,33 +135,9 @@ module Make (Storage : Db.Storage.S) = struct let open Odoc_model.Lang in TypeExpr.Arrow (None, parent_type, type_) - let generic_cost ~ignore_no_doc full_name doc = - String.length full_name - (* + (5 * List.length path) TODO : restore depth based ordering *) - + (if ignore_no_doc - then 0 - else - match Elt.(doc.txt) with - | "" -> 1000 - | _ -> 0) - + if String.starts_with ~prefix:"Stdlib." full_name then -100 else 0 - let type_cost type_ = String.length (Odoc_search.Render.text_of_type type_) + type_size type_ - let kind_cost (kind : Odoc_search.Entry.extra) = - let open Odoc_search.Entry in - match kind with - | Constructor { args; res } -> - type_cost (searchable_type_of_constructor args res) - | Field { parent_type; type_; _ } -> - type_cost (searchable_type_of_record parent_type type_) - | Value { value = _; type_ } -> type_cost type_ - | Doc _ -> 400 - | TypeDecl _ | Module | Exception _ | Class_type _ | Method _ | Class _ - | TypeExtension _ | ExtensionConstructor _ | ModuleType -> - 200 - let convert_kind (kind : Odoc_search.Entry.extra) = let open Odoc_search.Entry in match kind with diff --git a/lib/query/query.ml b/lib/query/query.ml index 0689461924..49ad9c3e02 100644 --- a/lib/query/query.ml +++ b/lib/query/query.ml @@ -96,12 +96,19 @@ let match_packages ~packages results = | _ -> Seq.filter (match_packages ~packages) results let api ~(shards : Db.Elt.t array Db.t list) params = + print_endline "api" ; let query_name, query_typ, query_typ_arrow, pretty = Parser.of_string params.query in + print_endline "api 1" ; let results = search ~shards query_name query_typ in + print_endline "api 2" ; let results = Succ.to_seq results in + print_endline "api 3" ; let results = match_packages ~packages:params.packages results in + print_endline "api 4" ; let results = List.of_seq @@ Seq.take params.limit results in + print_endline "api 5" ; let results = Sort.list query_name query_typ_arrow results in + print_endline "api end" ; pretty, results diff --git a/lib/query/succ.ml b/lib/query/succ.ml index 7039f842d0..09b8dcaf20 100644 --- a/lib/query/succ.ml +++ b/lib/query/succ.ml @@ -1,9 +1,10 @@ open Db +open Common type s = | All | Empty - | Set of Elt.Set.t + | Array of Elt.t array | Inter of s * s | Union of s * s @@ -15,15 +16,10 @@ type t = let all = { cardinal = -1; s = All } let empty = { cardinal = 0; s = Empty } -let of_set s = - if Elt.Set.is_empty s - then empty - else { cardinal = Elt.Set.cardinal s; s = Set s } - let of_array arr = - let li = Array.to_list arr in - let set = Elt.Set.of_list li in - of_set set + if Array.length arr = 0 + then empty + else { cardinal = Array.length arr; s = Array arr } let inter a b = match a.s, b.s with @@ -43,17 +39,15 @@ let union a b = let x, y = if a.cardinal < b.cardinal then x, y else y, x in { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } -let succ_ge' elt set = Elt.Set.find_first (fun e -> Elt.compare e elt >= 0) set -let succ_gt' elt set = Elt.Set.find_first (fun e -> Elt.compare e elt > 0) set -let first' set = Elt.Set.find_first (fun _ -> true) set +let array_first arr = arr.(0) exception Gt of Elt.t let rec succ_ge elt = function | All -> elt | Empty -> raise Not_found - | Set s -> - let out = succ_ge' elt s in + | Array s -> + let out = Array.succ_ge_exn ~compare:Elt.compare elt s in begin match Elt.compare elt out with | 0 -> elt @@ -83,7 +77,7 @@ let rec succ_ge elt = function let rec succ_gt elt = function | All -> invalid_arg "Succ.succ_gt All" | Empty -> raise Not_found - | Set s -> succ_gt' elt s + | Array s -> Array.succ_gt_exn ~compare:Elt.compare elt s | Inter (a, _b) -> succ_gt elt a | Union (a, b) -> begin match succ_gt_opt elt a, succ_gt_opt elt b with @@ -101,7 +95,7 @@ and succ_gt_opt elt t = try Some (succ_gt elt t) with Not_found -> None let rec first = function | All -> invalid_arg "Succ.first All" | Empty -> raise Not_found - | Set s -> first' s + | Array s -> array_first s | Inter (a, _b) -> first a | Union (a, b) -> begin match first_opt a, first_opt b with diff --git a/sherlodoc.opam b/sherlodoc.opam index 1b9de2484b..3bfb703b4e 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -15,6 +15,7 @@ depends: [ "odoc" {= "2.1.0"} "opam-core" "tyxml" + "alcotest" {with-test} ] build: [ ["dune" "subst"] {dev} diff --git a/test/unit/dune b/test/unit/dune new file mode 100644 index 0000000000..303021488f --- /dev/null +++ b/test/unit/dune @@ -0,0 +1,3 @@ +(test + (name test) + (libraries alcotest common)) diff --git a/test/unit/test.ml b/test/unit/test.ml new file mode 100644 index 0000000000..7c80b40fa0 --- /dev/null +++ b/test/unit/test.ml @@ -0,0 +1,93 @@ +open Common + +let rec succ_ge_reference i ~compare elt arr = + Printf.printf "ref_succ_ge %i\n%!" i ; + if i = Array.length arr + then None + else if ge ~compare arr.(i) elt + then Some arr.(i) + else succ_ge_reference (i + 1) ~compare elt arr + +let rec succ_gt_reference i ~compare elt arr = + if i = Array.length arr + then None + else if gt ~compare arr.(i) elt + then Some arr.(i) + else succ_gt_reference (i + 1) ~compare elt arr + +let succ_ge_reference ~compare elt arr = succ_ge_reference 0 ~compare elt arr +let succ_gt_reference ~compare elt arr = succ_gt_reference 0 ~compare elt arr + +let test_succ_ge elt arr () = + Alcotest.(check (option int)) + "same int option" + (succ_ge_reference ~compare:Int.compare elt arr) + (Array.succ_ge ~compare:Int.compare elt arr) + +let test_succ_gt elt arr () = + Alcotest.(check (option int)) + "same int option" + (succ_gt_reference ~compare:Int.compare elt arr) + (Array.succ_gt ~compare:Int.compare elt arr) + +let () = Random.init 123 + +(* The tests *) + +let random_array size = + let r = + List.init size (fun _ -> Random.full_int (size * 2)) + |> List.sort_uniq Int.compare |> Array.of_list + in + + r + +let test_ge a b = + Alcotest.test_case (Printf.sprintf "ge %i %i" a b) `Quick (fun () -> + Alcotest.(check bool) "same bool" (ge ~compare:Int.compare a b) (a >= b)) + +let test_gt a b = + Alcotest.test_case (Printf.sprintf "gt %i %i" a b) `Quick (fun () -> + Alcotest.(check bool) "same bool" (gt ~compare:Int.compare a b) (a > b)) + +let test_lt a b = + Alcotest.test_case (Printf.sprintf "lt %i %i" a b) `Quick (fun () -> + Alcotest.(check bool) "same bool" (lt ~compare:Int.compare a b) (a < b)) + +let test_le a b = + Alcotest.test_case (Printf.sprintf "le %i %i" a b) `Quick (fun () -> + Alcotest.(check bool) "same bool" (le ~compare:Int.compare a b) (a <= b)) + +let test_operators = + (let a = 12 and b = 12 in + [ test_ge a b; test_gt a b; test_le a b; test_lt a b ]) + @ (let a = 12 and b = 14 in + [ test_ge a b; test_gt a b; test_le a b; test_lt a b ]) + @ + let a = 15 and b = 10 in + [ test_ge a b; test_gt a b; test_le a b; test_lt a b ] + +let tests_arr name test = + List.init 50 (fun i -> + let elt = Random.full_int ((i * 2) + 1) in + let arr = random_array i in + let arr_string = + if i <= 5 + then + "[|" + ^ (arr |> Array.to_list |> List.map string_of_int + |> String.concat "; ") + ^ "|]" + else "[|...|]" + in + Alcotest.test_case + (Printf.sprintf "%s %i %s " name elt arr_string) + `Quick (test elt arr)) + +let tests_succ_ge = tests_arr "succ_ge" test_succ_ge +let tests_succ_gt = tests_arr "succ_gt" test_succ_gt + +let () = + let open Alcotest in + run "Common" + [ "Common", test_operators; "Array", tests_succ_ge @ tests_succ_gt ] From e4c613843681b3cded1bae350457e036d925d1ac Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 5 Jun 2023 16:36:35 +0200 Subject: [PATCH 076/285] Restore static order --- lib/db/elt.ml | 38 ++++++++++++++++++++++++++++++++++++-- lib/index_lib/load_doc.ml | 15 ++++----------- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/lib/db/elt.ml b/lib/db/elt.ml index e40625a0b2..71cd702dcf 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -55,7 +55,34 @@ module T = struct let compare_pkg { name; version = _ } (b : package) = String.compare name b.name - let compare a b = + let generic_cost ~ignore_no_doc name has_doc = + String.length name + (* + (5 * List.length path) TODO : restore depth based ordering *) + + (if ignore_no_doc || has_doc then 0 else 1000) + + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 + + let type_cost paths = + paths |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 + + let kind_cost (kind : kind) = + match kind with + | Constructor type_path | Field type_path | Val type_path -> + type_cost type_path + | Doc -> 400 + | TypeDecl | Module | Exception | Class_type | Method | Class + | TypeExtension | ExtensionConstructor | ModuleType -> + 200 + + let cost { name; kind; has_doc; pkg = _; json_display = _ } = + let ignore_no_doc = + match kind with + | Module | ModuleType -> true + | _ -> false + in + (* TODO : use entry cost *) + generic_cost ~ignore_no_doc name has_doc + kind_cost kind + + let structural_compare a b = begin match String.compare a.name b.name with | 0 -> begin @@ -66,7 +93,14 @@ module T = struct | c -> c end - let compare a b = if a == b then 0 else compare a b + let compare a b = + if a == b + then 0 + else + let cost_a = cost a in + let cost_b = cost b in + let cmp = Int.compare cost_a cost_b in + if cmp = 0 then structural_compare a b else cmp end include T diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index f392b7fde6..0cac318030 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -9,6 +9,9 @@ module Make (Storage : Db.Storage.S) = struct let clear () = Cache.clear () + (* + + todo : check usefulness let rec type_size = function | Odoc_model.Lang.TypeExpr.Var _ -> 1 | Any -> 1 @@ -20,7 +23,7 @@ module Make (Storage : Db.Storage.S) = struct | Constr (_, args) -> List.fold_left (fun acc t -> acc + type_size t) 1 args | Tuple args -> List.fold_left (fun acc t -> acc + type_size t) 1 args | _ -> 100 - +*) let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst @@ -135,9 +138,6 @@ module Make (Storage : Db.Storage.S) = struct let open Odoc_model.Lang in TypeExpr.Arrow (None, parent_type, type_) - let type_cost type_ = - String.length (Odoc_search.Render.text_of_type type_) + type_size type_ - let convert_kind (kind : Odoc_search.Entry.extra) = let open Odoc_search.Entry in match kind with @@ -209,13 +209,6 @@ module Make (Storage : Db.Storage.S) = struct Elt.{ html; txt } in let kind' = convert_kind extra in - let ignore_no_doc = - match extra with - | Module | ModuleType -> true - | _ -> false - in - (* TODO : use entry cost *) - let _cost = generic_cost ~ignore_no_doc full_name doc + kind_cost extra in let name = match extra with | Doc _ -> Pretty.prefixname id From dcaa254f40af43a87af26b47f81e83784b829c02 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 6 Jun 2023 16:04:42 +0200 Subject: [PATCH 077/285] Cleanup --- bin/JSherlodoc/main.ml | 2 +- lib/common/char.ml | 2 + lib/common/common.ml | 4 +- lib/common/list.ml | 2 + lib/common/map.ml | 2 + lib/common/option.ml | 4 + lib/common/set.ml | 4 +- lib/common/string.ml | 3 + {test/unit => lib/common/test}/dune | 0 {test/unit => lib/common/test}/test.ml | 0 lib/db/cache.ml | 151 ++++++++++++++----------- lib/db/cache.mli | 31 +++-- lib/db/db.ml | 35 +++--- lib/db/elt.ml | 123 ++++++++++++-------- lib/db/trie.ml | 16 ++- lib/db/trie.mli | 15 +++ lib/index_lib/load_doc.ml | 11 +- lib/query/sort.ml | 30 ++--- test/cram/base.t/run.t | 22 ++-- 19 files changed, 282 insertions(+), 175 deletions(-) create mode 100644 lib/common/string.ml rename {test/unit => lib/common/test}/dune (100%) rename {test/unit => lib/common/test}/test.ml (100%) create mode 100644 lib/db/trie.mli diff --git a/bin/JSherlodoc/main.ml b/bin/JSherlodoc/main.ml index 38d2fdc9e3..acf4618e21 100644 --- a/bin/JSherlodoc/main.ml +++ b/bin/JSherlodoc/main.ml @@ -1,5 +1,5 @@ let string_of_kind (kind : Db.Elt.kind) = - let open Db.Elt in + let open Db.Elt.Kind in match kind with | Doc -> "doc" | TypeDecl -> "type" diff --git a/lib/common/char.ml b/lib/common/char.ml index b76da69d6c..1f87eddaf2 100644 --- a/lib/common/char.ml +++ b/lib/common/char.ml @@ -1,3 +1,5 @@ include Stdlib.Char module Map = Map.Make (Stdlib.Char) module Array_map = Array_map.Make (Stdlib.Char) + +let hash : char -> int = Hashtbl.hash diff --git a/lib/common/common.ml b/lib/common/common.ml index 2da92646f0..b098a7a0c5 100644 --- a/lib/common/common.ml +++ b/lib/common/common.ml @@ -1,3 +1,5 @@ +(** Stdlib extensions and common data structures *) + include Common_ module Array = Array module Char_list_map = Char_list_map @@ -8,4 +10,4 @@ module Map = Map module Option = Option module Set = Set module String_list_map = String_list_map -module Array_map = Array_map (* todo delete *) +module String = String diff --git a/lib/common/list.ml b/lib/common/list.ml index 38809c948e..14b20cf7b9 100644 --- a/lib/common/list.ml +++ b/lib/common/list.ml @@ -5,3 +5,5 @@ let sort_map ~f ~compare li = |> map (fun elt -> elt, f elt) |> sort (fun (_, wit) (_, wit') -> compare wit wit') |> map (fun (elt, _) -> elt) + +let hash hash_a li = li |> map hash_a |> Hashtbl.hash diff --git a/lib/common/map.ml b/lib/common/map.ml index 0e9b2db8d1..34fdd1d6a7 100644 --- a/lib/common/map.ml +++ b/lib/common/map.ml @@ -473,6 +473,7 @@ module Make (Ord : OrderedType) = struct | Node { l; v; d; r } -> cons_enum l (More (v, d, r, e)) let compare cmp m1 m2 = + if m1 == m2 then 0 else let rec compare_aux e1 e2 = match e1, e2 with | End, End -> 0 @@ -491,6 +492,7 @@ module Make (Ord : OrderedType) = struct compare_aux (cons_enum m1 End) (cons_enum m2 End) let equal cmp m1 m2 = + if m1 == m2 then true else let rec equal_aux e1 e2 = match e1, e2 with | End, End -> true diff --git a/lib/common/option.ml b/lib/common/option.ml index be6ca1d4d5..643112e48e 100644 --- a/lib/common/option.ml +++ b/lib/common/option.ml @@ -4,3 +4,7 @@ module O = struct let ( let* ) = bind let ( let+ ) v f = map f v end + +let hash hash_a = function + | Some a -> Hashtbl.hash (Some (hash_a a)) + | None -> Hashtbl.hash None diff --git a/lib/common/set.ml b/lib/common/set.ml index a427c722c5..3b51db8247 100644 --- a/lib/common/set.ml +++ b/lib/common/set.ml @@ -399,7 +399,9 @@ module Make (Ord : OrderedType) = struct let c = Ord.compare v1 v2 in if c <> 0 then c else compare_aux (cons_enum r1 e1) (cons_enum r2 e2) - let compare s1 s2 = compare_aux (cons_enum s1 End) (cons_enum s2 End) + let compare s1 s2 = + if s1 == s2 then 0 else compare_aux (cons_enum s1 End) (cons_enum s2 End) + let equal s1 s2 = compare s1 s2 = 0 let rec subset s1 s2 = diff --git a/lib/common/string.ml b/lib/common/string.ml new file mode 100644 index 0000000000..7980b7aaa7 --- /dev/null +++ b/lib/common/string.ml @@ -0,0 +1,3 @@ +include Stdlib.String + +let hash : t -> int = Hashtbl.hash \ No newline at end of file diff --git a/test/unit/dune b/lib/common/test/dune similarity index 100% rename from test/unit/dune rename to lib/common/test/dune diff --git a/test/unit/test.ml b/lib/common/test/test.ml similarity index 100% rename from test/unit/test.ml rename to lib/common/test/test.ml diff --git a/lib/db/cache.ml b/lib/db/cache.ml index 6d92a24cb6..6cb42cb82c 100644 --- a/lib/db/cache.ml +++ b/lib/db/cache.ml @@ -3,33 +3,45 @@ open Common let clears = ref [] let clear () = Common.List.iter (fun f -> f ()) !clears -module type Elt = sig +module type Cached = sig type t + val memo : t -> t +end + +(** The result of the [Make] functor. [equal] and [hash] are reexported for + composability with other functors. *) +module type Memo = sig + include Cached + val equal : t -> t -> bool val hash : t -> int - val sub : memo:(t -> t) -> t -> t end -module type Memo = sig +(** This module specifies what is need to construct a cache. *) +module type Cachable = sig type t val equal : t -> t -> bool val hash : t -> int - val memo : t -> t + + val sub : memo:(t -> t) -> t -> t + (** [sub ~memo (v : t)] should replace subvalues [v'] of type [t] by [memo v'], + and subvalues [a] of type [A.t] by [A.memo a]. *) end -module Make (Element : Elt) : Memo with type t = Element.t = struct - type t = Element.t +(** Builds a cache from an cachable type.*) +module Make (Elt : Cachable) : Memo with type t = Elt.t = struct + type t = Elt.t - let equal = Element.equal - let hash = Element.hash + let equal = Elt.equal + let hash = Elt.hash module H = Hashtbl.Make (struct - type t = Element.t + type t = Elt.t - let equal = Element.equal - let hash = Element.hash + let equal = Elt.equal + let hash = Elt.hash end) let cache = H.create 16 @@ -38,17 +50,21 @@ module Make (Element : Elt) : Memo with type t = Element.t = struct let rec memo str = try H.find cache str with Not_found -> - let str = Element.sub ~memo str in + let str = Elt.sub ~memo str in H.add cache str str ; str end -module Make_sub_only (Element : Elt) : Memo with type t = Element.t = struct - type t = Element.t +(** Does not build a cache, but exposes functions that caches that subvalues of + a given cache. This is useful for big value with a lot of subvalues, an + expansive [hash] and [equal] function, and not a lot of opportunities for + sharing. *) +module Make_sub_only (Elt : Cachable) : Memo with type t = Elt.t = struct + type t = Elt.t let equal = ( = ) let hash = Hashtbl.hash - let rec memo str = Element.sub ~memo str + let rec memo str = Elt.sub ~memo str end (** This module does not use {!Make} because it does not actually cache anything, @@ -69,13 +85,28 @@ module String = Make (struct let hash = Hashtbl.hash let equal = String.equal - let sub ~memo:_ str = String.init (String.length str) (String.get str) + + let sub ~memo:_ str = + (* not returning [str] here is required by [Ancient]. *) + String.init (String.length str) (String.get str) +end) + +module Option (A : Memo) = Make (struct + type t = A.t option + + let equal = Option.equal A.equal + let hash = Option.hash A.hash + + let sub ~memo:_ opt = + match opt with + | Some a -> Some (A.memo a) + | None -> None end) module List (A : Memo) = Make (struct type t = A.t list - let hash li = li |> List.map A.hash |> Hashtbl.hash + let hash = List.hash A.hash let equal = List.equal A.equal let rec sub ~memo lst = @@ -96,14 +127,37 @@ module Char_list = List (Char) module String_list = List (String) module String_list_list = List (String_list) +module Kind = Make (struct + include Elt.Kind + + let sub ~memo:_ k = + match k with + | Constructor type_path -> Constructor (String_list_list.memo type_path) + | Field type_path -> Constructor (String_list_list.memo type_path) + | Val type_path -> Constructor (String_list_list.memo type_path) + | _ -> k +end) + +module Package = Make (struct + include Elt.Package + + let sub ~memo:_ { name; version } = + { name = String.memo name; version = String.memo version } +end) + +module Package_option = Option (Package) + module Elt = struct include Make (struct + module Kind_memo = Kind include Elt - let sub ~memo:_ { name; kind; has_doc; pkg; json_display } = + let sub ~memo:_ Elt.{ name; kind; has_doc; pkg; json_display } = let name = String.memo name in let json_display = String.memo json_display in - { name; kind; has_doc; pkg; json_display } + (* For unknown reasons, this causes a terrible performance drop. *) + (* let kind = Kind_memo.memo kind in *) + Elt.{ name; kind; has_doc; pkg; json_display } end) module Set = Elt.Set @@ -115,14 +169,13 @@ module Set (A : Memo) (S : Set.S with type elt = A.t) = Make (struct type t = S.t let equal = S.equal - - let hash m = - m |> S.elements |> Common.List.map (fun v -> A.hash v) |> Hashtbl.hash + let hash m = m |> S.elements |> Common.List.hash A.hash let sub ~memo set = match set with | S.Empty -> S.Empty | S.Node { l; v; r; h } -> + (* This shares subset. Not actually very useful on tested exemples. *) let l = memo l in let v = A.memo v in let r = memo r in @@ -143,47 +196,17 @@ module Map (A : Memo) (M : Map.S) = Make (struct match m with | M.Empty -> M.Empty | M.Node { l; v; d; r; h } -> + (* This shares submaps ! *) let l = memo l in let r = memo r in let d = A.memo d in M.Node { l; v; d; r; h } end) -module Array_map (A : Memo) (M : Array_map.S) = Make (struct - type t = A.t M.t - - let equal = M.equal A.equal - - let hash m = - m |> M.to_array - |> Common.Array.map (fun (k, v) -> k, A.hash v) - |> Hashtbl.hash - - let sub ~memo:_ m = M.map ~f:A.memo m -end) - module Elt_set = Set (Elt) (Elt.Set) - -module Option (A : Memo) = Make (struct - type t = A.t option - - let equal = Option.equal A.equal - - let hash opt = - match opt with - | None -> Hashtbl.hash None - | Some a -> Hashtbl.hash (Some (A.hash a)) - - let sub ~memo:_ opt = - match opt with - | Some a -> Some (A.memo a) - | None -> None -end) - module Elt_set_option = Option (Elt_set) module Char_map (A : Memo) = Map (A) (Char.Map) module Int_map (A : Memo) = Map (A) (Int.Map) -module Char_array_map (A : Memo) = Array_map (A) (Char.Array_map) module Elt_array_occ = Int_map (Elt_array) module Elt_set_occ = Int_map (Elt_set) module Elt_set_char_map = Char_map (Elt_set) @@ -191,25 +214,25 @@ module Elt_set_char_map = Char_map (Elt_set) module Trie (A : Memo) : Memo with type t = A.t Trie.t = struct module A_option = Option (A) + (* Here [Make_sub_only] is good enough. Using [Make] instead slows down the + [Base] test by 50s for a 20ko gain. *) module rec M : (Memo with type t = A.t Trie.t) = Make_sub_only (struct type t = A.t Trie.t - let equal t1 t2 = - (*( = )*) - let open Trie in - match t1, t2 with - | Leaf (chars, elt), Leaf (chars', elt') -> - Char_list.equal chars chars' && A.equal elt elt' - | Node { leaf; children }, Node { leaf = leaf'; children = children' } -> - A_option.equal leaf leaf' && Children.equal children children' - | _ -> false + let equal = Trie.equal A.equal let hash trie = let open Trie in match trie with - | Leaf _ -> Hashtbl.hash trie + | Leaf (chars, a) -> + Hashtbl.hash + (Leaf (Obj.magic @@ Char_list.hash chars, Obj.magic @@ A.hash a)) | Node { leaf; children } -> - Hashtbl.hash (Hashtbl.hash leaf, Children.hash children) + Hashtbl.hash + (Node + { leaf = Obj.magic @@ A_option.hash leaf + ; children = Obj.magic @@ Children.hash children + }) let sub ~memo:_ trie = let open Trie in diff --git a/lib/db/cache.mli b/lib/db/cache.mli index 9b8995b0de..a45090ea55 100644 --- a/lib/db/cache.mli +++ b/lib/db/cache.mli @@ -1,21 +1,28 @@ +(** This module provides a way to do memory-sharing after the fact, for + a nuumber a OCaml types. + Every sharable element inside a type is also shared.*) + open Common val clear : unit -> unit +(** [clear ()] removes every value from the caches of every types. *) -module type Memo = sig +(** A type [t] and its [memo] function. *) +module type Cached = sig type t - val equal : t -> t -> bool - val hash : t -> int val memo : t -> t + (** [memo v] is [v] with the maximum amount of shared memory. As side effect + is to register [v] and its subvalues to be shared in the future. *) end -module String : Memo with type t = string -module Char_list : Memo with type t = char list -module String_list : Memo with type t = string list -module String_list_list : Memo with type t = string list list -module Elt_array : Memo with type t = Elt.t array -module Elt_set_trie : Memo with type t = Elt.Set.t Trie.t -module Elt_set_occ_trie : Memo with type t = Elt.Set.t Int.Map.t Trie.t -module Elt_array_trie : Memo with type t = Elt.t Array.t Trie.t -module Elt_array_occ_trie : Memo with type t = Elt.t Array.t Int.Map.t Trie.t +module String : Cached with type t = string +module Char_list : Cached with type t = char list +module String_list : Cached with type t = string list +module String_list_list : Cached with type t = string list list +module Kind : Cached with type t = Elt.Kind.t +module Elt_array : Cached with type t = Elt.t array +module Elt_set_trie : Cached with type t = Elt.Set.t Trie.t +module Elt_set_occ_trie : Cached with type t = Elt.Set.t Int.Map.t Trie.t +module Elt_array_trie : Cached with type t = Elt.t Array.t Trie.t +module Elt_array_occ_trie : Cached with type t = Elt.t Array.t Int.Map.t Trie.t diff --git a/lib/db/db.ml b/lib/db/db.ml index 2a7e6bff5f..6a038826dd 100644 --- a/lib/db/db.ml +++ b/lib/db/db.ml @@ -8,10 +8,7 @@ include Types module Occ = Int.Map let trie_with_array trie = - Trie.map_leaf - ~f:(fun set -> - set |> Elt.Set.to_seq |> Array.of_seq |> Cache.Elt_array.memo) - trie + Trie.map_leaf ~f:(fun set -> set |> Elt.Set.to_seq |> Array.of_seq) trie let trie_with_set trie = Trie.map_leaf ~f:(fun arr -> arr |> Array.to_seq |> Elt.Set.of_seq) trie @@ -19,9 +16,7 @@ let trie_with_set trie = let trie_with_array_occ trie = Trie.map_leaf ~f:(fun occs -> - occs - |> Int.Map.map (fun set -> - set |> Elt.Set.to_seq |> Array.of_seq |> Cache.Elt_array.memo)) + occs |> Int.Map.map (fun set -> set |> Elt.Set.to_seq |> Array.of_seq)) trie let trie_with_set_occ trie = @@ -33,10 +28,22 @@ let trie_with_set_occ trie = let compact db = let open Types in let { db_types; db_names } = db in + let t0 = Unix.gettimeofday () in let db_types = trie_with_array_occ db_types in + let t1 = Unix.gettimeofday () in let db_names = trie_with_array db_names in + let t2 = Unix.gettimeofday () in let db_types = Cache.Elt_array_occ_trie.memo db_types in + let t3 = Unix.gettimeofday () in let db_names = Cache.Elt_array_trie.memo db_names in + let t4 = Unix.gettimeofday () in + Printf.printf + "trie_with_array_occ:%.2fs\n\ + trie_with_array:%.2fs\n\ + Cache.Elt_array_occ_trie.memo:%.2fs\n\ + Cache.Elt_array_trie.memo:%.2fs\n\ + %!" + (t1 -. t0) (t2 -. t1) (t3 -. t2) (t4 -. t3) ; { db_types; db_names } let list_of_string s = List.init (String.length s) (String.get s) @@ -54,8 +61,8 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct type writer = Storage.writer let load_counter = ref 0 - let db_types = ref (Trie.empty ()) - let db_names = ref (Trie.empty ()) + let db_types = ref Trie.empty + let db_names = ref Trie.empty module Hset2 = Hashtbl.Make (struct type t = Elt.Set.t * Elt.Set.t @@ -76,8 +83,8 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let db = { db_types = !db_types; db_names = !db_names } in let db = compact db in Storage.save ~db:h db ; - db_types := Trie.empty () ; - db_names := Trie.empty () + db_types := Trie.empty ; + db_names := Trie.empty module Hset = Hashtbl.Make (struct type t = Elt.Set.t option @@ -133,8 +140,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let ho = Hocc.create 16 in let hs = Hset.create 16 in List.iter - (fun (path, count) -> - store ~ho ~hs ~count (Cache.Char_list.memo path) elt) + (fun (path, count) -> store ~ho ~hs ~count path elt) (regroup_chars paths) let store_type_paths elt paths = @@ -157,8 +163,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct db_names := go !db_names name let store_word word elt = - (word |> list_of_string |> List.rev |> Cache.Char_list.memo |> store_chars) - elt + (word |> list_of_string |> List.rev |> store_chars) elt end module Storage = Storage diff --git a/lib/db/elt.ml b/lib/db/elt.ml index 71cd702dcf..ec15347336 100644 --- a/lib/db/elt.ml +++ b/lib/db/elt.ml @@ -23,32 +23,81 @@ type type_path = string list list It is used to sort results. *) -type kind = - | Doc - | TypeDecl - | Module - | Exception - | Class_type - | Method - | Class - | TypeExtension - | ExtensionConstructor - | ModuleType - | Constructor of type_path - | Field of type_path - | Val of type_path - -type package = +let hash_type_path path = List.hash (List.hash String.hash) path + +module Kind = struct + type 'a abstract = + | Doc + | TypeDecl + | Module + | Exception + | Class_type + | Method + | Class + | TypeExtension + | ExtensionConstructor + | ModuleType + | Constructor of 'a + | Field of 'a + | Val of 'a + + type t = type_path abstract + + let hash k = + match k with + | Doc | TypeDecl | Module | Exception | Class_type | Method | Class + | TypeExtension | ExtensionConstructor | ModuleType -> + Hashtbl.hash k + | Constructor type_path -> + Hashtbl.hash (Constructor (hash_type_path type_path)) + | Field type_path -> Hashtbl.hash (Field (hash_type_path type_path)) + | Val type_path -> Hashtbl.hash (Val (hash_type_path type_path)) + + let equal = ( = ) + let doc = Doc + let type_decl = TypeDecl + let module_ = Module + let exception_ = Exception + let class_type = Class_type + let method_ = Method + let class_ = Class + let type_extension = TypeExtension + let extension_constructor = ExtensionConstructor + let module_type = ModuleType + let constructor type_path = Constructor type_path + let field type_path = Field type_path + let val_ type_path = Val type_path +end + +module Package = struct + type t = + { name : string + ; version : string + } + + let hash { name; version } = + Hashtbl.hash (String.hash name, String.hash version) + + let equal = ( = ) + + let v ~name ~version = let version = version in + + { name; version } +end + +type package = Package.t = { name : string ; version : string } +type kind = Kind.t + module T = struct type t = { name : string - ; kind : kind + ; kind : Kind.t ; has_doc : bool - ; pkg : package option + ; pkg : Package.t option ; json_display : string } @@ -105,13 +154,21 @@ end include T -let equal a b = compare a b = 0 +let equal a b = structural_compare a b = 0 let ( = ) = equal let ( < ) e e' = compare e e' < 0 let ( <= ) e e' = compare e e' <= 0 let ( > ) e e' = compare e e' > 0 let ( >= ) e e' = compare e e' >= 0 -let hash : t -> int = Hashtbl.hash + +let hash : t -> int = + fun { name; kind; has_doc; pkg; json_display } -> + Hashtbl.hash + ( Hashtbl.hash name + , Kind.hash kind + , Hashtbl.hash has_doc + , Option.hash Package.hash pkg + , Hashtbl.hash json_display ) module Set = Set.Make (T) @@ -130,32 +187,6 @@ let link t = let+ pkg_link = pkg_link t in pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name -module Kind = struct - type t = kind - - let doc = Doc - let type_decl = TypeDecl - let module_ = Module - let exception_ = Exception - let class_type = Class_type - let method_ = Method - let class_ = Class - let type_extension = TypeExtension - let extension_constructor = ExtensionConstructor - let module_type = ModuleType - let constructor type_path = Constructor type_path - let field type_path = Field type_path - let val_ type_path = Val type_path -end - -module Package = struct - type t = package - - let v ~name ~version = let version = version in - - { name; version } -end - let v ~name ~kind ~has_doc ?(pkg = None) ~json_display () = let json_display = json_display in { name; kind; has_doc; pkg; json_display } diff --git a/lib/db/trie.ml b/lib/db/trie.ml index b9802b51fc..5d5fbee13d 100644 --- a/lib/db/trie.ml +++ b/lib/db/trie.ml @@ -8,11 +8,12 @@ type 'a t = ; children : 'a t M.t } -let empty () = Node { leaf = None; children = M.empty } +let empty = Node { leaf = None; children = M.empty } let rec add path leaf t = match t, path with - | Node t, [] -> Node { t with leaf = Some (leaf t.leaf) } + | Node t, [] -> + Node { t with leaf = Some (leaf t.leaf) } | Node t, p :: path -> let child = match M.find p t.children with @@ -79,3 +80,14 @@ let rec map_leaf ~f t = let leaf = Option.map f leaf in let children = M.map (map_leaf ~f) children in Node { leaf; children } + +let rec equal a_eq t1 t2 = + if t1 == t2 + then true + else + match t1, t2 with + | Leaf (chars, elt), Leaf (chars', elt') -> + List.equal Char.equal chars chars' && a_eq elt elt' + | Node { leaf; children }, Node { leaf = leaf'; children = children' } -> + Option.equal a_eq leaf leaf' && M.equal (equal a_eq) children children' + | _ -> false diff --git a/lib/db/trie.mli b/lib/db/trie.mli new file mode 100644 index 0000000000..8a325c101f --- /dev/null +++ b/lib/db/trie.mli @@ -0,0 +1,15 @@ +open Common + +type 'a t = + | Leaf of char list * 'a + | Node of + { leaf : 'a option + ; children : 'a t Char.Map.t + } + +val empty : 'a t +val add : char list -> ('a option -> 'a) -> 'a t -> 'a t +val find : char list -> 'a t -> 'a t +val fold_map : ('a -> 'a -> 'a) -> ('b -> 'a) -> 'b t -> 'a option +val map_leaf : f:('a -> 'b) -> 'a t -> 'b t +val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool diff --git a/lib/index_lib/load_doc.ml b/lib/index_lib/load_doc.ml index 0cac318030..8bbe6e26f7 100644 --- a/lib/index_lib/load_doc.ml +++ b/lib/index_lib/load_doc.ml @@ -76,7 +76,7 @@ module Make (Storage : Db.Storage.S) = struct @@ args | _ -> [] in - Cache.String_list_list.memo r + r (** for indexing *) let rec type_paths ~prefix ~sgn = function @@ -108,7 +108,7 @@ module Make (Storage : Db.Storage.S) = struct | _ -> [] let type_paths ~prefix ~sgn t = - Cache.String_list_list.memo (type_paths ~prefix ~sgn t) + (type_paths ~prefix ~sgn t) let register_doc elt doc_txt = let doc_words = String.split_on_char ' ' doc_txt in @@ -141,8 +141,8 @@ module Make (Storage : Db.Storage.S) = struct let convert_kind (kind : Odoc_search.Entry.extra) = let open Odoc_search.Entry in match kind with - | TypeDecl _ -> Elt.TypeDecl - | Module -> Elt.ModuleType + | TypeDecl _ -> Elt.Kind.TypeDecl + | Module -> Elt.Kind.ModuleType | Value { value = _; type_ } -> let paths = paths ~prefix:[] ~sgn:Pos type_ in Elt.Kind.val_ paths @@ -166,6 +166,9 @@ module Make (Storage : Db.Storage.S) = struct | ExtensionConstructor _ -> ExtensionConstructor | ModuleType -> ModuleType + let convert_kind k = + k |> convert_kind |> Cache.Kind.memo + let register_type_expr elt type_ = let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in Db.store_type_paths elt type_paths diff --git a/lib/query/sort.ml b/lib/query/sort.ml index b7bedc2f62..2e83621060 100644 --- a/lib/query/sort.ml +++ b/lib/query/sort.ml @@ -144,7 +144,7 @@ module Reasoning = struct let with_words query_words elt = match elt.Elt.kind with - | Elt.Doc -> List.map (fun _ : t -> Doc) query_words + | Elt.Kind.Doc -> List.map (fun _ : t -> Doc) query_words | _ -> List.map (fun word -> with_word word elt.Elt.name) query_words let compare nm nm' = @@ -190,7 +190,7 @@ module Reasoning = struct let open Elt in match query_type, elt.kind with | [], _ -> None - | _, (Elt.Constructor type_paths | Elt.Field type_paths | Elt.Val type_paths) + | _, Elt.Kind.(Constructor type_paths | Field type_paths | Val type_paths) -> Some (Type_distance.v query_type type_paths) | _ -> None @@ -209,19 +209,19 @@ module Reasoning = struct let kind elt = match elt.Elt.kind with - | Elt.Doc -> Doc - | Elt.TypeDecl -> TypeDecl - | Elt.Module -> Module - | Elt.Exception -> Exception - | Elt.Class_type -> Class_type - | Elt.Method -> Method - | Elt.Class -> Class - | Elt.TypeExtension -> TypeExtension - | Elt.ExtensionConstructor -> ExtensionConstructor - | Elt.ModuleType -> ModuleType - | Elt.Constructor _ -> Constructor - | Elt.Field _ -> Field - | Elt.Val _ -> Val + | Elt.Kind.Doc -> Doc + | Elt.Kind.TypeDecl -> TypeDecl + | Elt.Kind.Module -> Module + | Elt.Kind.Exception -> Exception + | Elt.Kind.Class_type -> Class_type + | Elt.Kind.Method -> Method + | Elt.Kind.Class -> Class + | Elt.Kind.TypeExtension -> TypeExtension + | Elt.Kind.ExtensionConstructor -> ExtensionConstructor + | Elt.Kind.ModuleType -> ModuleType + | Elt.Kind.Constructor _ -> Constructor + | Elt.Kind.Field _ -> Field + | Elt.Kind.Val _ -> Val let name_length elt = String.length elt.Elt.name diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index aa4d88cee7..08da6a6acf 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -6,13 +6,10 @@ loading doc ! doc loaded - real 0m15.087s - user 0m14.968s - sys 0m0.076s - $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Index_lib.main - loading doc ! - doc loaded + real 0m18.813s + user 0m18.673s + sys 0m0.096s +$ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -20,16 +17,13 @@ $ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -n $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null $ gzip -k db.js - $ gzip -k db_marshal.bin $ gzip -k megaodocl - $ du -s *.js *.gz *.bin - 3056 db.js - 2296 db.js.gz - 2180 db_marshal.bin.gz + $ du -s *.js *.gz + 3196 db.js + 2408 db.js.gz 1628 megaodocl.gz - 6716 db_marshal.bin $ for f in $(find . -name '*.odocl'); do @@ -41,7 +35,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr cp: cannot stat 'sherlodoc_db.bin': No such file or directory [1] $ du -sh html/index.js - 7.9M html/index.js + 8.0M html/index.js $ ls html base fonts From 05e42115d43cd12d00854845dba6c176682c3b7f Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 7 Jun 2023 12:52:44 +0200 Subject: [PATCH 078/285] flat directory hierarchy --- bin/api/_dune | 4 - bin/api/main.ml | 92 ------------------ {lib/common => common}/array.ml | 0 {lib/common => common}/array_map.ml | 0 {lib/common => common}/char.ml | 0 {lib/common => common}/char_list_map.ml | 0 {lib/common => common}/common.ml | 0 {lib/common => common}/common_.ml | 0 {lib/common => common}/dune | 0 {lib/common => common}/int.ml | 0 {lib/common => common}/list.ml | 0 {lib/common => common}/map.ml | 0 {lib/common => common}/option.ml | 0 {lib/common => common}/set.ml | 0 {lib/common => common}/string.ml | 0 {lib/common => common}/string_list_map.ml | 0 {lib/common => common}/test/dune | 0 {lib/common => common}/test/test.ml | 0 {lib/db => db}/cache.ml | 0 {lib/db => db}/cache.mli | 0 {lib/db => db}/db.ml | 0 {lib/db => db}/db.mli | 0 {lib/db => db}/dune | 0 {lib/db => db}/elt.ml | 0 {lib/db => db}/storage.ml | 0 {lib/db => db}/trie.ml | 0 {lib/db => db}/trie.mli | 0 {lib/db => db}/types.ml | 0 {bin/index => index}/dune | 9 +- {bin/index => index}/index.ml | 0 {lib/index_lib => index}/index_lib.ml | 0 {lib/index_lib => index}/index_lib.mli | 0 {lib/index_lib => index}/load_doc.ml | 0 {lib/index_lib => index}/load_doc.mli | 0 {lib/index_lib => index}/pretty.ml | 0 {bin/JSherlodoc => jsoo}/dune | 0 {bin/JSherlodoc => jsoo}/index.html | 0 {bin/JSherlodoc => jsoo}/main.ml | 0 {bin/JSherlodoc => jsoo}/result.db | Bin {bin/JSherlodoc => jsoo}/style.css | 0 lib/index_lib/dune | 13 --- lib/storage_ancient/dune | 3 - lib/storage_js/dune | 3 - lib/storage_marshal/dune | 3 - odoc_output/mylib/1.0/main.odocl | Bin 71757 -> 0 bytes {lib/query => query}/dune | 0 {lib/query => query}/lexer.mll | 0 {lib/query => query}/parser.mly | 0 {lib/query => query}/query.ml | 0 {lib/query => query}/query.mli | 0 {lib/query => query}/query_ast.ml | 0 {lib/query => query}/query_parser.ml | 0 {lib/query => query}/sort.ml | 0 {lib/query => query}/succ.ml | 0 .../storage_ancient.ml | 0 .../storage_ancient.mli | 0 {lib/storage_js => store}/storage_js.ml | 0 {lib/storage_js => store}/storage_js.mli | 0 .../storage_marshal.ml | 0 .../storage_marshal.mli | 0 test/cram/base.t/run.t | 2 +- test/cram/dune | 2 +- test/cram/simple.t/run.t | 2 +- utils/dune | 2 - utils/utils.ml | 0 {bin/www => www}/_dune | 0 {bin/www => www}/packages.ml | 0 {bin/www => www}/ui.ml | 0 {bin/www => www}/www.ml | 0 69 files changed, 11 insertions(+), 124 deletions(-) delete mode 100644 bin/api/_dune delete mode 100644 bin/api/main.ml rename {lib/common => common}/array.ml (100%) rename {lib/common => common}/array_map.ml (100%) rename {lib/common => common}/char.ml (100%) rename {lib/common => common}/char_list_map.ml (100%) rename {lib/common => common}/common.ml (100%) rename {lib/common => common}/common_.ml (100%) rename {lib/common => common}/dune (100%) rename {lib/common => common}/int.ml (100%) rename {lib/common => common}/list.ml (100%) rename {lib/common => common}/map.ml (100%) rename {lib/common => common}/option.ml (100%) rename {lib/common => common}/set.ml (100%) rename {lib/common => common}/string.ml (100%) rename {lib/common => common}/string_list_map.ml (100%) rename {lib/common => common}/test/dune (100%) rename {lib/common => common}/test/test.ml (100%) rename {lib/db => db}/cache.ml (100%) rename {lib/db => db}/cache.mli (100%) rename {lib/db => db}/db.ml (100%) rename {lib/db => db}/db.mli (100%) rename {lib/db => db}/dune (100%) rename {lib/db => db}/elt.ml (100%) rename {lib/db => db}/storage.ml (100%) rename {lib/db => db}/trie.ml (100%) rename {lib/db => db}/trie.mli (100%) rename {lib/db => db}/types.ml (100%) rename {bin/index => index}/dune (63%) rename {bin/index => index}/index.ml (100%) rename {lib/index_lib => index}/index_lib.ml (100%) rename {lib/index_lib => index}/index_lib.mli (100%) rename {lib/index_lib => index}/load_doc.ml (100%) rename {lib/index_lib => index}/load_doc.mli (100%) rename {lib/index_lib => index}/pretty.ml (100%) rename {bin/JSherlodoc => jsoo}/dune (100%) rename {bin/JSherlodoc => jsoo}/index.html (100%) rename {bin/JSherlodoc => jsoo}/main.ml (100%) rename {bin/JSherlodoc => jsoo}/result.db (100%) rename {bin/JSherlodoc => jsoo}/style.css (100%) delete mode 100644 lib/index_lib/dune delete mode 100644 lib/storage_ancient/dune delete mode 100644 lib/storage_js/dune delete mode 100644 lib/storage_marshal/dune delete mode 100644 odoc_output/mylib/1.0/main.odocl rename {lib/query => query}/dune (100%) rename {lib/query => query}/lexer.mll (100%) rename {lib/query => query}/parser.mly (100%) rename {lib/query => query}/query.ml (100%) rename {lib/query => query}/query.mli (100%) rename {lib/query => query}/query_ast.ml (100%) rename {lib/query => query}/query_parser.ml (100%) rename {lib/query => query}/sort.ml (100%) rename {lib/query => query}/succ.ml (100%) rename {lib/storage_ancient => store}/storage_ancient.ml (100%) rename {lib/storage_ancient => store}/storage_ancient.mli (100%) rename {lib/storage_js => store}/storage_js.ml (100%) rename {lib/storage_js => store}/storage_js.mli (100%) rename {lib/storage_marshal => store}/storage_marshal.ml (100%) rename {lib/storage_marshal => store}/storage_marshal.mli (100%) delete mode 100644 utils/dune delete mode 100644 utils/utils.ml rename {bin/www => www}/_dune (100%) rename {bin/www => www}/packages.ml (100%) rename {bin/www => www}/ui.ml (100%) rename {bin/www => www}/www.ml (100%) diff --git a/bin/api/_dune b/bin/api/_dune deleted file mode 100644 index f630c01b88..0000000000 --- a/bin/api/_dune +++ /dev/null @@ -1,4 +0,0 @@ -(executable - (name main) - (public_name sherlodoc_api) - (libraries cmdliner dream db query storage_marshal)) diff --git a/bin/api/main.ml b/bin/api/main.ml deleted file mode 100644 index 51b959414a..0000000000 --- a/bin/api/main.ml +++ /dev/null @@ -1,92 +0,0 @@ -module Storage = Db.Storage -module Succ = Query.Succ -module Sort = Query.Sort -module H = Tyxml.Html - -let api ~shards params = - let r = Query.api ~shards params in - Lwt.return (Marshal.to_string r []) - -open Lwt.Syntax - -let get_query params = Option.value ~default:"" (Dream.query params "q") - -let get_packages params = - match Dream.query params "packages" with - | None -> [] - | Some str -> String.split_on_char ',' str - -let get_limit params = - let default = 100 in - match Dream.query params "limit" with - | None -> default - | Some str -> ( - try max 1 (min default (int_of_string str)) with _ -> default) - -let get_params params = - { Query.query = get_query params - ; packages = get_packages params - ; limit = get_limit params - } - -let root fn params = - let params = get_params params in - let* result = fn params in - Dream.respond result - -let string_of_tyxml html = Format.asprintf "%a" (Tyxml.Html.pp ()) html -let string_of_tyxml' html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) html - -let cache_header : int option -> Dream.middleware = - fun max_age f req -> - let+ response = f req in - begin - match max_age with - | None -> () - | Some max_age -> - Dream.add_header response "Cache-Control" - ("public, max-age=" ^ string_of_int max_age) - end ; - response - -let cors_header f req = - let+ response = f req in - Dream.add_header response "Access-Control-Allow-Origin" "*" ; - response - -let cors_options = - Dream.options "**" (fun _ -> - let+ response = Dream.empty `No_Content in - Dream.add_header response "Access-Control-Allow-Methods" "GET, OPTIONS" ; - Dream.add_header response "Access-Control-Allow-Headers" "*" ; - response) - -let main port db_filename cache_max_age = - let shards = Storage_marshal.load db_filename in - Dream.run ~interface:"127.0.0.1" ~port - @@ Dream.logger @@ cache_header cache_max_age @@ cors_header - @@ Dream.router - [ Dream.get "/" (root (fun params -> api ~shards params)); cors_options ] - -open Cmdliner - -let path = - let doc = "Database filename" in - Arg.(required & pos 0 (some file) None & info [] ~docv:"DB" ~doc) - -let port = - let doc = "Port" in - Arg.(value & opt int 1234 & info [] ~docv:"PORT" ~doc) - -let cache_max_age = - let doc = "HTTP cache max age (in seconds)" in - Arg.(value & opt (some int) None & info [ "c"; "cache" ] ~docv:"MAX_AGE" ~doc) - -let www = Term.(const main $ port $ path $ cache_max_age) - -let cmd = - let doc = "API for sherlodoc" in - let info = Cmd.info "shelodoc_api" ~doc in - Cmd.v info www - -let () = exit (Cmd.eval cmd) diff --git a/lib/common/array.ml b/common/array.ml similarity index 100% rename from lib/common/array.ml rename to common/array.ml diff --git a/lib/common/array_map.ml b/common/array_map.ml similarity index 100% rename from lib/common/array_map.ml rename to common/array_map.ml diff --git a/lib/common/char.ml b/common/char.ml similarity index 100% rename from lib/common/char.ml rename to common/char.ml diff --git a/lib/common/char_list_map.ml b/common/char_list_map.ml similarity index 100% rename from lib/common/char_list_map.ml rename to common/char_list_map.ml diff --git a/lib/common/common.ml b/common/common.ml similarity index 100% rename from lib/common/common.ml rename to common/common.ml diff --git a/lib/common/common_.ml b/common/common_.ml similarity index 100% rename from lib/common/common_.ml rename to common/common_.ml diff --git a/lib/common/dune b/common/dune similarity index 100% rename from lib/common/dune rename to common/dune diff --git a/lib/common/int.ml b/common/int.ml similarity index 100% rename from lib/common/int.ml rename to common/int.ml diff --git a/lib/common/list.ml b/common/list.ml similarity index 100% rename from lib/common/list.ml rename to common/list.ml diff --git a/lib/common/map.ml b/common/map.ml similarity index 100% rename from lib/common/map.ml rename to common/map.ml diff --git a/lib/common/option.ml b/common/option.ml similarity index 100% rename from lib/common/option.ml rename to common/option.ml diff --git a/lib/common/set.ml b/common/set.ml similarity index 100% rename from lib/common/set.ml rename to common/set.ml diff --git a/lib/common/string.ml b/common/string.ml similarity index 100% rename from lib/common/string.ml rename to common/string.ml diff --git a/lib/common/string_list_map.ml b/common/string_list_map.ml similarity index 100% rename from lib/common/string_list_map.ml rename to common/string_list_map.ml diff --git a/lib/common/test/dune b/common/test/dune similarity index 100% rename from lib/common/test/dune rename to common/test/dune diff --git a/lib/common/test/test.ml b/common/test/test.ml similarity index 100% rename from lib/common/test/test.ml rename to common/test/test.ml diff --git a/lib/db/cache.ml b/db/cache.ml similarity index 100% rename from lib/db/cache.ml rename to db/cache.ml diff --git a/lib/db/cache.mli b/db/cache.mli similarity index 100% rename from lib/db/cache.mli rename to db/cache.mli diff --git a/lib/db/db.ml b/db/db.ml similarity index 100% rename from lib/db/db.ml rename to db/db.ml diff --git a/lib/db/db.mli b/db/db.mli similarity index 100% rename from lib/db/db.mli rename to db/db.mli diff --git a/lib/db/dune b/db/dune similarity index 100% rename from lib/db/dune rename to db/dune diff --git a/lib/db/elt.ml b/db/elt.ml similarity index 100% rename from lib/db/elt.ml rename to db/elt.ml diff --git a/lib/db/storage.ml b/db/storage.ml similarity index 100% rename from lib/db/storage.ml rename to db/storage.ml diff --git a/lib/db/trie.ml b/db/trie.ml similarity index 100% rename from lib/db/trie.ml rename to db/trie.ml diff --git a/lib/db/trie.mli b/db/trie.mli similarity index 100% rename from lib/db/trie.mli rename to db/trie.mli diff --git a/lib/db/types.ml b/db/types.ml similarity index 100% rename from lib/db/types.ml rename to db/types.ml diff --git a/bin/index/dune b/index/dune similarity index 63% rename from bin/index/dune rename to index/dune index eab034c3a7..2238eb028f 100644 --- a/bin/index/dune +++ b/index/dune @@ -2,9 +2,16 @@ (public_name sherlodoc_index) (name index) (libraries + db + fpath + tyxml + opam-core odoc.search + odoc.loader + odoc.model + odoc.xref2 + odoc.odoc cmdliner - index_lib storage_ancient storage_marshal storage_js)) diff --git a/bin/index/index.ml b/index/index.ml similarity index 100% rename from bin/index/index.ml rename to index/index.ml diff --git a/lib/index_lib/index_lib.ml b/index/index_lib.ml similarity index 100% rename from lib/index_lib/index_lib.ml rename to index/index_lib.ml diff --git a/lib/index_lib/index_lib.mli b/index/index_lib.mli similarity index 100% rename from lib/index_lib/index_lib.mli rename to index/index_lib.mli diff --git a/lib/index_lib/load_doc.ml b/index/load_doc.ml similarity index 100% rename from lib/index_lib/load_doc.ml rename to index/load_doc.ml diff --git a/lib/index_lib/load_doc.mli b/index/load_doc.mli similarity index 100% rename from lib/index_lib/load_doc.mli rename to index/load_doc.mli diff --git a/lib/index_lib/pretty.ml b/index/pretty.ml similarity index 100% rename from lib/index_lib/pretty.ml rename to index/pretty.ml diff --git a/bin/JSherlodoc/dune b/jsoo/dune similarity index 100% rename from bin/JSherlodoc/dune rename to jsoo/dune diff --git a/bin/JSherlodoc/index.html b/jsoo/index.html similarity index 100% rename from bin/JSherlodoc/index.html rename to jsoo/index.html diff --git a/bin/JSherlodoc/main.ml b/jsoo/main.ml similarity index 100% rename from bin/JSherlodoc/main.ml rename to jsoo/main.ml diff --git a/bin/JSherlodoc/result.db b/jsoo/result.db similarity index 100% rename from bin/JSherlodoc/result.db rename to jsoo/result.db diff --git a/bin/JSherlodoc/style.css b/jsoo/style.css similarity index 100% rename from bin/JSherlodoc/style.css rename to jsoo/style.css diff --git a/lib/index_lib/dune b/lib/index_lib/dune deleted file mode 100644 index 71de3f538f..0000000000 --- a/lib/index_lib/dune +++ /dev/null @@ -1,13 +0,0 @@ -(library - (name index_lib) - (libraries - db - fpath - tyxml - opam-core - odoc.search - odoc.loader - odoc.model - odoc.xref2 - odoc.odoc - str)) diff --git a/lib/storage_ancient/dune b/lib/storage_ancient/dune deleted file mode 100644 index ecf5dc277b..0000000000 --- a/lib/storage_ancient/dune +++ /dev/null @@ -1,3 +0,0 @@ -(library - (name storage_ancient) - (libraries ancient db)) diff --git a/lib/storage_js/dune b/lib/storage_js/dune deleted file mode 100644 index 62e1488500..0000000000 --- a/lib/storage_js/dune +++ /dev/null @@ -1,3 +0,0 @@ -(library - (name storage_js) - (libraries db base64 bigstringaf decompress.zl)) diff --git a/lib/storage_marshal/dune b/lib/storage_marshal/dune deleted file mode 100644 index a11ca6debf..0000000000 --- a/lib/storage_marshal/dune +++ /dev/null @@ -1,3 +0,0 @@ -(library - (name storage_marshal) - (libraries db)) diff --git a/odoc_output/mylib/1.0/main.odocl b/odoc_output/mylib/1.0/main.odocl deleted file mode 100644 index 2f5addd9776978dea7d5ad7beb292db998c9c934..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71757 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 G`QLws@B^{{ diff --git a/lib/query/dune b/query/dune similarity index 100% rename from lib/query/dune rename to query/dune diff --git a/lib/query/lexer.mll b/query/lexer.mll similarity index 100% rename from lib/query/lexer.mll rename to query/lexer.mll diff --git a/lib/query/parser.mly b/query/parser.mly similarity index 100% rename from lib/query/parser.mly rename to query/parser.mly diff --git a/lib/query/query.ml b/query/query.ml similarity index 100% rename from lib/query/query.ml rename to query/query.ml diff --git a/lib/query/query.mli b/query/query.mli similarity index 100% rename from lib/query/query.mli rename to query/query.mli diff --git a/lib/query/query_ast.ml b/query/query_ast.ml similarity index 100% rename from lib/query/query_ast.ml rename to query/query_ast.ml diff --git a/lib/query/query_parser.ml b/query/query_parser.ml similarity index 100% rename from lib/query/query_parser.ml rename to query/query_parser.ml diff --git a/lib/query/sort.ml b/query/sort.ml similarity index 100% rename from lib/query/sort.ml rename to query/sort.ml diff --git a/lib/query/succ.ml b/query/succ.ml similarity index 100% rename from lib/query/succ.ml rename to query/succ.ml diff --git a/lib/storage_ancient/storage_ancient.ml b/store/storage_ancient.ml similarity index 100% rename from lib/storage_ancient/storage_ancient.ml rename to store/storage_ancient.ml diff --git a/lib/storage_ancient/storage_ancient.mli b/store/storage_ancient.mli similarity index 100% rename from lib/storage_ancient/storage_ancient.mli rename to store/storage_ancient.mli diff --git a/lib/storage_js/storage_js.ml b/store/storage_js.ml similarity index 100% rename from lib/storage_js/storage_js.ml rename to store/storage_js.ml diff --git a/lib/storage_js/storage_js.mli b/store/storage_js.mli similarity index 100% rename from lib/storage_js/storage_js.mli rename to store/storage_js.mli diff --git a/lib/storage_marshal/storage_marshal.ml b/store/storage_marshal.ml similarity index 100% rename from lib/storage_marshal/storage_marshal.ml rename to store/storage_marshal.ml diff --git a/lib/storage_marshal/storage_marshal.mli b/store/storage_marshal.mli similarity index 100% rename from lib/storage_marshal/storage_marshal.mli rename to store/storage_marshal.mli diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 08da6a6acf..5b03276c69 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -30,7 +30,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr > odoc html-generate --with-search --output-dir html $f 2> /dev/null > done $ odoc support-files -o html - $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js + $ cat db.js ../../../jsoo/main.bc.js > html/index.js $ cp sherlodoc_db.bin html cp: cannot stat 'sherlodoc_db.bin': No such file or directory [1] diff --git a/test/cram/dune b/test/cram/dune index 94c7c65a64..a430ff1235 100644 --- a/test/cram/dune +++ b/test/cram/dune @@ -1,3 +1,3 @@ (cram (alias runexamples) - (deps %{bin:odoc} %{bin:sherlodoc_index} ../../bin/JSherlodoc/main.bc.js)) + (deps %{bin:odoc} %{bin:sherlodoc_index} ../../jsoo/main.bc.js)) diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 1eca26f169..8b7c3cb25e 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -34,7 +34,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr > odoc html-generate --with-search --output-dir html $f 2> /dev/null > done $ odoc support-files -o html - $ cat db.js ../../../bin/JSherlodoc/main.bc.js > html/index.js + $ cat db.js ../../../jsoo/main.bc.js > html/index.js $ cp sherlodoc_db.bin html $ du -sh html/index.js 4.9M html/index.js diff --git a/utils/dune b/utils/dune deleted file mode 100644 index 8d1d8a67cc..0000000000 --- a/utils/dune +++ /dev/null @@ -1,2 +0,0 @@ -(library - (name utils)) diff --git a/utils/utils.ml b/utils/utils.ml deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/bin/www/_dune b/www/_dune similarity index 100% rename from bin/www/_dune rename to www/_dune diff --git a/bin/www/packages.ml b/www/packages.ml similarity index 100% rename from bin/www/packages.ml rename to www/packages.ml diff --git a/bin/www/ui.ml b/www/ui.ml similarity index 100% rename from bin/www/ui.ml rename to www/ui.ml diff --git a/bin/www/www.ml b/www/www.ml similarity index 100% rename from bin/www/www.ml rename to www/www.ml From 6e1bfc98849022b0699aa3c2f22674633e7cec02 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 7 Jun 2023 15:28:57 +0200 Subject: [PATCH 079/285] restore website --- common/map.ml | 58 +++++++++++++++++++++++++---------------------- common/string.ml | 2 +- db/cache.ml | 21 +++++++++++++---- db/elt.ml | 30 ++++++++++++------------ db/trie.ml | 3 +-- index/load_doc.ml | 34 ++++++++++++++------------- jsoo/main.ml | 2 +- query/sort.ml | 4 ++-- www/_dune | 3 --- www/ui.ml | 28 +++++++++++++---------- 10 files changed, 100 insertions(+), 85 deletions(-) delete mode 100644 www/_dune diff --git a/common/map.ml b/common/map.ml index 34fdd1d6a7..e34a51c1ce 100644 --- a/common/map.ml +++ b/common/map.ml @@ -473,37 +473,41 @@ module Make (Ord : OrderedType) = struct | Node { l; v; d; r } -> cons_enum l (More (v, d, r, e)) let compare cmp m1 m2 = - if m1 == m2 then 0 else - let rec compare_aux e1 e2 = - match e1, e2 with - | End, End -> 0 - | End, _ -> -1 - | _, End -> 1 - | More (v1, d1, r1, e1), More (v2, d2, r2, e2) -> - let c = Ord.compare v1 v2 in - if c <> 0 - then c - else - let c = cmp d1 d2 in + if m1 == m2 + then 0 + else + let rec compare_aux e1 e2 = + match e1, e2 with + | End, End -> 0 + | End, _ -> -1 + | _, End -> 1 + | More (v1, d1, r1, e1), More (v2, d2, r2, e2) -> + let c = Ord.compare v1 v2 in if c <> 0 then c - else compare_aux (cons_enum r1 e1) (cons_enum r2 e2) - in - compare_aux (cons_enum m1 End) (cons_enum m2 End) + else + let c = cmp d1 d2 in + if c <> 0 + then c + else compare_aux (cons_enum r1 e1) (cons_enum r2 e2) + in + compare_aux (cons_enum m1 End) (cons_enum m2 End) let equal cmp m1 m2 = - if m1 == m2 then true else - let rec equal_aux e1 e2 = - match e1, e2 with - | End, End -> true - | End, _ -> false - | _, End -> false - | More (v1, d1, r1, e1), More (v2, d2, r2, e2) -> - Ord.compare v1 v2 = 0 - && cmp d1 d2 - && equal_aux (cons_enum r1 e1) (cons_enum r2 e2) - in - equal_aux (cons_enum m1 End) (cons_enum m2 End) + if m1 == m2 + then true + else + let rec equal_aux e1 e2 = + match e1, e2 with + | End, End -> true + | End, _ -> false + | _, End -> false + | More (v1, d1, r1, e1), More (v2, d2, r2, e2) -> + Ord.compare v1 v2 = 0 + && cmp d1 d2 + && equal_aux (cons_enum r1 e1) (cons_enum r2 e2) + in + equal_aux (cons_enum m1 End) (cons_enum m2 End) let rec cardinal = function | Empty -> 0 diff --git a/common/string.ml b/common/string.ml index 7980b7aaa7..5f40354b72 100644 --- a/common/string.ml +++ b/common/string.ml @@ -1,3 +1,3 @@ include Stdlib.String -let hash : t -> int = Hashtbl.hash \ No newline at end of file +let hash : t -> int = Hashtbl.hash diff --git a/db/cache.ml b/db/cache.ml index 6cb42cb82c..901218438d 100644 --- a/db/cache.ml +++ b/db/cache.ml @@ -127,14 +127,24 @@ module Char_list = List (Char) module String_list = List (String) module String_list_list = List (String_list) +module Type = Make (struct + type t = Elt.type_path + + let equal = ( = ) + let hash = Hashtbl.hash + + let sub ~memo:_ { Elt.str; paths } = + { Elt.str = String.memo str; paths = String_list_list.memo paths } +end) + module Kind = Make (struct include Elt.Kind let sub ~memo:_ k = match k with - | Constructor type_path -> Constructor (String_list_list.memo type_path) - | Field type_path -> Constructor (String_list_list.memo type_path) - | Val type_path -> Constructor (String_list_list.memo type_path) + | Constructor type_path -> Constructor (Type.memo type_path) + | Field type_path -> Field (Type.memo type_path) + | Val type_path -> Val (Type.memo type_path) | _ -> k end) @@ -152,12 +162,13 @@ module Elt = struct module Kind_memo = Kind include Elt - let sub ~memo:_ Elt.{ name; kind; has_doc; pkg; json_display } = + let sub ~memo:_ Elt.{ name; kind; doc_html; pkg; json_display } = let name = String.memo name in let json_display = String.memo json_display in + let doc_html = String.memo doc_html in (* For unknown reasons, this causes a terrible performance drop. *) (* let kind = Kind_memo.memo kind in *) - Elt.{ name; kind; has_doc; pkg; json_display } + Elt.{ name; kind; doc_html; pkg; json_display } end) module Set = Elt.Set diff --git a/db/elt.ml b/db/elt.ml index ec15347336..0ef4e77d73 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -1,11 +1,9 @@ open Common -type displayable = - { html : string - ; txt : string +type type_path = + { str : string + ; paths : string list list } - -type type_path = string list list (** A type can viewed as a tree. [a -> b -> c * d] is the following tree : {[ -> @@ -49,9 +47,9 @@ module Kind = struct | TypeExtension | ExtensionConstructor | ModuleType -> Hashtbl.hash k | Constructor type_path -> - Hashtbl.hash (Constructor (hash_type_path type_path)) - | Field type_path -> Hashtbl.hash (Field (hash_type_path type_path)) - | Val type_path -> Hashtbl.hash (Val (hash_type_path type_path)) + Hashtbl.hash (Constructor (hash_type_path type_path.paths)) + | Field type_path -> Hashtbl.hash (Field (hash_type_path type_path.paths)) + | Val type_path -> Hashtbl.hash (Val (hash_type_path type_path.paths)) let equal = ( = ) let doc = Doc @@ -96,7 +94,7 @@ module T = struct type t = { name : string ; kind : Kind.t - ; has_doc : bool + ; doc_html : string ; pkg : Package.t option ; json_display : string } @@ -116,18 +114,19 @@ module T = struct let kind_cost (kind : kind) = match kind with | Constructor type_path | Field type_path | Val type_path -> - type_cost type_path + type_cost type_path.paths | Doc -> 400 | TypeDecl | Module | Exception | Class_type | Method | Class | TypeExtension | ExtensionConstructor | ModuleType -> 200 - let cost { name; kind; has_doc; pkg = _; json_display = _ } = + let cost { name; kind; doc_html; pkg = _; json_display = _ } = let ignore_no_doc = match kind with | Module | ModuleType -> true | _ -> false in + let has_doc = doc_html <> "" in (* TODO : use entry cost *) generic_cost ~ignore_no_doc name has_doc + kind_cost kind @@ -162,11 +161,11 @@ let ( > ) e e' = compare e e' > 0 let ( >= ) e e' = compare e e' >= 0 let hash : t -> int = - fun { name; kind; has_doc; pkg; json_display } -> + fun { name; kind; doc_html; pkg; json_display } -> Hashtbl.hash ( Hashtbl.hash name , Kind.hash kind - , Hashtbl.hash has_doc + , Hashtbl.hash doc_html , Option.hash Package.hash pkg , Hashtbl.hash json_display ) @@ -187,6 +186,5 @@ let link t = let+ pkg_link = pkg_link t in pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name -let v ~name ~kind ~has_doc ?(pkg = None) ~json_display () = - let json_display = json_display in - { name; kind; has_doc; pkg; json_display } +let v ~name ~kind ~doc_html ?(pkg = None) ~json_display () = + { name; kind; doc_html; pkg; json_display } diff --git a/db/trie.ml b/db/trie.ml index 5d5fbee13d..01abe394dc 100644 --- a/db/trie.ml +++ b/db/trie.ml @@ -12,8 +12,7 @@ let empty = Node { leaf = None; children = M.empty } let rec add path leaf t = match t, path with - | Node t, [] -> - Node { t with leaf = Some (leaf t.leaf) } + | Node t, [] -> Node { t with leaf = Some (leaf t.leaf) } | Node t, p :: path -> let child = match M.find p t.children with diff --git a/index/load_doc.ml b/index/load_doc.ml index 8bbe6e26f7..94c932b0af 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -107,8 +107,7 @@ module Make (Storage : Db.Storage.S) = struct | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args | _ -> [] - let type_paths ~prefix ~sgn t = - (type_paths ~prefix ~sgn t) + let type_paths ~prefix ~sgn t = type_paths ~prefix ~sgn t let register_doc elt doc_txt = let doc_words = String.split_on_char ' ' doc_txt in @@ -139,24 +138,28 @@ module Make (Storage : Db.Storage.S) = struct TypeExpr.Arrow (None, parent_type, type_) let convert_kind (kind : Odoc_search.Entry.extra) = + let open Odoc_search in let open Odoc_search.Entry in match kind with | TypeDecl _ -> Elt.Kind.TypeDecl | Module -> Elt.Kind.ModuleType | Value { value = _; type_ } -> + let str = Render.text_of_type type_ in let paths = paths ~prefix:[] ~sgn:Pos type_ in - Elt.Kind.val_ paths + Elt.Kind.val_ { Elt.str; paths } | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let type_paths = paths ~prefix:[] ~sgn:Pos searchable_type in - Elt.Kind.constructor type_paths + let str = Render.text_of_type searchable_type in + let paths = paths ~prefix:[] ~sgn:Pos searchable_type in + Elt.Kind.constructor { Elt.str; paths } | Field { mutable_ = _; parent_type; type_ } -> - let type_paths = + let str = Render.text_of_type type_ in + let paths = type_ |> searchable_type_of_record parent_type |> paths ~prefix:[] ~sgn:Pos in - Elt.Kind.field type_paths + Elt.Kind.field { Elt.str; paths } | Doc _ -> Doc | Exception _ -> Exception | Class_type _ -> Class_type @@ -166,8 +169,7 @@ module Make (Storage : Db.Storage.S) = struct | ExtensionConstructor _ -> ExtensionConstructor | ModuleType -> ModuleType - let convert_kind k = - k |> convert_kind |> Cache.Kind.memo + let convert_kind k = k |> convert_kind |> Cache.Kind.memo let register_type_expr elt type_ = let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in @@ -206,10 +208,11 @@ module Make (Storage : Db.Storage.S) = struct let open Odoc_search in let open Odoc_search.Entry in let full_name = id |> Pretty.fullname |> String.concat "." in - let doc = - let html = doc |> Render.html_of_doc |> string_of_html - and txt = Render.text_of_doc doc in - Elt.{ html; txt } + let doc_txt = Render.text_of_doc doc in + let doc_html = + match doc_txt with + | "" -> "" + | _ -> doc |> Render.html_of_doc |> string_of_html in let kind' = convert_kind extra in let name = @@ -222,9 +225,8 @@ module Make (Storage : Db.Storage.S) = struct then "" else entry |> Json_display.of_entry |> Odoc_html.Json.to_string in - let has_doc = doc.txt <> "" in - let elt = Elt.v ~name ~kind:kind' ~json_display ~has_doc () in - if index_docstring then register_doc elt doc.txt ; + let elt = Elt.v ~name ~kind:kind' ~json_display ~doc_html () in + if index_docstring then register_doc elt doc_txt ; (if index_name then match extra with diff --git a/jsoo/main.ml b/jsoo/main.ml index acf4618e21..1ab0d0dbce 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -1,5 +1,5 @@ let string_of_kind (kind : Db.Elt.kind) = - let open Db.Elt.Kind in + let open Db.Elt.Kind in match kind with | Doc -> "doc" | TypeDecl -> "type" diff --git a/query/sort.ml b/query/sort.ml index 2e83621060..4635699827 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -192,7 +192,7 @@ module Reasoning = struct | [], _ -> None | _, Elt.Kind.(Constructor type_paths | Field type_paths | Val type_paths) -> - Some (Type_distance.v query_type type_paths) + Some (Type_distance.v query_type type_paths.paths) | _ -> None let type_in_query query_type = query_type <> [] @@ -227,7 +227,7 @@ module Reasoning = struct let v query_words query_type elt = let is_stdlib = is_stdlib elt in - let has_doc = elt.Elt.has_doc in + let has_doc = elt.Elt.doc_html <> "" in let name_matches = Name_match.with_words query_words elt in let kind = kind elt in let type_distance = type_distance query_type elt in diff --git a/www/_dune b/www/_dune deleted file mode 100644 index cc56b73a47..0000000000 --- a/www/_dune +++ /dev/null @@ -1,3 +0,0 @@ -(executable - (name www) - (libraries cmdliner dream db query storage_ancient storage_marshal)) diff --git a/www/ui.ml b/www/ui.ml index 4704ce8854..aee6486dba 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -13,16 +13,16 @@ let render_link elt = let render_elt elt = let open Db.Elt in let link = render_link elt in + let html_txt = Unsafe.data in match elt.kind with - | Val { type_; _ } -> - [ txt "val "; a ~a:link [ em [ txt elt.name ] ]; txt " : "; txt type_ ] - | Doc -> [ txt "comment "; a ~a:link [ em [ txt elt.name ] ] ] - | TypeDecl { type_decl } -> - [ txt "type " + | Val { str = type_; _ } -> + [ txt "val " ; a ~a:link [ em [ txt elt.name ] ] - ; txt " = " - ; txt type_decl + ; txt " : " + ; html_txt type_ ] + | Doc -> [ txt "comment "; a ~a:link [ em [ txt elt.name ] ] ] + | TypeDecl -> [ txt "type "; a ~a:link [ em [ txt elt.name ] ] ] | Module -> [ txt "module "; a ~a:link [ em [ txt elt.name ] ] ] | Exception -> [ txt "exception "; a ~a:link [ em [ txt elt.name ] ] ] | Class_type -> [ txt "class type "; a ~a:link [ em [ txt elt.name ] ] ] @@ -33,14 +33,18 @@ let render_elt elt = | ExtensionConstructor -> [ txt "ext constructor "; a ~a:link [ em [ txt elt.name ] ] ] | ModuleType -> [ txt "module type "; a ~a:link [ em [ txt elt.name ] ] ] - | Constructor { type_; _ } -> + | Constructor { str = type_; _ } -> [ txt "constructor " ; a ~a:link [ em [ txt elt.name ] ] ; txt " : " - ; txt type_ + ; html_txt type_ + ] + | Field { str = type_; _ } -> + [ txt "field " + ; a ~a:link [ em [ txt elt.name ] ] + ; txt " : " + ; html_txt type_ ] - | Field { type_; _ } -> - [ txt "field "; a ~a:link [ em [ txt elt.name ] ]; txt " : "; txt type_ ] let render_pkg elt = let open Db.Elt in @@ -61,7 +65,7 @@ let render_pkg elt = let render_result elt = let open Db.Elt in - render_pkg elt @ [ pre (render_elt elt); Unsafe.data elt.doc.Db.Elt.html ] + render_pkg elt @ [ pre (render_elt elt); Unsafe.data elt.doc_html ] let render ~pretty results = match results with From c73f771f0c3c63261ccba23fcb39f0a60f54b35e Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 7 Jun 2023 18:10:33 +0200 Subject: [PATCH 080/285] precompute static score --- common/list.ml | 9 ------- db/cache.ml | 17 ++++++++++---- db/elt.ml | 58 ++++------------------------------------------ index/index_lib.ml | 4 +++- index/load_doc.ml | 33 ++++++++++++++++++++++++-- query/query.ml | 7 ------ query/sort.ml | 15 ++++++------ 7 files changed, 58 insertions(+), 85 deletions(-) delete mode 100644 common/list.ml diff --git a/common/list.ml b/common/list.ml deleted file mode 100644 index 14b20cf7b9..0000000000 --- a/common/list.ml +++ /dev/null @@ -1,9 +0,0 @@ -include Stdlib.List - -let sort_map ~f ~compare li = - li - |> map (fun elt -> elt, f elt) - |> sort (fun (_, wit) (_, wit') -> compare wit wit') - |> map (fun (elt, _) -> elt) - -let hash hash_a li = li |> map hash_a |> Hashtbl.hash diff --git a/db/cache.ml b/db/cache.ml index 901218438d..276d6bb307 100644 --- a/db/cache.ml +++ b/db/cache.ml @@ -106,7 +106,7 @@ end) module List (A : Memo) = Make (struct type t = A.t list - let hash = List.hash A.hash + let hash = Hashtbl.hash let equal = List.equal A.equal let rec sub ~memo lst = @@ -138,9 +138,13 @@ module Type = Make (struct end) module Kind = Make (struct - include Elt.Kind + type t = Elt.Kind.t + + let equal = ( = ) + let hash = Hashtbl.hash let sub ~memo:_ k = + let open Elt.Kind in match k with | Constructor type_path -> Constructor (Type.memo type_path) | Field type_path -> Field (Type.memo type_path) @@ -162,13 +166,16 @@ module Elt = struct module Kind_memo = Kind include Elt - let sub ~memo:_ Elt.{ name; kind; doc_html; pkg; json_display } = + let equal = ( = ) + let hash = Hashtbl.hash + + let sub ~memo:_ Elt.{ name; kind; score; doc_html; pkg; json_display } = let name = String.memo name in let json_display = String.memo json_display in let doc_html = String.memo doc_html in (* For unknown reasons, this causes a terrible performance drop. *) (* let kind = Kind_memo.memo kind in *) - Elt.{ name; kind; doc_html; pkg; json_display } + Elt.{ name; kind; score; doc_html; pkg; json_display } end) module Set = Elt.Set @@ -180,7 +187,7 @@ module Set (A : Memo) (S : Set.S with type elt = A.t) = Make (struct type t = S.t let equal = S.equal - let hash m = m |> S.elements |> Common.List.hash A.hash + let hash m = m |> S.elements |> Hashtbl.hash let sub ~memo set = match set with diff --git a/db/elt.ml b/db/elt.ml index 0ef4e77d73..4a8eb1167c 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -21,8 +21,6 @@ type type_path = It is used to sort results. *) -let hash_type_path path = List.hash (List.hash String.hash) path - module Kind = struct type 'a abstract = | Doc @@ -41,16 +39,6 @@ module Kind = struct type t = type_path abstract - let hash k = - match k with - | Doc | TypeDecl | Module | Exception | Class_type | Method | Class - | TypeExtension | ExtensionConstructor | ModuleType -> - Hashtbl.hash k - | Constructor type_path -> - Hashtbl.hash (Constructor (hash_type_path type_path.paths)) - | Field type_path -> Hashtbl.hash (Field (hash_type_path type_path.paths)) - | Val type_path -> Hashtbl.hash (Val (hash_type_path type_path.paths)) - let equal = ( = ) let doc = Doc let type_decl = TypeDecl @@ -94,6 +82,7 @@ module T = struct type t = { name : string ; kind : Kind.t + ; score : int ; doc_html : string ; pkg : Package.t option ; json_display : string @@ -102,34 +91,6 @@ module T = struct let compare_pkg { name; version = _ } (b : package) = String.compare name b.name - let generic_cost ~ignore_no_doc name has_doc = - String.length name - (* + (5 * List.length path) TODO : restore depth based ordering *) - + (if ignore_no_doc || has_doc then 0 else 1000) - + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 - - let type_cost paths = - paths |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 - - let kind_cost (kind : kind) = - match kind with - | Constructor type_path | Field type_path | Val type_path -> - type_cost type_path.paths - | Doc -> 400 - | TypeDecl | Module | Exception | Class_type | Method | Class - | TypeExtension | ExtensionConstructor | ModuleType -> - 200 - - let cost { name; kind; doc_html; pkg = _; json_display = _ } = - let ignore_no_doc = - match kind with - | Module | ModuleType -> true - | _ -> false - in - let has_doc = doc_html <> "" in - (* TODO : use entry cost *) - generic_cost ~ignore_no_doc name has_doc + kind_cost kind - let structural_compare a b = begin match String.compare a.name b.name with @@ -145,9 +106,7 @@ module T = struct if a == b then 0 else - let cost_a = cost a in - let cost_b = cost b in - let cmp = Int.compare cost_a cost_b in + let cmp = Int.compare a.score b.score in if cmp = 0 then structural_compare a b else cmp end @@ -160,15 +119,6 @@ let ( <= ) e e' = compare e e' <= 0 let ( > ) e e' = compare e e' > 0 let ( >= ) e e' = compare e e' >= 0 -let hash : t -> int = - fun { name; kind; doc_html; pkg; json_display } -> - Hashtbl.hash - ( Hashtbl.hash name - , Kind.hash kind - , Hashtbl.hash doc_html - , Option.hash Package.hash pkg - , Hashtbl.hash json_display ) - module Set = Set.Make (T) let pkg_link { pkg; _ } = @@ -186,5 +136,5 @@ let link t = let+ pkg_link = pkg_link t in pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name -let v ~name ~kind ~doc_html ?(pkg = None) ~json_display () = - { name; kind; doc_html; pkg; json_display } +let v ~name ~kind ~score ~doc_html ?(pkg = None) ~json_display () = + { name; kind; score; doc_html; pkg; json_display } diff --git a/index/index_lib.ml b/index/index_lib.ml index 5a06729f72..a4eb084b74 100644 --- a/index/index_lib.ml +++ b/index/index_lib.ml @@ -11,7 +11,9 @@ let main ~index_docstring ~index_name ~type_search ~empty_payload ~index Load_doc.clear () ; Db.export h in + let t0 = Unix.gettimeofday () in Load_doc.run ~index_docstring ~index_name ~type_search ~empty_payload ~index ; - print_endline "doc loaded" ; + let t1 = Unix.gettimeofday () in + Format.printf "Indexing in %fs@." (t1 -. t0) ; flush () ; Storage.close_out h diff --git a/index/load_doc.ml b/index/load_doc.ml index 94c932b0af..a6861b2781 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -9,6 +9,34 @@ module Make (Storage : Db.Storage.S) = struct let clear () = Cache.clear () + let generic_cost ~ignore_no_doc name has_doc = + String.length name + (* + (5 * List.length path) TODO : restore depth based ordering *) + + (if ignore_no_doc || has_doc then 0 else 1000) + + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 + + let type_cost paths = + paths |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 + + let kind_cost (kind : Elt.Kind.t) = + match kind with + | Constructor type_path | Field type_path | Val type_path -> + type_cost type_path.paths + | Doc -> 400 + | TypeDecl | Module | Exception | Class_type | Method | Class + | TypeExtension | ExtensionConstructor | ModuleType -> + 200 + + let cost ~name ~kind ~doc_html = + let ignore_no_doc = + match kind with + | Elt.Kind.Module | ModuleType -> true + | _ -> false + in + let has_doc = doc_html <> "" in + (* TODO : use entry cost *) + generic_cost ~ignore_no_doc name has_doc + kind_cost kind + (* todo : check usefulness @@ -24,6 +52,7 @@ module Make (Storage : Db.Storage.S) = struct | Tuple args -> List.fold_left (fun acc t -> acc + type_size t) 1 args | _ -> 100 *) + let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst @@ -225,7 +254,8 @@ module Make (Storage : Db.Storage.S) = struct then "" else entry |> Json_display.of_entry |> Odoc_html.Json.to_string in - let elt = Elt.v ~name ~kind:kind' ~json_display ~doc_html () in + let score = cost ~name ~kind:kind' ~doc_html in + let elt = Elt.v ~name ~kind:kind' ~json_display ~doc_html ~score () in if index_docstring then register_doc elt doc_txt ; (if index_name then @@ -237,7 +267,6 @@ module Make (Storage : Db.Storage.S) = struct module Resolver = Odoc_odoc.Resolver let run ~index_docstring ~index_name ~type_search ~empty_payload ~index = - print_endline "loading doc !" ; List.iter (register_entry ~index_docstring ~index_name ~type_search ~empty_payload) index diff --git a/query/query.ml b/query/query.ml index 49ad9c3e02..0689461924 100644 --- a/query/query.ml +++ b/query/query.ml @@ -96,19 +96,12 @@ let match_packages ~packages results = | _ -> Seq.filter (match_packages ~packages) results let api ~(shards : Db.Elt.t array Db.t list) params = - print_endline "api" ; let query_name, query_typ, query_typ_arrow, pretty = Parser.of_string params.query in - print_endline "api 1" ; let results = search ~shards query_name query_typ in - print_endline "api 2" ; let results = Succ.to_seq results in - print_endline "api 3" ; let results = match_packages ~packages:params.packages results in - print_endline "api 4" ; let results = List.of_seq @@ Seq.take params.limit results in - print_endline "api 5" ; let results = Sort.list query_name query_typ_arrow results in - print_endline "api end" ; pretty, results diff --git a/query/sort.ml b/query/sort.ml index 4635699827..98dd266b86 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -244,9 +244,6 @@ module Reasoning = struct ; name_length } - let compare_is_stblib b1 b2 = if b1 && b2 then 0 else if b1 then -1 else 1 - let compare_has_doc b1 b2 = if b1 && b2 then 0 else if b1 then -1 else 1 - let compare_kind k k' = let to_int = function | Val -> 0 @@ -309,10 +306,14 @@ module Reasoning = struct + (if has_doc then 0 else 500) + name_matches + type_cost + kind + name_length - let compare r r' = Int.compare (score r) (score r') + let score ~query_name ~query_type elt = score (v query_name query_type elt) end let list query_name query_type results = - let open Reasoning in - let f = v query_name query_type in - List.sort_map ~f ~compare results + let scored = + List.map + (fun elt -> elt, Reasoning.score ~query_name ~query_type elt) + results + in + let sorted = List.sort (fun (_, a) (_, b) -> Int.compare a b) scored in + List.map (fun (elt, _) -> elt) sorted From a5c29f3992b27112639b3935db674cfc31854bf1 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 8 Jun 2023 16:16:55 +0200 Subject: [PATCH 081/285] add missing dune files --- store/dune | 14 ++++++++++++++ www/dune | 3 +++ 2 files changed, 17 insertions(+) create mode 100644 store/dune create mode 100644 www/dune diff --git a/store/dune b/store/dune new file mode 100644 index 0000000000..c46f2196c5 --- /dev/null +++ b/store/dune @@ -0,0 +1,14 @@ +(library + (name storage_ancient) + (modules storage_ancient) + (libraries ancient db)) + +(library + (name storage_js) + (modules storage_js) + (libraries db base64 bigstringaf decompress.zl)) + +(library + (name storage_marshal) + (modules storage_marshal) + (libraries db)) diff --git a/www/dune b/www/dune new file mode 100644 index 0000000000..cc56b73a47 --- /dev/null +++ b/www/dune @@ -0,0 +1,3 @@ +(executable + (name www) + (libraries cmdliner dream db query storage_ancient storage_marshal)) From d5e88e0742cedb912e5794a246902c2d1211ae17 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 6 Jun 2023 18:45:04 +0200 Subject: [PATCH 082/285] Better performance for cache --- common/int.ml | 2 + db/cache.ml | 269 +++++++++++++++++++++++++++------------------- db/cache.mli | 20 ++-- db/db.ml | 4 +- index/load_doc.ml | 2 +- 5 files changed, 172 insertions(+), 125 deletions(-) diff --git a/common/int.ml b/common/int.ml index 0c6f8d8cf9..9f4b82ec35 100644 --- a/common/int.ml +++ b/common/int.ml @@ -1,2 +1,4 @@ include Stdlib.Int module Map = Map.Make (Stdlib.Int) + +let hash : int -> int = Hashtbl.hash diff --git a/db/cache.ml b/db/cache.ml index 276d6bb307..c8adf52ac3 100644 --- a/db/cache.ml +++ b/db/cache.ml @@ -1,5 +1,7 @@ open Common +type uid = int + let clears = ref [] let clear () = Common.List.iter (fun f -> f ()) !clears @@ -12,20 +14,17 @@ end (** The result of the [Make] functor. [equal] and [hash] are reexported for composability with other functors. *) module type Memo = sig - include Cached + type t - val equal : t -> t -> bool - val hash : t -> int + val memo : t -> uid * t end (** This module specifies what is need to construct a cache. *) module type Cachable = sig type t + type key - val equal : t -> t -> bool - val hash : t -> int - - val sub : memo:(t -> t) -> t -> t + val sub : memo:(t -> uid * t) -> t -> key * t (** [sub ~memo (v : t)] should replace subvalues [v'] of type [t] by [memo v'], and subvalues [a] of type [A.t] by [A.memo a]. *) end @@ -34,37 +33,57 @@ end module Make (Elt : Cachable) : Memo with type t = Elt.t = struct type t = Elt.t - let equal = Elt.equal - let hash = Elt.hash + let equal = ( = ) + let hash = Hashtbl.hash + + let new_uid = + let i = ref 0 in + fun () -> + let r = !i in + i := r + 1 ; + r module H = Hashtbl.Make (struct - type t = Elt.t + type t = Elt.key - let equal = Elt.equal - let hash = Elt.hash + let equal = equal + let hash = hash end) - let cache = H.create 16 + let cache : (int * t) H.t = H.create 16 let () = clears := (fun () -> H.clear cache) :: !clears - let rec memo str = - try H.find cache str - with Not_found -> - let str = Elt.sub ~memo str in - H.add cache str str ; - str + let rec memo elt : int * t = + let key, elt = Elt.sub ~memo elt in + match H.find cache key with + | uid, elt -> uid, elt + | exception Not_found -> + let uid = new_uid () in + + H.add cache key (uid, elt) ; + uid, elt end (** Does not build a cache, but exposes functions that caches that subvalues of a given cache. This is useful for big value with a lot of subvalues, an expansive [hash] and [equal] function, and not a lot of opportunities for sharing. *) -module Make_sub_only (Elt : Cachable) : Memo with type t = Elt.t = struct - type t = Elt.t +(*module Make_sub_only (Elt : Cachable) : Memo with type t = Elt.t = struct + type t = Elt.t + type key = Elt.key - let equal = ( = ) - let hash = Hashtbl.hash - let rec memo str = Elt.sub ~memo str + let equal = Elt.equal + let hash = Elt.hash + let rec memo str = Elt.sub ~memo str + end +*) + +module Strip (Memo : Memo) : Cached with type t = Memo.t = struct + type t = Memo.t + + let memo elt = + let _, elt = Memo.memo elt in + elt end (** This module does not use {!Make} because it does not actually cache anything, @@ -72,9 +91,7 @@ end module Char = struct type t = char - let equal = Char.equal - let hash = Hashtbl.hash - let memo c = c + let memo c = Char.code c, c module Map = Char.Map module Array_map = Char.Array_map @@ -82,45 +99,48 @@ end module String = Make (struct type t = string + type key = string - let hash = Hashtbl.hash - let equal = String.equal - - let sub ~memo:_ str = - (* not returning [str] here is required by [Ancient]. *) - String.init (String.length str) (String.get str) + let sub ~memo:_ str = str, str end) module Option (A : Memo) = Make (struct type t = A.t option - - let equal = Option.equal A.equal - let hash = Option.hash A.hash + type key = uid option let sub ~memo:_ opt = match opt with - | Some a -> Some (A.memo a) - | None -> None + | Some a -> + let uid, a = A.memo a in + Some uid, Some a + | None -> None, None end) module List (A : Memo) = Make (struct type t = A.t list - let hash = Hashtbl.hash - let equal = List.equal A.equal + type key = + | Empty + | Cons of uid * uid - let rec sub ~memo lst = + let sub ~memo lst = match lst with - | [] -> [] - | x :: xs -> A.memo x :: memo (sub ~memo xs) + | [] -> Empty, [] + | elt :: li -> + let uid_elt, elt = A.memo elt in + let uid_li, li = memo li in + Cons (uid_elt, uid_li), elt :: li end) module Array (A : Memo) = Make (struct type t = A.t array + type key = uid array - let equal = Array.equal A.equal - let hash = Array.hash A.hash - let sub ~memo:_ arr = Array.map A.memo arr + let sub ~memo:_ arr = + let arr = Array.map A.memo arr in + let key = Array.map (fun (key, _) -> key) arr in + let arr = Array.map (fun (_, elt) -> elt) arr in + key, arr end) module Char_list = List (Char) @@ -130,52 +150,60 @@ module String_list_list = List (String_list) module Type = Make (struct type t = Elt.type_path - let equal = ( = ) - let hash = Hashtbl.hash + type key = + { str : uid + ; paths : uid + } let sub ~memo:_ { Elt.str; paths } = - { Elt.str = String.memo str; paths = String_list_list.memo paths } + let uid_str, str = String.memo str in + let uid_paths, paths = String_list_list.memo paths in + { str = uid_str; paths = uid_paths }, Elt.{ str; paths } end) module Kind = Make (struct type t = Elt.Kind.t - - let equal = ( = ) - let hash = Hashtbl.hash + type key = uid Elt.Kind.abstract let sub ~memo:_ k = let open Elt.Kind in match k with - | Constructor type_path -> Constructor (Type.memo type_path) - | Field type_path -> Field (Type.memo type_path) - | Val type_path -> Val (Type.memo type_path) - | _ -> k + | Constructor type_ -> + let uid, type_ = Type.memo type_ in + Constructor uid, Constructor type_ + | Field type_ -> + let uid, type_ = Type.memo type_ in + Field uid, Field type_ + | Val type_ -> + let uid, type_ = Type.memo type_ in + Val uid, Val type_ + (* the below looks like it could be [k -> (k, k) but it does not because of typing issues] *) + | Doc -> Doc, Doc + | TypeDecl -> TypeDecl, TypeDecl + | Module -> Module, Module + | Exception -> Exception, Exception + | Class_type -> Class_type, Class_type + | Method -> Method, Method + | Class -> Class, Class + | TypeExtension -> TypeExtension, TypeExtension + | ExtensionConstructor -> ExtensionConstructor, ExtensionConstructor + | ModuleType -> ModuleType, ModuleType end) -module Package = Make (struct - include Elt.Package - - let sub ~memo:_ { name; version } = - { name = String.memo name; version = String.memo version } -end) - -module Package_option = Option (Package) - module Elt = struct include Make (struct - module Kind_memo = Kind include Elt - let equal = ( = ) - let hash = Hashtbl.hash + type key = + { name : uid + ; score : int + } - let sub ~memo:_ Elt.{ name; kind; score; doc_html; pkg; json_display } = - let name = String.memo name in - let json_display = String.memo json_display in - let doc_html = String.memo doc_html in - (* For unknown reasons, this causes a terrible performance drop. *) + let sub ~memo:_ Elt.{ name; kind; doc_html; score; pkg; json_display } = + let uid_name, name = String.memo name in (* let kind = Kind_memo.memo kind in *) - Elt.{ name; kind; score; doc_html; pkg; json_display } + ( { name = uid_name; score } + , Elt.{ name; kind; doc_html; pkg; json_display; score } ) end) module Set = Elt.Set @@ -186,39 +214,48 @@ module Elt_array = Array (Elt) module Set (A : Memo) (S : Set.S with type elt = A.t) = Make (struct type t = S.t - let equal = S.equal - let hash m = m |> S.elements |> Hashtbl.hash + type key = + | Empty + | Node of + { l : uid + ; v : uid + ; r : uid + ; h : int + } let sub ~memo set = match set with - | S.Empty -> S.Empty + | S.Empty -> Empty, S.Empty | S.Node { l; v; r; h } -> (* This shares subset. Not actually very useful on tested exemples. *) - let l = memo l in - let v = A.memo v in - let r = memo r in - S.Node { l; v; r; h } + let uid_l, l = memo l in + let uid_v, v = A.memo v in + let uid_r, r = memo r in + Node { l = uid_l; v = uid_v; r = uid_r; h }, S.Node { l; v; r; h } end) module Map (A : Memo) (M : Map.S) = Make (struct type t = A.t M.t - let equal = M.equal A.equal - - let hash m = - m |> M.bindings - |> Common.List.map (fun (k, v) -> k, A.hash v) - |> Hashtbl.hash + type key = + | Empty + | Node of + { l : uid + ; v : M.key + ; d : uid + ; r : uid + ; h : int + } let sub ~memo m = match m with - | M.Empty -> M.Empty + | M.Empty -> Empty, M.Empty | M.Node { l; v; d; r; h } -> (* This shares submaps ! *) - let l = memo l in - let r = memo r in - let d = A.memo d in - M.Node { l; v; d; r; h } + let uid_l, l = memo l in + let uid_d, d = A.memo d in + let uid_r, r = memo r in + Node { l = uid_l; v; d = uid_d; r = uid_r; h }, M.Node { l; v; d; r; h } end) module Elt_set = Set (Elt) (Elt.Set) @@ -234,32 +271,28 @@ module Trie (A : Memo) : Memo with type t = A.t Trie.t = struct (* Here [Make_sub_only] is good enough. Using [Make] instead slows down the [Base] test by 50s for a 20ko gain. *) - module rec M : (Memo with type t = A.t Trie.t) = Make_sub_only (struct + module rec M : (Memo with type t = A.t Trie.t) = Make (struct type t = A.t Trie.t - let equal = Trie.equal A.equal + type key = + | Leaf of uid * uid + | Node of + { leaf : uid + ; children : uid + } - let hash trie = + let sub ~memo:_ trie : key * _ = let open Trie in match trie with - | Leaf (chars, a) -> - Hashtbl.hash - (Leaf (Obj.magic @@ Char_list.hash chars, Obj.magic @@ A.hash a)) + | Leaf (chars, elts) -> + let uid_chars, chars = Char_list.memo chars in + let uid_elts, elts = A.memo elts in + Leaf (uid_chars, uid_elts), Trie.Leaf (chars, elts) | Node { leaf; children } -> - Hashtbl.hash - (Node - { leaf = Obj.magic @@ A_option.hash leaf - ; children = Obj.magic @@ Children.hash children - }) - - let sub ~memo:_ trie = - let open Trie in - match trie with - | Leaf (chars, elts) -> Leaf (Char_list.memo chars, A.memo elts) - | Node { leaf; children } -> - let leaf = A_option.memo leaf in - let children = Children.memo children in - Node { leaf; children } + let uid_leaf, leaf = A_option.memo leaf in + let uid_children, children = Children.memo children in + ( Node { leaf = uid_leaf; children = uid_children } + , Trie.Node { leaf; children } ) end) and Children : (Memo with type t = A.t Trie.t Char.Map.t) = Char_map (M) @@ -271,3 +304,15 @@ module Elt_set_trie = Trie (Elt_set) module Elt_set_occ_trie = Trie (Elt_set_occ) module Elt_array_trie = Trie (Elt_array) module Elt_array_occ_trie = Trie (Elt_array_occ) + +(* Hiding the uids *) +module String_ = Strip (String) +module Char_list_ = Strip (Char_list) +module String_list_ = Strip (String_list) +module String_list_list_ = Strip (String_list_list) +module Kind_ = Strip (Kind) +module Elt_array_ = Strip (Elt_array) +module Elt_set_trie_ = Strip (Elt_set_trie) +module Elt_set_occ_trie_ = Strip (Elt_set_occ_trie) +module Elt_array_trie_ = Strip (Elt_array_trie) +module Elt_array_occ_trie_ = Strip (Elt_array_occ_trie) diff --git a/db/cache.mli b/db/cache.mli index a45090ea55..6143bd10eb 100644 --- a/db/cache.mli +++ b/db/cache.mli @@ -16,13 +16,13 @@ module type Cached = sig is to register [v] and its subvalues to be shared in the future. *) end -module String : Cached with type t = string -module Char_list : Cached with type t = char list -module String_list : Cached with type t = string list -module String_list_list : Cached with type t = string list list -module Kind : Cached with type t = Elt.Kind.t -module Elt_array : Cached with type t = Elt.t array -module Elt_set_trie : Cached with type t = Elt.Set.t Trie.t -module Elt_set_occ_trie : Cached with type t = Elt.Set.t Int.Map.t Trie.t -module Elt_array_trie : Cached with type t = Elt.t Array.t Trie.t -module Elt_array_occ_trie : Cached with type t = Elt.t Array.t Int.Map.t Trie.t +module String_ : Cached with type t = string +module Char_list_ : Cached with type t = char list +module String_list_ : Cached with type t = string list +module String_list_list_ : Cached with type t = string list list +module Kind_ : Cached with type t = Elt.Kind.t +module Elt_array_ : Cached with type t = Elt.t array +module Elt_set_trie_ : Cached with type t = Elt.Set.t Trie.t +module Elt_set_occ_trie_ : Cached with type t = Elt.Set.t Int.Map.t Trie.t +module Elt_array_trie_ : Cached with type t = Elt.t Array.t Trie.t +module Elt_array_occ_trie_ : Cached with type t = Elt.t Array.t Int.Map.t Trie.t diff --git a/db/db.ml b/db/db.ml index 6a038826dd..3c221f4eaa 100644 --- a/db/db.ml +++ b/db/db.ml @@ -33,9 +33,9 @@ let compact db = let t1 = Unix.gettimeofday () in let db_names = trie_with_array db_names in let t2 = Unix.gettimeofday () in - let db_types = Cache.Elt_array_occ_trie.memo db_types in + let db_types = Cache.Elt_array_occ_trie_.memo db_types in let t3 = Unix.gettimeofday () in - let db_names = Cache.Elt_array_trie.memo db_names in + let db_names = Cache.Elt_array_trie_.memo db_names in let t4 = Unix.gettimeofday () in Printf.printf "trie_with_array_occ:%.2fs\n\ diff --git a/index/load_doc.ml b/index/load_doc.ml index a6861b2781..a3dd91510d 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -198,7 +198,7 @@ module Make (Storage : Db.Storage.S) = struct | ExtensionConstructor _ -> ExtensionConstructor | ModuleType -> ModuleType - let convert_kind k = k |> convert_kind |> Cache.Kind.memo + let convert_kind k = k |> convert_kind |> Cache.Kind_.memo let register_type_expr elt type_ = let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in From 0a955ffa64605a90fb050f9cd9b7ea763b50e151 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 8 Jun 2023 17:48:57 +0200 Subject: [PATCH 083/285] Remove json_display --- db/cache.ml | 29 +++++++--------------- db/elt.ml | 13 +++++----- index/index.ml | 16 +++--------- index/index_lib.ml | 4 +-- index/index_lib.mli | 1 - index/load_doc.ml | 39 ++++++++++++----------------- index/load_doc.mli | 1 - jsoo/dune | 2 +- jsoo/main.ml | 11 +++++++-- query/sort.ml | 2 +- test/cram/base.t/run.t | 19 ++++++++------ test/cram/simple.t/run.t | 16 ++++++++---- www/ui.ml | 53 +++++++++++++++++----------------------- 13 files changed, 91 insertions(+), 115 deletions(-) diff --git a/db/cache.ml b/db/cache.ml index c8adf52ac3..4811be2a82 100644 --- a/db/cache.ml +++ b/db/cache.ml @@ -146,20 +146,7 @@ end) module Char_list = List (Char) module String_list = List (String) module String_list_list = List (String_list) - -module Type = Make (struct - type t = Elt.type_path - - type key = - { str : uid - ; paths : uid - } - - let sub ~memo:_ { Elt.str; paths } = - let uid_str, str = String.memo str in - let uid_paths, paths = String_list_list.memo paths in - { str = uid_str; paths = uid_paths }, Elt.{ str; paths } -end) +module String_option = Option (String) module Kind = Make (struct type t = Elt.Kind.t @@ -169,13 +156,13 @@ module Kind = Make (struct let open Elt.Kind in match k with | Constructor type_ -> - let uid, type_ = Type.memo type_ in + let uid, type_ = String_list_list.memo type_ in Constructor uid, Constructor type_ | Field type_ -> - let uid, type_ = Type.memo type_ in + let uid, type_ = String_list_list.memo type_ in Field uid, Field type_ | Val type_ -> - let uid, type_ = Type.memo type_ in + let uid, type_ = String_list_list.memo type_ in Val uid, Val type_ (* the below looks like it could be [k -> (k, k) but it does not because of typing issues] *) | Doc -> Doc, Doc @@ -197,13 +184,15 @@ module Elt = struct type key = { name : uid ; score : int + ; rhs : uid } - let sub ~memo:_ Elt.{ name; kind; doc_html; score; pkg; json_display } = + let sub ~memo:_ Elt.{ name; kind; doc_html; score; pkg; rhs; url } = let uid_name, name = String.memo name in + let uid_rhs, rhs = String_option.memo rhs in (* let kind = Kind_memo.memo kind in *) - ( { name = uid_name; score } - , Elt.{ name; kind; doc_html; pkg; json_display; score } ) + ( { name = uid_name; rhs = uid_rhs; score } + , Elt.{ name; kind; doc_html; pkg; rhs; score; url } ) end) module Set = Elt.Set diff --git a/db/elt.ml b/db/elt.ml index 4a8eb1167c..55e3788858 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -1,9 +1,7 @@ open Common -type type_path = - { str : string - ; paths : string list list - } +type type_path = string list list + (** A type can viewed as a tree. [a -> b -> c * d] is the following tree : {[ -> @@ -81,11 +79,12 @@ type kind = Kind.t module T = struct type t = { name : string + ; rhs : string option + ; url:string ; kind : Kind.t ; score : int ; doc_html : string ; pkg : Package.t option - ; json_display : string } let compare_pkg { name; version = _ } (b : package) = @@ -136,5 +135,5 @@ let link t = let+ pkg_link = pkg_link t in pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name -let v ~name ~kind ~score ~doc_html ?(pkg = None) ~json_display () = - { name; kind; score; doc_html; pkg; json_display } +let v ~name ~kind ~score ~rhs ~doc_html ~url ?(pkg = None) () = + { name; kind; url; score; doc_html; pkg; rhs } diff --git a/index/index.ml b/index/index.ml index a636081d37..caa3650b5d 100644 --- a/index/index.ml +++ b/index/index.ml @@ -1,5 +1,4 @@ -let main files index_docstring index_name type_search empty_payload db_filename - db_format = +let main files index_docstring index_name type_search db_filename db_format = let index = files |> List.map Fpath.of_string |> List.map Result.get_ok in let storage = match db_format with @@ -19,8 +18,8 @@ let main files index_docstring index_name type_search empty_payload db_filename |> Result.get_ok |> Option.value ~default:[]) [] in - Index_lib.main ~index_docstring ~index_name ~type_search ~empty_payload ~index - ~db_filename storage + Index_lib.main ~index_docstring ~index_name ~type_search ~index ~db_filename + storage open Cmdliner @@ -36,13 +35,6 @@ let type_search = let doc = "Enable type based search" in Arg.(value & opt bool true & info ~doc [ "type-search" ]) -let empty_payload = - let doc = - "Dont put anything in the payloads. For testing purposes, will break the \ - UI." - in - Arg.(value & flag & info ~doc [ "empty-payload" ]) - let db_format = let doc = "Database format" in let kind = Arg.enum [ "ancient", `ancient; "marshal", `marshal; "js", `js ] in @@ -60,7 +52,7 @@ let odoc_files = let index = Term.( const main $ odoc_files $ index_docstring $ index_name $ type_search - $ empty_payload $ db_filename $ db_format) + $ db_filename $ db_format) let cmd = let doc = "Index odocl files" in diff --git a/index/index_lib.ml b/index/index_lib.ml index a4eb084b74..29b339ffaa 100644 --- a/index/index_lib.ml +++ b/index/index_lib.ml @@ -1,6 +1,6 @@ module Storage = Db.Storage -let main ~index_docstring ~index_name ~type_search ~empty_payload ~index +let main ~index_docstring ~index_name ~type_search ~index ~db_filename storage = print_endline "Index_lib.main" ; let module Storage = (val storage : Storage.S) in @@ -12,7 +12,7 @@ let main ~index_docstring ~index_name ~type_search ~empty_payload ~index Db.export h in let t0 = Unix.gettimeofday () in - Load_doc.run ~index_docstring ~index_name ~type_search ~empty_payload ~index ; + Load_doc.run ~index_docstring ~index_name ~type_search ~index ; let t1 = Unix.gettimeofday () in Format.printf "Indexing in %fs@." (t1 -. t0) ; flush () ; diff --git a/index/index_lib.mli b/index/index_lib.mli index 1d2730ace3..6aa4d2d560 100644 --- a/index/index_lib.mli +++ b/index/index_lib.mli @@ -2,7 +2,6 @@ val main : index_docstring:bool -> index_name:bool -> type_search:bool - -> empty_payload:bool -> index:Odoc_search.Entry.t list -> db_filename:string -> (module Db.Storage.S) diff --git a/index/load_doc.ml b/index/load_doc.ml index a3dd91510d..bbd0c512b5 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -21,7 +21,7 @@ module Make (Storage : Db.Storage.S) = struct let kind_cost (kind : Elt.Kind.t) = match kind with | Constructor type_path | Field type_path | Val type_path -> - type_cost type_path.paths + type_cost type_path | Doc -> 400 | TypeDecl | Module | Exception | Class_type | Method | Class | TypeExtension | ExtensionConstructor | ModuleType -> @@ -167,28 +167,24 @@ module Make (Storage : Db.Storage.S) = struct TypeExpr.Arrow (None, parent_type, type_) let convert_kind (kind : Odoc_search.Entry.extra) = - let open Odoc_search in let open Odoc_search.Entry in match kind with | TypeDecl _ -> Elt.Kind.TypeDecl | Module -> Elt.Kind.ModuleType | Value { value = _; type_ } -> - let str = Render.text_of_type type_ in let paths = paths ~prefix:[] ~sgn:Pos type_ in - Elt.Kind.val_ { Elt.str; paths } + Elt.Kind.val_ paths | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let str = Render.text_of_type searchable_type in let paths = paths ~prefix:[] ~sgn:Pos searchable_type in - Elt.Kind.constructor { Elt.str; paths } + Elt.Kind.constructor paths | Field { mutable_ = _; parent_type; type_ } -> - let str = Render.text_of_type type_ in let paths = type_ |> searchable_type_of_record parent_type |> paths ~prefix:[] ~sgn:Pos in - Elt.Kind.field { Elt.str; paths } + Elt.Kind.field paths | Doc _ -> Doc | Exception _ -> Exception | Class_type _ -> Class_type @@ -228,12 +224,12 @@ module Make (Storage : Db.Storage.S) = struct let type_ = TypeExpr.Arrow (None, parent_type, type_) in register_type_expr elt type_ - let register_entry ~empty_payload ~index_name ~type_search ~index_docstring - (Odoc_search.Entry. - { id : Odoc_model.Paths.Identifier.Any.t - ; doc : Odoc_model.Comment.docs - ; extra : extra - } as entry) = + let register_entry ~index_name ~type_search ~index_docstring + Odoc_search.Entry. + { id : Odoc_model.Paths.Identifier.Any.t + ; doc : Odoc_model.Comment.docs + ; extra : extra + } = let open Odoc_search in let open Odoc_search.Entry in let full_name = id |> Pretty.fullname |> String.concat "." in @@ -249,13 +245,10 @@ module Make (Storage : Db.Storage.S) = struct | Doc _ -> Pretty.prefixname id | _ -> full_name in - let json_display = - if empty_payload - then "" - else entry |> Json_display.of_entry |> Odoc_html.Json.to_string - in let score = cost ~name ~kind:kind' ~doc_html in - let elt = Elt.v ~name ~kind:kind' ~json_display ~doc_html ~score () in + let rhs = Json_display.rhs_of_kind extra in + let url = Render.url id in + let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in if index_docstring then register_doc elt doc_txt ; (if index_name then @@ -266,8 +259,6 @@ module Make (Storage : Db.Storage.S) = struct module Resolver = Odoc_odoc.Resolver - let run ~index_docstring ~index_name ~type_search ~empty_payload ~index = - List.iter - (register_entry ~index_docstring ~index_name ~type_search ~empty_payload) - index + let run ~index_docstring ~index_name ~type_search ~index = + List.iter (register_entry ~index_docstring ~index_name ~type_search) index end diff --git a/index/load_doc.mli b/index/load_doc.mli index 3ceec4f905..9e2abf8e40 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -7,7 +7,6 @@ module Make (Storage : Db.Storage.S) : sig index_docstring:bool -> index_name:bool -> type_search:bool - -> empty_payload:bool -> index:Odoc_search.Entry.t list -> unit end diff --git a/jsoo/dune b/jsoo/dune index 8e863dabfe..d1727d5e14 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -1,4 +1,4 @@ (executable (name main) (modes js) - (libraries common tyxml query storage_js brr checkseum.ocaml)) + (libraries common tyxml query storage_js brr checkseum.ocaml odoc.search)) diff --git a/jsoo/main.ml b/jsoo/main.ml index 1ab0d0dbce..3d09a9c207 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -107,8 +107,15 @@ let search message = let _ = Jv.(apply (get global "postMessage")) [| Jv.of_list - (fun Db.Elt.{ json_display; _ } -> - json_display |> Jstr.of_string |> Brr.Json.decode |> Result.get_ok) + (fun Db.Elt.{ name; rhs; doc_html; kind; url; _ } -> + let kind = string_of_kind kind in + let json_display = + Odoc_search.Json_display.of_strings + ~id:(String.split_on_char '.' name) + ~rhs ~doc:doc_html ~kind ~url + in + json_display |> Odoc_html.Json.to_string |> Jstr.of_string + |> Brr.Json.decode |> Result.get_ok) results |] in diff --git a/query/sort.ml b/query/sort.ml index 98dd266b86..fd264623fc 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -192,7 +192,7 @@ module Reasoning = struct | [], _ -> None | _, Elt.Kind.(Constructor type_paths | Field type_paths | Val type_paths) -> - Some (Type_distance.v query_type type_paths.paths) + Some (Type_distance.v query_type type_paths) | _ -> None let type_in_query query_type = query_type <> [] diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 5b03276c69..016af7591e 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -3,12 +3,15 @@ 5.1M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main - loading doc ! - doc loaded + Indexing in 9.149565s + trie_with_array_occ:0.35s + trie_with_array:0.26s + Cache.Elt_array_occ_trie.memo:2.40s + Cache.Elt_array_trie.memo:2.17s - real 0m18.813s - user 0m18.673s - sys 0m0.096s + real 0m15.614s + user 0m15.322s + sys 0m0.237s $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null @@ -21,8 +24,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 3196 db.js - 2408 db.js.gz + 2972 db.js + 2240 db.js.gz 1628 megaodocl.gz @@ -35,7 +38,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr cp: cannot stat 'sherlodoc_db.bin': No such file or directory [1] $ du -sh html/index.js - 8.0M html/index.js + 15M html/index.js $ ls html base fonts diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 8b7c3cb25e..6d77d484dc 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -8,12 +8,18 @@ 8.0K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main - loading doc ! - doc loaded + Indexing in 0.002059s + trie_with_array_occ:0.00s + trie_with_array:0.00s + Cache.Elt_array_occ_trie.memo:0.00s + Cache.Elt_array_trie.memo:0.00s $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null Index_lib.main - loading doc ! - doc loaded + Indexing in 0.002210s + trie_with_array_occ:0.00s + trie_with_array:0.00s + Cache.Elt_array_occ_trie.memo:0.00s + Cache.Elt_array_trie.memo:0.00s $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -37,7 +43,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cat db.js ../../../jsoo/main.bc.js > html/index.js $ cp sherlodoc_db.bin html $ du -sh html/index.js - 4.9M html/index.js + 13M html/index.js $ ls html Main fonts diff --git a/www/ui.ml b/www/ui.ml index aee6486dba..7865f6bc8d 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -14,37 +14,28 @@ let render_elt elt = let open Db.Elt in let link = render_link elt in let html_txt = Unsafe.data in - match elt.kind with - | Val { str = type_; _ } -> - [ txt "val " - ; a ~a:link [ em [ txt elt.name ] ] - ; txt " : " - ; html_txt type_ - ] - | Doc -> [ txt "comment "; a ~a:link [ em [ txt elt.name ] ] ] - | TypeDecl -> [ txt "type "; a ~a:link [ em [ txt elt.name ] ] ] - | Module -> [ txt "module "; a ~a:link [ em [ txt elt.name ] ] ] - | Exception -> [ txt "exception "; a ~a:link [ em [ txt elt.name ] ] ] - | Class_type -> [ txt "class type "; a ~a:link [ em [ txt elt.name ] ] ] - | Method -> [ txt "method "; a ~a:link [ em [ txt elt.name ] ] ] - | Class -> [ txt "class "; a ~a:link [ em [ txt elt.name ] ] ] - | TypeExtension -> - [ txt "type extension "; a ~a:link [ em [ txt elt.name ] ] ] - | ExtensionConstructor -> - [ txt "ext constructor "; a ~a:link [ em [ txt elt.name ] ] ] - | ModuleType -> [ txt "module type "; a ~a:link [ em [ txt elt.name ] ] ] - | Constructor { str = type_; _ } -> - [ txt "constructor " - ; a ~a:link [ em [ txt elt.name ] ] - ; txt " : " - ; html_txt type_ - ] - | Field { str = type_; _ } -> - [ txt "field " - ; a ~a:link [ em [ txt elt.name ] ] - ; txt " : " - ; html_txt type_ - ] + let rhs = + match elt.rhs with + | Some rhs -> [ html_txt rhs ] + | None -> [] + in + let kind = + match elt.kind with + | Val _ -> "val " + | Doc -> "comment " + | TypeDecl -> "type " + | Module -> "module " + | Exception -> "exception " + | Class_type -> "class type" + | Method -> "method " + | Class -> "class " + | TypeExtension -> "type extension " + | ExtensionConstructor -> "ext constructor " + | ModuleType -> "module type " + | Constructor _ -> "constructor " + | Field _ -> "field " + in + [ txt kind; a ~a:link [ em [ txt elt.name ] ] ] @ rhs let render_pkg elt = let open Db.Elt in From f2eb565b49652fb911f669df07b64d1da9be6054 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 8 Jun 2023 18:26:47 +0200 Subject: [PATCH 084/285] sorting ajustments --- index/load_doc.ml | 12 +++++++----- query/sort.ml | 16 +++++++++++++--- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/index/load_doc.ml b/index/load_doc.ml index bbd0c512b5..8d841a0005 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -12,7 +12,7 @@ module Make (Storage : Db.Storage.S) = struct let generic_cost ~ignore_no_doc name has_doc = String.length name (* + (5 * List.length path) TODO : restore depth based ordering *) - + (if ignore_no_doc || has_doc then 0 else 1000) + + (if ignore_no_doc || has_doc then 0 else 100) + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 let type_cost paths = @@ -23,9 +23,11 @@ module Make (Storage : Db.Storage.S) = struct | Constructor type_path | Field type_path | Val type_path -> type_cost type_path | Doc -> 400 - | TypeDecl | Module | Exception | Class_type | Method | Class - | TypeExtension | ExtensionConstructor | ModuleType -> - 200 + | TypeDecl | Module -> 0 + | Exception | Class_type | Method | Class + | TypeExtension -> 1000 + | ExtensionConstructor | ModuleType -> + 10 let cost ~name ~kind ~doc_html = let ignore_no_doc = @@ -170,7 +172,7 @@ module Make (Storage : Db.Storage.S) = struct let open Odoc_search.Entry in match kind with | TypeDecl _ -> Elt.Kind.TypeDecl - | Module -> Elt.Kind.ModuleType + | Module -> Elt.Kind.Module | Value { value = _; type_ } -> let paths = paths ~prefix:[] ~sgn:Pos type_ in Elt.Kind.val_ paths diff --git a/query/sort.ml b/query/sort.ml index fd264623fc..25674475a0 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -124,6 +124,9 @@ module Reasoning = struct Re.execp re s let with_word query_word name = + let low_query_word = String.lowercase_ascii query_word in + let has_case = low_query_word <> query_word in + let name = if not has_case then String.lowercase_ascii name else name in if String.starts_with ~prefix:query_word name || String.ends_with ~suffix:query_word name then PrefixSuffix @@ -138,7 +141,8 @@ module Reasoning = struct then SubUnderscore else if is_substring ~sub:query_word name then Sub - else if String.lowercase_ascii query_word = String.lowercase_ascii name + else if has_case + && is_substring ~sub:low_query_word (String.lowercase_ascii name) then Lowercase else (* Matches only in the docstring are always worse *) Doc @@ -272,6 +276,11 @@ module Reasoning = struct ; kind ; name_length } = + let ignore_no_doc = + match kind with + | Module | ModuleType -> true + | _ -> false + in let kind = match kind with | Val | Module | Constructor | Field | TypeDecl -> 0 @@ -292,6 +301,7 @@ module Reasoning = struct | Doc -> 1000) |> List.fold_left ( + ) 0 in + let type_cost = if type_in_elt && type_in_query then Option.get type_distance @@ -299,11 +309,11 @@ module Reasoning = struct then 0 else (* If query request a type, elements which do not have one are not to be - placed high. *) + placed high. They should never appear anyway. *) 10000 in (if is_stdlib then 0 else 100) - + (if has_doc then 0 else 500) + + (if has_doc || ignore_no_doc then 0 else 100) + name_matches + type_cost + kind + name_length let score ~query_name ~query_type elt = score (v query_name query_type elt) From eca30d9135462c0a409fa5f85d76c458bf39d953 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 12 Jun 2023 18:14:19 +0200 Subject: [PATCH 085/285] Sherldoc now has a cli interface --- cli/dune | 6 +++++ cli/main.ml | 45 +++++++++++++++++++++++++++++++ cli/unescape.mll | 21 +++++++++++++++ db/elt.ml | 17 +++++++++++- jsoo/main.ml | 19 +------------- test/cram/cli.t/main.ml | 57 ++++++++++++++++++++++++++++++++++++++++ test/cram/cli.t/page.mld | 10 +++++++ test/cram/cli.t/run.t | 14 ++++++++++ test/cram/dune | 2 +- test/cram/simple.t/run.t | 4 +-- www/www.ml | 2 +- 11 files changed, 174 insertions(+), 23 deletions(-) create mode 100644 cli/dune create mode 100644 cli/main.ml create mode 100644 cli/unescape.mll create mode 100644 test/cram/cli.t/main.ml create mode 100644 test/cram/cli.t/page.mld create mode 100644 test/cram/cli.t/run.t diff --git a/cli/dune b/cli/dune new file mode 100644 index 0000000000..0a7a0eae70 --- /dev/null +++ b/cli/dune @@ -0,0 +1,6 @@ +(ocamllex unescape) + +(executable + (name main) + (public_name sherlodoc) + (libraries cmdliner query storage_marshal)) \ No newline at end of file diff --git a/cli/main.ml b/cli/main.ml new file mode 100644 index 0000000000..de2da05914 --- /dev/null +++ b/cli/main.ml @@ -0,0 +1,45 @@ +let print_result + Db.Elt.{ name; rhs; url = _; kind; score = _; doc_html = _; pkg = _ } = + let kind = kind |> Db.Elt.Kind.to_string |> Unescape.string in + let name = Unescape.string name in + let rhs = rhs |> Option.value ~default:"" |> Unescape.string in + Printf.printf "%s %s%s\n" kind name rhs + +let search db query = + match Query.(api ~shards:db { query; packages = []; limit = 50 }) with + | _, [] -> print_endline "[No results]" + | _, (_ :: _ as results) -> + List.iter print_result results ; + flush stdout + +let rec search_loop db = + match In_channel.input_line stdin with + | Some query -> + search db query ; + search_loop db + | None -> print_endline "[Search session ended]" + +let main db query = + let db = Storage_marshal.load db in + match query with + | None -> search_loop db + | Some query -> search db query + +open Cmdliner + +let db_filename = + let doc = "The database to query" in + Arg.(required & opt (some file) None & info [ "db" ] ~docv:"DB" ~doc) + +let query = + let doc = "The query" in + Arg.(value & pos 0 (some string) None & info [] ~docv:"QUERY" ~doc) + +let main = Term.(const main $ db_filename $ query) + +let cmd = + let doc = "CLI interface to query sherlodoc" in + let info = Cmd.info "sherlodoc" ~doc in + Cmd.v info main + +let () = exit (Cmd.eval cmd) diff --git a/cli/unescape.mll b/cli/unescape.mll new file mode 100644 index 0000000000..5ca36fa2d4 --- /dev/null +++ b/cli/unescape.mll @@ -0,0 +1,21 @@ + +rule buffer b = parse +| "&" { Buffer.add_char b '&'; buffer b lexbuf } +| "<" { Buffer.add_char b '<'; buffer b lexbuf } +| ">" { Buffer.add_char b '>'; buffer b lexbuf } +| ">" { Buffer.add_char b '>'; buffer b lexbuf } +| ">" { Buffer.add_char b '>'; buffer b lexbuf } +| """ { Buffer.add_char b '>'; buffer b lexbuf } +| "'" { Buffer.add_char b '\''; buffer b lexbuf } +| "-" { Buffer.add_char b '-'; buffer b lexbuf } + +| eof { () } +| _ { Buffer.add_string b (Lexing.lexeme lexbuf) ; buffer b lexbuf } + +{ +let string str = + let lexbuf = Lexing.from_string str in + let b = Buffer.create (String.length str) in + buffer b lexbuf ; + Buffer.contents b +} \ No newline at end of file diff --git a/db/elt.ml b/db/elt.ml index 55e3788858..cad1192f45 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -51,6 +51,21 @@ module Kind = struct let constructor type_path = Constructor type_path let field type_path = Field type_path let val_ type_path = Val type_path + + let to_string = function + | Doc -> "doc" + | TypeDecl -> "type" + | Module -> "module" + | Exception -> "exception" + | Class_type -> "class type" + | Method -> "method" + | Class -> "class" + | TypeExtension -> "type ext" + | ExtensionConstructor -> "extension constructor" + | ModuleType -> "module type" + | Constructor _ -> "constructor" + | Field _ -> "field" + | Val _ -> "val" end module Package = struct @@ -80,7 +95,7 @@ module T = struct type t = { name : string ; rhs : string option - ; url:string + ; url : string ; kind : Kind.t ; score : int ; doc_html : string diff --git a/jsoo/main.ml b/jsoo/main.ml index 3d09a9c207..157537a999 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -1,20 +1,3 @@ -let string_of_kind (kind : Db.Elt.kind) = - let open Db.Elt.Kind in - match kind with - | Doc -> "doc" - | TypeDecl -> "type" - | Module -> "module" - | Exception -> "exception" - | Class_type -> "class type" - | Method -> "method" - | Class -> "class" - | TypeExtension -> "type ext" - | ExtensionConstructor -> "extension constructor" - | ModuleType -> "module type" - | Constructor _ -> "constructor" - | Field _ -> "field" - | Val _ -> "val" - let print_error e = let open Jv.Error in Printf.eprintf "Error : %s %s\n%s%!" @@ -108,7 +91,7 @@ let search message = Jv.(apply (get global "postMessage")) [| Jv.of_list (fun Db.Elt.{ name; rhs; doc_html; kind; url; _ } -> - let kind = string_of_kind kind in + let kind = Db.Elt.Kind.to_string kind in let json_display = Odoc_search.Json_display.of_strings ~id:(String.split_on_char '.' name) diff --git a/test/cram/cli.t/main.ml b/test/cram/cli.t/main.ml new file mode 100644 index 0000000000..c283b8a554 --- /dev/null +++ b/test/cram/cli.t/main.ml @@ -0,0 +1,57 @@ +type t = int +(** A comment *) + +(** {1 this is a title} + + and this is a paragraph + + *) + +module M = struct + type t + (** dsdsd *) +end + +(** a reference {!t}, and some {e formatted} {b content} with [code] and + +{[ + code blocks +]} + + *) +let v = 9 + +(** lorem 1 + *) +let lorem _ = 'a' + +(** lorem 2 + *) +let lorem2 _ = 'a' + +(** lorem 3 + *) +let lorem3 _ = 'e' + +(** lorem 4 + *) +let lorem4 = 1 + +type my_type = int * char + +type babar = + | A of string + | B + | C of + { z : int + ; w : char + } + +type _ celeste = + { x : babar + ; y : int -> string + } + +type 'a list = + | Cons of 'a * 'a list + | Nil diff --git a/test/cram/cli.t/page.mld b/test/cram/cli.t/page.mld new file mode 100644 index 0000000000..37fe4527d8 --- /dev/null +++ b/test/cram/cli.t/page.mld @@ -0,0 +1,10 @@ +{0 A title} + +A paragraph + +{v some verbatim v} + +{[and code]} + +- a list {e of} things +- bliblib diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t new file mode 100644 index 0000000000..7128faf496 --- /dev/null +++ b/test/cram/cli.t/run.t @@ -0,0 +1,14 @@ + $ ocamlc -c main.ml -bin-annot -I . + $ odoc compile -I . main.cmt + $ odoc compile -I . page.mld + $ odoc link -I . main.odoc + $ odoc link -I . page-page.odoc + $ cat $(find . -name '*.odocl') > megaodocl + $ du -sh megaodocl + 8.0K megaodocl + $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') 2> /dev/null > /dev/null + $ sherlodoc --db=db.bin "lorem" + val Main.lorem : 'a -> char + val Main.lorem4 : int + val Main.lorem2 : 'a -> char + val Main.lorem3 : 'a -> char diff --git a/test/cram/dune b/test/cram/dune index a430ff1235..f1894b6437 100644 --- a/test/cram/dune +++ b/test/cram/dune @@ -1,3 +1,3 @@ (cram (alias runexamples) - (deps %{bin:odoc} %{bin:sherlodoc_index} ../../jsoo/main.bc.js)) + (deps %{bin:odoc} %{bin:sherlodoc} %{bin:sherlodoc_index} ../../jsoo/main.bc.js)) diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 6d77d484dc..7327c25ed0 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -8,14 +8,14 @@ 8.0K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.002059s + Indexing in 0.000979s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s Cache.Elt_array_trie.memo:0.00s $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.002210s + Indexing in 0.000850s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s diff --git a/www/www.ml b/www/www.ml index 290494ae3b..dbb267ad91 100644 --- a/www/www.ml +++ b/www/www.ml @@ -105,7 +105,7 @@ let main db_format db_filename cache_max_age = open Cmdliner let db_format = - let doc = "Databse format" in + let doc = "Database format" in let kind = Arg.enum [ "ancient", `ancient; "marshal", `marshal ] in Arg.( required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) From 9c15dea6cb2b359d5afbf5e76d4d0f6686c9b27a Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 12 Jun 2023 18:17:50 +0200 Subject: [PATCH 086/285] ignore perf data --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a04b03726e..e63a38c5e0 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ _build/ _doc/ _coverage/ _opam/ +**/perf.data +**/perf.data.old From 9f58218fe6365f22e1f1e06c8fcabbc76c1edab4 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 13 Jun 2023 15:26:00 +0200 Subject: [PATCH 087/285] Tests order --- cli/main.ml | 39 ++++++++++++++++++--------- common/int.ml | 2 ++ common/option.ml | 3 +++ common/string.ml | 2 ++ db/cache.ml | 36 ++++++++++++++++++++----- db/db.ml | 6 ++++- query/query.ml | 1 + query/sort.ml | 55 ++++++++++++++++++++------------------ test/cram/cli.t/main.ml | 57 ---------------------------------------- test/cram/cli.t/main.mli | 42 +++++++++++++++++++++++++++++ test/cram/cli.t/run.t | 43 ++++++++++++++++++++++++------ 11 files changed, 175 insertions(+), 111 deletions(-) delete mode 100644 test/cram/cli.t/main.ml create mode 100644 test/cram/cli.t/main.mli diff --git a/cli/main.ml b/cli/main.ml index de2da05914..381c77a51f 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -1,29 +1,34 @@ -let print_result - Db.Elt.{ name; rhs; url = _; kind; score = _; doc_html = _; pkg = _ } = +open Common + +let pp_or cond pp_true pp_false ppf = if cond then pp_true ppf else pp_false ppf + +let print_result ~print_cost + Db.Elt.{ name; rhs; url = _; kind; score; doc_html = _; pkg = _ } = + let score = if print_cost then string_of_int score ^ " " else "" in let kind = kind |> Db.Elt.Kind.to_string |> Unescape.string in let name = Unescape.string name in - let rhs = rhs |> Option.value ~default:"" |> Unescape.string in - Printf.printf "%s %s%s\n" kind name rhs + let rhs = Option.map Unescape.string rhs in + Format.printf "%s%s %s%a\n" score kind name (Option.pp String.pp) rhs -let search db query = +let search ~print_cost ~db query = match Query.(api ~shards:db { query; packages = []; limit = 50 }) with | _, [] -> print_endline "[No results]" | _, (_ :: _ as results) -> - List.iter print_result results ; + List.iter (print_result ~print_cost) results ; flush stdout -let rec search_loop db = +let rec search_loop ~print_cost ~db = match In_channel.input_line stdin with | Some query -> - search db query ; - search_loop db + search ~print_cost ~db query ; + search_loop ~print_cost ~db | None -> print_endline "[Search session ended]" -let main db query = +let main db query print_cost = let db = Storage_marshal.load db in match query with - | None -> search_loop db - | Some query -> search db query + | None -> search_loop ~print_cost ~db + | Some query -> search ~print_cost ~db query open Cmdliner @@ -31,11 +36,19 @@ let db_filename = let doc = "The database to query" in Arg.(required & opt (some file) None & info [ "db" ] ~docv:"DB" ~doc) +let limit = + let doc = "The maximum number of results" in + Arg.(value & opt int 50 & info [ "limit"; "n" ] ~docv:"N" ~doc) + let query = let doc = "The query" in Arg.(value & pos 0 (some string) None & info [] ~docv:"QUERY" ~doc) -let main = Term.(const main $ db_filename $ query) +let print_cost = + let doc = "Prints cost of each result" in + Arg.(value & flag & info [ "print-cost" ] ~doc) + +let main = Term.(const main $ db_filename $ query $ print_cost) let cmd = let doc = "CLI interface to query sherlodoc" in diff --git a/common/int.ml b/common/int.ml index 9f4b82ec35..c029895d89 100644 --- a/common/int.ml +++ b/common/int.ml @@ -2,3 +2,5 @@ include Stdlib.Int module Map = Map.Make (Stdlib.Int) let hash : int -> int = Hashtbl.hash + +let pp = Format.pp_print_int \ No newline at end of file diff --git a/common/option.ml b/common/option.ml index 643112e48e..7139831226 100644 --- a/common/option.ml +++ b/common/option.ml @@ -8,3 +8,6 @@ end let hash hash_a = function | Some a -> Hashtbl.hash (Some (hash_a a)) | None -> Hashtbl.hash None + + +let pp = Format.pp_print_option \ No newline at end of file diff --git a/common/string.ml b/common/string.ml index 5f40354b72..5f0011194b 100644 --- a/common/string.ml +++ b/common/string.ml @@ -1,3 +1,5 @@ include Stdlib.String let hash : t -> int = Hashtbl.hash + +let pp = Format.pp_print_string \ No newline at end of file diff --git a/db/cache.ml b/db/cache.ml index 4811be2a82..f762530f90 100644 --- a/db/cache.ml +++ b/db/cache.ml @@ -25,7 +25,12 @@ module type Cachable = sig type key val sub : memo:(t -> uid * t) -> t -> key * t - (** [sub ~memo (v : t)] should replace subvalues [v'] of type [t] by [memo v'], + (** [sub ~memo (v : t)] is [(k, v')]. [v'] should be equal to [v], and [k] a + hashable shallow copy of [v]. + For every subvalue [vs] of type [t] we have [ks, vs' = memo vs]. + In [k], [vs] is replaced by [ks]. + In [v], [vs] is replaced by [vs']. + and subvalues [a] of type [A.t] by [A.memo a]. *) end @@ -179,19 +184,36 @@ end) module Elt = struct include Make (struct - include Elt + type t = Elt.t type key = { name : uid - ; score : int - ; rhs : uid + ; kind : int } + let int_of_kind = + let open Elt.Kind in + function + | Constructor _ -> 0 + | Field _ -> 1 + | Val _ -> 2 + (* the below looks like it could be [k -> (k, k) but it does not because of typing issues] *) + | Doc -> 3 + | TypeDecl -> 4 + | Module -> 5 + | Exception -> 6 + | Class_type -> 7 + | Method -> 8 + | Class -> 9 + | TypeExtension -> 10 + | ExtensionConstructor -> 11 + | ModuleType -> 12 + let sub ~memo:_ Elt.{ name; kind; doc_html; score; pkg; rhs; url } = let uid_name, name = String.memo name in - let uid_rhs, rhs = String_option.memo rhs in - (* let kind = Kind_memo.memo kind in *) - ( { name = uid_name; rhs = uid_rhs; score } + let _uid_rhs, rhs = String_option.memo rhs in + (*let _uid_kind, kind = Kind.memo kind in*) + ( { name = uid_name; kind = int_of_kind kind } , Elt.{ name; kind; doc_html; pkg; rhs; score; url } ) end) diff --git a/db/db.ml b/db/db.ml index 3c221f4eaa..86bf8cc7e6 100644 --- a/db/db.ml +++ b/db/db.ml @@ -48,6 +48,10 @@ let compact db = let list_of_string s = List.init (String.length s) (String.get s) +let list_of_string_rev s = + let len = String.length s in + List.init len (fun i -> String.get s (len - i - 1)) + module type S = sig type writer @@ -163,7 +167,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct db_names := go !db_names name let store_word word elt = - (word |> list_of_string |> List.rev |> store_chars) elt + (word |> list_of_string_rev |> store_chars) elt end module Storage = Storage diff --git a/query/query.ml b/query/query.ml index 0689461924..bc1c805ad6 100644 --- a/query/query.ml +++ b/query/query.ml @@ -95,6 +95,7 @@ let match_packages ~packages results = | [] -> results | _ -> Seq.filter (match_packages ~packages) results + let api ~(shards : Db.Elt.t array Db.t list) params = let query_name, query_typ, query_typ_arrow, pretty = Parser.of_string params.query diff --git a/query/sort.ml b/query/sort.ml index 25674475a0..882fa97443 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -112,6 +112,7 @@ end module Reasoning = struct module Name_match = struct type t = + | DotSuffix | PrefixSuffix | SubDot | SubUnderscore @@ -127,8 +128,10 @@ module Reasoning = struct let low_query_word = String.lowercase_ascii query_word in let has_case = low_query_word <> query_word in let name = if not has_case then String.lowercase_ascii name else name in - if String.starts_with ~prefix:query_word name - || String.ends_with ~suffix:query_word name + if String.ends_with ~suffix:("." ^ query_word) name + then DotSuffix + else if String.starts_with ~prefix:query_word name + || String.ends_with ~suffix:query_word name then PrefixSuffix else if is_substring ~sub:("(" ^ query_word) name || is_substring ~sub:(query_word ^ ")") name @@ -154,12 +157,13 @@ module Reasoning = struct let compare nm nm' = let to_int nm = match nm with - | PrefixSuffix -> 0 - | SubDot -> 1 - | SubUnderscore -> 2 - | Sub -> 3 - | Lowercase -> 4 - | Doc -> 5 + | DotSuffix -> 0 + | PrefixSuffix -> 1 + | SubDot -> 2 + | SubUnderscore -> 3 + | Sub -> 4 + | Lowercase -> 5 + | Doc -> 6 in Int.compare (to_int nm) (to_int nm') end @@ -199,7 +203,8 @@ module Reasoning = struct Some (Type_distance.v query_type type_paths) | _ -> None - let type_in_query query_type = query_type <> [] + let type_in_query query_type = + query_type <> [] && List.exists (( <> ) []) query_type let type_in_elt elt = let open Elt in @@ -293,11 +298,12 @@ module Reasoning = struct let open Name_match in name_matches |> List.map (function - | PrefixSuffix -> 0 - | SubDot -> 1 - | SubUnderscore -> 2 - | Sub -> 3 - | Lowercase -> 4 + | DotSuffix -> 0 + | PrefixSuffix -> 3 + | SubDot -> 4 + | SubUnderscore -> 5 + | Sub -> 6 + | Lowercase -> 7 | Doc -> 1000) |> List.fold_left ( + ) 0 in @@ -307,10 +313,12 @@ module Reasoning = struct then Option.get type_distance else if type_in_elt then 0 - else - (* If query request a type, elements which do not have one are not to be - placed high. They should never appear anyway. *) - 10000 + else if type_in_query + then + (* If query request a type, elements which do not have one should never + appear. *) + assert false + else 0 in (if is_stdlib then 0 else 100) + (if has_doc || ignore_no_doc then 0 else 100) @@ -320,10 +328,7 @@ module Reasoning = struct end let list query_name query_type results = - let scored = - List.map - (fun elt -> elt, Reasoning.score ~query_name ~query_type elt) - results - in - let sorted = List.sort (fun (_, a) (_, b) -> Int.compare a b) scored in - List.map (fun (elt, _) -> elt) sorted + results + |> List.map (fun elt -> + Elt.{ elt with score = Reasoning.score ~query_name ~query_type elt }) + |> List.sort Elt.compare diff --git a/test/cram/cli.t/main.ml b/test/cram/cli.t/main.ml deleted file mode 100644 index c283b8a554..0000000000 --- a/test/cram/cli.t/main.ml +++ /dev/null @@ -1,57 +0,0 @@ -type t = int -(** A comment *) - -(** {1 this is a title} - - and this is a paragraph - - *) - -module M = struct - type t - (** dsdsd *) -end - -(** a reference {!t}, and some {e formatted} {b content} with [code] and - -{[ - code blocks -]} - - *) -let v = 9 - -(** lorem 1 - *) -let lorem _ = 'a' - -(** lorem 2 - *) -let lorem2 _ = 'a' - -(** lorem 3 - *) -let lorem3 _ = 'e' - -(** lorem 4 - *) -let lorem4 = 1 - -type my_type = int * char - -type babar = - | A of string - | B - | C of - { z : int - ; w : char - } - -type _ celeste = - { x : babar - ; y : int -> string - } - -type 'a list = - | Cons of 'a * 'a list - | Nil diff --git a/test/cram/cli.t/main.mli b/test/cram/cli.t/main.mli new file mode 100644 index 0000000000..725e90f46d --- /dev/null +++ b/test/cram/cli.t/main.mli @@ -0,0 +1,42 @@ +type foo + +val unique_name : foo +val multiple_hit_1 : foo +val multiple_hit_2 : foo +val multiple_hit_3 : foo + +type name_conflict = foo + +val name_conflict : foo + +module Nest : sig + val nesting_priority : foo +end + +val nesting_priority : foo + +module Map : sig + val to_list : foo +end + +type 'a list + +module List : sig + type 'a t = 'a list + + val map : ('a -> 'b) -> 'a t -> 'b t +end + +val foo : foo +(** this is not a list nor a map *) + +type moo +type t + +val value : moo +val consume : moo -> unit +val consume_2 : moo -> moo -> unit +val consume_2_other : moo -> t -> unit + +val produce : unit -> moo +val produce_2' : unit -> unit -> moo diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 7128faf496..818416ea05 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -1,14 +1,41 @@ - $ ocamlc -c main.ml -bin-annot -I . - $ odoc compile -I . main.cmt + $ ocamlc -c main.mli -bin-annot -I . + $ odoc compile -I . main.cmti $ odoc compile -I . page.mld $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl - 8.0K megaodocl + 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') 2> /dev/null > /dev/null - $ sherlodoc --db=db.bin "lorem" - val Main.lorem : 'a -> char - val Main.lorem4 : int - val Main.lorem2 : 'a -> char - val Main.lorem3 : 'a -> char + $ sherlodoc --db=db.bin "unique_name" + val Main.unique_name : foo + $ sherlodoc --db=db.bin "multiple_hit" + val Main.multiple_hit_1 : foo + val Main.multiple_hit_2 : foo + val Main.multiple_hit_3 : foo + $ sherlodoc --db=db.bin "name_conflict" + type Main.name_conflict = foo + val Main.name_conflict : foo + $ sherlodoc --db=db.bin "nesting_priority" + val Main.nesting_priority : foo + val Main.Nest.nesting_priority : foo + $ sherlodoc --print-cost --db=db.bin "list" + 109 module Main.List + 209 type Main.list + 215 type Main.List.t = 'a list + 217 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 219 val Main.Map.to_list : foo + 1108 val Main.foo : foo + 1154 doc page + $ sherlodoc --print-cost --db=db.bin "list map" + 217 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 223 val Main.Map.to_list : foo + 2108 val Main.foo : foo + $ sherlodoc --print-cost --db=db.bin ":moo" + 210 val Main.value : moo + 213 val Main.produce : unit -> moo + 217 val Main.produce_2' : unit -> unit -> moo + $ sherlodoc --print-cost --db=db.bin ":moo -> _" + 212 val Main.consume : moo -> unit + 215 val Main.consume_2 : moo -> moo -> unit + 221 val Main.consume_2_other : moo -> t -> unit From d204bf4f127a5b0b6ccd47f15063dd186e670497 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 13 Jun 2023 15:41:25 +0200 Subject: [PATCH 088/285] CLI : database can be provided as an environment variable --- cli/main.ml | 22 ++++++++++++++++------ test/cram/cli.t/run.t | 17 +++++++++-------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index 381c77a51f..f38f9d7157 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -25,16 +25,26 @@ let rec search_loop ~print_cost ~db = | None -> print_endline "[Search session ended]" let main db query print_cost = - let db = Storage_marshal.load db in - match query with - | None -> search_loop ~print_cost ~db - | Some query -> search ~print_cost ~db query + match db with + | None -> + output_string stderr + "No database provided. Provide one by exporting the SHERLODOC_DB \ + variable, or using the --db option\n" ; + exit 1 + | Some db -> ( + let db = Storage_marshal.load db in + match query with + | None -> search_loop ~print_cost ~db + | Some query -> search ~print_cost ~db query) open Cmdliner let db_filename = - let doc = "The database to query" in - Arg.(required & opt (some file) None & info [ "db" ] ~docv:"DB" ~doc) + let env = + let doc = "The database to query" in + Cmd.Env.info "SHERLODOC_DB" ~doc + in + Arg.(value & opt (some file) None & info [ "db" ] ~docv:"DB" ~env) let limit = let doc = "The maximum number of results" in diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 818416ea05..1a23e82d59 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,19 +7,20 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') 2> /dev/null > /dev/null - $ sherlodoc --db=db.bin "unique_name" + $ export SHERLODOC_DB=db.bin + $ sherlodoc "unique_name" val Main.unique_name : foo - $ sherlodoc --db=db.bin "multiple_hit" + $ sherlodoc "multiple_hit" val Main.multiple_hit_1 : foo val Main.multiple_hit_2 : foo val Main.multiple_hit_3 : foo - $ sherlodoc --db=db.bin "name_conflict" + $ sherlodoc "name_conflict" type Main.name_conflict = foo val Main.name_conflict : foo - $ sherlodoc --db=db.bin "nesting_priority" + $ sherlodoc "nesting_priority" val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo - $ sherlodoc --print-cost --db=db.bin "list" + $ sherlodoc --print-cost "list" 109 module Main.List 209 type Main.list 215 type Main.List.t = 'a list @@ -27,15 +28,15 @@ 219 val Main.Map.to_list : foo 1108 val Main.foo : foo 1154 doc page - $ sherlodoc --print-cost --db=db.bin "list map" + $ sherlodoc --print-cost "list map" 217 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t 223 val Main.Map.to_list : foo 2108 val Main.foo : foo - $ sherlodoc --print-cost --db=db.bin ":moo" + $ sherlodoc --print-cost ":moo" 210 val Main.value : moo 213 val Main.produce : unit -> moo 217 val Main.produce_2' : unit -> unit -> moo - $ sherlodoc --print-cost --db=db.bin ":moo -> _" + $ sherlodoc --print-cost ":moo -> _" 212 val Main.consume : moo -> unit 215 val Main.consume_2 : moo -> moo -> unit 221 val Main.consume_2_other : moo -> t -> unit From cf3be1889312bfc0b7d774bffdd8cf0c2c7ff1d9 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 16 Jun 2023 15:56:50 +0200 Subject: [PATCH 089/285] UI update --- db/elt.ml | 17 ++++++++--------- test/cram/simple.t/main.ml | 33 ++++++++++++++++++++++++++++++++- test/cram/simple.t/run.t | 2 +- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/db/elt.ml b/db/elt.ml index cad1192f45..c985175e47 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -55,19 +55,18 @@ module Kind = struct let to_string = function | Doc -> "doc" | TypeDecl -> "type" - | Module -> "module" - | Exception -> "exception" - | Class_type -> "class type" - | Method -> "method" + | Module -> "mod" + | Exception -> "exn" + | Class_type -> "class" + | Method -> "meth" | Class -> "class" - | TypeExtension -> "type ext" - | ExtensionConstructor -> "extension constructor" - | ModuleType -> "module type" - | Constructor _ -> "constructor" + | TypeExtension -> "type" + | ExtensionConstructor -> "cons" + | ModuleType -> "sig" + | Constructor _ -> "cons" | Field _ -> "field" | Val _ -> "val" end - module Package = struct type t = { name : string diff --git a/test/cram/simple.t/main.ml b/test/cram/simple.t/main.ml index c283b8a554..7c6fbd1fb5 100644 --- a/test/cram/simple.t/main.ml +++ b/test/cram/simple.t/main.ml @@ -7,7 +7,25 @@ type t = int *) -module M = struct +module type Signature = sig end + +class istack = object + val mutable v = [0; 2] + + method pop = + match v with + | hd :: tl -> + v <- tl; + Some hd + | [] -> None + + method push hd = + v <- hd :: v +end + +class type my_class_type = object end + +module Modulule = struct type t (** dsdsd *) end @@ -55,3 +73,16 @@ type _ celeste = type 'a list = | Cons of 'a * 'a list | Nil + + +(** Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat + non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. *) +let long = 3 + +type ext_t = .. + +type ext_t += Ext_const of int \ No newline at end of file diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 7327c25ed0..aa1d4319c4 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -56,5 +56,5 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr page.html sherlodoc_db.bin $ cp -r html /tmp - $ firefox /tmp/html/Main/index.html +$ firefox /tmp/html/Main/index.html From 5fd47a4b8c77bc8791baf3d6b87e502b87c495b8 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 16 Jun 2023 17:31:55 +0200 Subject: [PATCH 090/285] sort improvement --- query/sort.ml | 16 ++++++++-------- test/cram/cli.t/main.mli | 9 +++++++++ test/cram/cli.t/run.t | 31 +++++++++++++++++++++++++------ 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/query/sort.ml b/query/sort.ml index 882fa97443..146b2355cb 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -128,7 +128,8 @@ module Reasoning = struct let low_query_word = String.lowercase_ascii query_word in let has_case = low_query_word <> query_word in let name = if not has_case then String.lowercase_ascii name else name in - if String.ends_with ~suffix:("." ^ query_word) name + if String.equal query_word name + || String.ends_with ~suffix:("." ^ query_word) name then DotSuffix else if String.starts_with ~prefix:query_word name || String.ends_with ~suffix:query_word name @@ -288,8 +289,7 @@ module Reasoning = struct in let kind = match kind with - | Val | Module | Constructor | Field | TypeDecl -> 0 - | ModuleType -> 20 + | Val | Module | ModuleType | Constructor | Field | TypeDecl -> 0 | Exception -> 30 | Class_type | Class | TypeExtension -> 40 | ExtensionConstructor | Method | Doc -> 50 @@ -299,11 +299,11 @@ module Reasoning = struct name_matches |> List.map (function | DotSuffix -> 0 - | PrefixSuffix -> 3 - | SubDot -> 4 - | SubUnderscore -> 5 - | Sub -> 6 - | Lowercase -> 7 + | PrefixSuffix -> 103 + | SubDot -> 104 + | SubUnderscore -> 105 + | Sub -> 106 + | Lowercase -> 107 | Doc -> 1000) |> List.fold_left ( + ) 0 in diff --git a/test/cram/cli.t/main.mli b/test/cram/cli.t/main.mli index 725e90f46d..f058fa4f46 100644 --- a/test/cram/cli.t/main.mli +++ b/test/cram/cli.t/main.mli @@ -40,3 +40,12 @@ val consume_2_other : moo -> t -> unit val produce : unit -> moo val produce_2' : unit -> unit -> moo + + +module type Modtype = sig + val v_modtype : foo +end + +module type S = sig end + +module S_to_S1 : sig end \ No newline at end of file diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 1a23e82d59..e0d0fc5e4d 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -21,16 +21,16 @@ val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo $ sherlodoc --print-cost "list" - 109 module Main.List + 109 mod Main.List 209 type Main.list - 215 type Main.List.t = 'a list - 217 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 219 val Main.Map.to_list : foo + 315 type Main.List.t = 'a list + 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 319 val Main.Map.to_list : foo 1108 val Main.foo : foo 1154 doc page $ sherlodoc --print-cost "list map" - 217 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 223 val Main.Map.to_list : foo + 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 423 val Main.Map.to_list : foo 2108 val Main.foo : foo $ sherlodoc --print-cost ":moo" 210 val Main.value : moo @@ -40,3 +40,22 @@ 212 val Main.consume : moo -> unit 215 val Main.consume_2 : moo -> moo -> unit 221 val Main.consume_2_other : moo -> t -> unit + $ sherlodoc --print-cost "modtype" + 112 sig Main.Modtype + 325 val Main.Modtype.v_modtype : foo + $ sherlodoc --print-cost "S" + 106 sig Main.S + 216 mod Main.List + 216 mod Main.Nest + 216 mod Main.S_to_S1 + 316 type Main.list + 318 type Main.List.t = 'a list + 319 val Main.consume : moo -> unit + 320 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 321 val Main.consume_2 : moo -> moo -> unit + 323 val Main.Map.to_list : foo + 327 val Main.consume_2_other : moo -> t -> unit + 328 val Main.nesting_priority : foo + 333 val Main.Nest.nesting_priority : foo + 1108 val Main.foo : foo + 1154 doc page From 15443cb8d547a4c9c6aec13d476dc55c47e9b32a Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 16 Jun 2023 18:01:00 +0200 Subject: [PATCH 091/285] format --- cli/dune | 2 +- common/int.ml | 3 +-- common/option.ml | 3 +-- common/string.ml | 3 +-- db/db.ml | 3 +-- db/elt.ml | 1 + index/index_lib.ml | 3 +-- index/load_doc.ml | 8 +++----- query/query.ml | 1 - test/cram/dune | 6 +++++- 10 files changed, 15 insertions(+), 18 deletions(-) diff --git a/cli/dune b/cli/dune index 0a7a0eae70..729873e534 100644 --- a/cli/dune +++ b/cli/dune @@ -3,4 +3,4 @@ (executable (name main) (public_name sherlodoc) - (libraries cmdliner query storage_marshal)) \ No newline at end of file + (libraries cmdliner query storage_marshal)) diff --git a/common/int.ml b/common/int.ml index c029895d89..c424efd1dc 100644 --- a/common/int.ml +++ b/common/int.ml @@ -2,5 +2,4 @@ include Stdlib.Int module Map = Map.Make (Stdlib.Int) let hash : int -> int = Hashtbl.hash - -let pp = Format.pp_print_int \ No newline at end of file +let pp = Format.pp_print_int diff --git a/common/option.ml b/common/option.ml index 7139831226..6d7123168e 100644 --- a/common/option.ml +++ b/common/option.ml @@ -9,5 +9,4 @@ let hash hash_a = function | Some a -> Hashtbl.hash (Some (hash_a a)) | None -> Hashtbl.hash None - -let pp = Format.pp_print_option \ No newline at end of file +let pp = Format.pp_print_option diff --git a/common/string.ml b/common/string.ml index 5f0011194b..ab153e88c4 100644 --- a/common/string.ml +++ b/common/string.ml @@ -1,5 +1,4 @@ include Stdlib.String let hash : t -> int = Hashtbl.hash - -let pp = Format.pp_print_string \ No newline at end of file +let pp = Format.pp_print_string diff --git a/db/db.ml b/db/db.ml index 86bf8cc7e6..1a6733ed64 100644 --- a/db/db.ml +++ b/db/db.ml @@ -166,8 +166,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct in db_names := go !db_names name - let store_word word elt = - (word |> list_of_string_rev |> store_chars) elt + let store_word word elt = (word |> list_of_string_rev |> store_chars) elt end module Storage = Storage diff --git a/db/elt.ml b/db/elt.ml index c985175e47..db090938d9 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -67,6 +67,7 @@ module Kind = struct | Field _ -> "field" | Val _ -> "val" end + module Package = struct type t = { name : string diff --git a/index/index_lib.ml b/index/index_lib.ml index 29b339ffaa..10efd2d87a 100644 --- a/index/index_lib.ml +++ b/index/index_lib.ml @@ -1,7 +1,6 @@ module Storage = Db.Storage -let main ~index_docstring ~index_name ~type_search ~index - ~db_filename storage = +let main ~index_docstring ~index_name ~type_search ~index ~db_filename storage = print_endline "Index_lib.main" ; let module Storage = (val storage : Storage.S) in let module Load_doc = Load_doc.Make (Storage) in diff --git a/index/load_doc.ml b/index/load_doc.ml index 8d841a0005..ee95cbe80e 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -23,11 +23,9 @@ module Make (Storage : Db.Storage.S) = struct | Constructor type_path | Field type_path | Val type_path -> type_cost type_path | Doc -> 400 - | TypeDecl | Module -> 0 - | Exception | Class_type | Method | Class - | TypeExtension -> 1000 - | ExtensionConstructor | ModuleType -> - 10 + | TypeDecl | Module -> 0 + | Exception | Class_type | Method | Class | TypeExtension -> 1000 + | ExtensionConstructor | ModuleType -> 10 let cost ~name ~kind ~doc_html = let ignore_no_doc = diff --git a/query/query.ml b/query/query.ml index bc1c805ad6..0689461924 100644 --- a/query/query.ml +++ b/query/query.ml @@ -95,7 +95,6 @@ let match_packages ~packages results = | [] -> results | _ -> Seq.filter (match_packages ~packages) results - let api ~(shards : Db.Elt.t array Db.t list) params = let query_name, query_typ, query_typ_arrow, pretty = Parser.of_string params.query diff --git a/test/cram/dune b/test/cram/dune index f1894b6437..5e020b6093 100644 --- a/test/cram/dune +++ b/test/cram/dune @@ -1,3 +1,7 @@ (cram (alias runexamples) - (deps %{bin:odoc} %{bin:sherlodoc} %{bin:sherlodoc_index} ../../jsoo/main.bc.js)) + (deps + %{bin:odoc} + %{bin:sherlodoc} + %{bin:sherlodoc_index} + ../../jsoo/main.bc.js)) From caaf3d2318c4e966ddd5b66e2346646cd777ccea Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 16 Jun 2023 17:57:33 +0200 Subject: [PATCH 092/285] Trie.find is allowed not to find anything --- db/trie.ml | 11 +++-- db/trie.mli | 2 +- index/load_doc.ml | 51 ++++++++++++---------- query/query.ml | 13 +++--- test/cram/cli.t/main.mli | 7 ++- test/cram/cli.t/run.t | 94 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 143 insertions(+), 35 deletions(-) diff --git a/db/trie.ml b/db/trie.ml index 01abe394dc..c72b015f38 100644 --- a/db/trie.ml +++ b/db/trie.ml @@ -46,14 +46,19 @@ let rec add path leaf t = let rec find path t = match t, path with - | _, [] -> t + | _, [] -> + print_endline "_, []" ; + Some t | Node node, p :: path -> begin match M.find p node.children with | child -> find path child - | exception Not_found -> t + | exception Not_found -> None end | Leaf (x :: xs, outcome), y :: ys when x = y -> find ys (Leaf (xs, outcome)) - | _ -> t + | _ -> + print_endline "_" ; + + None let rec fold_map merge transform t = match t with diff --git a/db/trie.mli b/db/trie.mli index 8a325c101f..5916911086 100644 --- a/db/trie.mli +++ b/db/trie.mli @@ -9,7 +9,7 @@ type 'a t = val empty : 'a t val add : char list -> ('a option -> 'a) -> 'a t -> 'a t -val find : char list -> 'a t -> 'a t +val find : char list -> 'a t -> 'a t option val fold_map : ('a -> 'a -> 'a) -> ('b -> 'a) -> 'b t -> 'a option val map_leaf : f:('a -> 'b) -> 'a t -> 'b t val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool diff --git a/index/load_doc.ml b/index/load_doc.ml index ee95cbe80e..0d8c787200 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -232,30 +232,33 @@ module Make (Storage : Db.Storage.S) = struct } = let open Odoc_search in let open Odoc_search.Entry in - let full_name = id |> Pretty.fullname |> String.concat "." in - let doc_txt = Render.text_of_doc doc in - let doc_html = - match doc_txt with - | "" -> "" - | _ -> doc |> Render.html_of_doc |> string_of_html - in - let kind' = convert_kind extra in - let name = - match extra with - | Doc _ -> Pretty.prefixname id - | _ -> full_name - in - let score = cost ~name ~kind:kind' ~doc_html in - let rhs = Json_display.rhs_of_kind extra in - let url = Render.url id in - let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in - if index_docstring then register_doc elt doc_txt ; - (if index_name - then - match extra with - | Doc _ -> () - | _ -> register_full_name full_name elt) ; - register_kind ~type_search elt extra + if Odoc_model.Paths.Identifier.is_internal id + then () + else + let full_name = id |> Pretty.fullname |> String.concat "." in + let doc_txt = Render.text_of_doc doc in + let doc_html = + match doc_txt with + | "" -> "" + | _ -> doc |> Render.html_of_doc |> string_of_html + in + let kind' = convert_kind extra in + let name = + match extra with + | Doc _ -> Pretty.prefixname id + | _ -> full_name + in + let score = cost ~name ~kind:kind' ~doc_html in + let rhs = Json_display.rhs_of_kind extra in + let url = Render.url id in + let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in + if index_docstring then register_doc elt doc_txt ; + (if index_name + then + match extra with + | Doc _ -> () + | _ -> register_full_name full_name elt) ; + register_kind ~type_search elt extra module Resolver = Odoc_odoc.Resolver diff --git a/query/query.ml b/query/query.ml index 0689461924..1f311a108b 100644 --- a/query/query.ml +++ b/query/query.ml @@ -33,6 +33,11 @@ let collapse_trie_with_poly ~count name t = end | _ -> collapse_trie ~count t +let find_succ trie name collapse = + match Trie.find name trie with + | Some trie -> collapse trie + | None -> Succ.empty + let find_inter ~shards names = List.fold_left (fun acc shard -> @@ -42,7 +47,7 @@ let find_inter ~shards names = @@ List.map (fun (name, count) -> let name' = List.concat_map Db.list_of_string name in - db |> Trie.find name' |> collapse_trie_with_poly ~count name) + find_succ db name' (collapse_trie_with_poly ~count name)) (regroup names) in Succ.union acc r) @@ -58,11 +63,7 @@ let find_names ~(shards : Db.Elt.t array Db.t list) names = (fun acc shard -> let db_names = shard.db_names in let candidates = - List.map - (fun name -> - let t = Trie.find name db_names in - collapse_triechar t) - names + List.map (fun name -> find_succ db_names name collapse_triechar) names in let candidates = inter_list candidates in Succ.union acc candidates) diff --git a/test/cram/cli.t/main.mli b/test/cram/cli.t/main.mli index f058fa4f46..5372817b43 100644 --- a/test/cram/cli.t/main.mli +++ b/test/cram/cli.t/main.mli @@ -48,4 +48,9 @@ end module type S = sig end -module S_to_S1 : sig end \ No newline at end of file +module S_to_S1 : sig end + +(**/**) +val hidden : foo +(**/**) + diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index e0d0fc5e4d..edad7fdb9f 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -9,18 +9,79 @@ $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') 2> /dev/null > /dev/null $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" + Node node, (p='e') :: path + Node node, (p='m') :: path + Node node, (p='a') :: path + Node node, (p='n') :: path + Node node, (p='_') :: path + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + _, [] val Main.unique_name : foo $ sherlodoc "multiple_hit" + Node node, (p='t') :: path + Node node, (p='i') :: path + Node node, (p='h') :: path + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + _, [] val Main.multiple_hit_1 : foo val Main.multiple_hit_2 : foo val Main.multiple_hit_3 : foo $ sherlodoc "name_conflict" + Node node, (p='t') :: path + Node node, (p='c') :: path + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + Leaf (x :: xs, outcome), y :: ys when x = y + _, [] type Main.name_conflict = foo val Main.name_conflict : foo $ sherlodoc "nesting_priority" + Node node, (p='y') :: path + Node node, (p='t') :: path + Node node, (p='i') :: path + Node node, (p='r') :: path + Node node, (p='o') :: path + Node node, (p='i') :: path + Node node, (p='r') :: path + Node node, (p='p') :: path + Node node, (p='_') :: path + Node node, (p='g') :: path + Node node, (p='n') :: path + Node node, (p='i') :: path + Node node, (p='t') :: path + Node node, (p='s') :: path + Node node, (p='e') :: path + Node node, (p='n') :: path + _, [] val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo $ sherlodoc --print-cost "list" + Node node, (p='t') :: path + Node node, (p='s') :: path + Node node, (p='i') :: path + Node node, (p='l') :: path + _, [] 109 mod Main.List 209 type Main.list 315 type Main.List.t = 'a list @@ -29,21 +90,50 @@ 1108 val Main.foo : foo 1154 doc page $ sherlodoc --print-cost "list map" + Node node, (p='t') :: path + Node node, (p='s') :: path + Node node, (p='i') :: path + Node node, (p='l') :: path + _, [] + Node node, (p='p') :: path + Node node, (p='a') :: path + Node node, (p='m') :: path + _, [] 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t 423 val Main.Map.to_list : foo 2108 val Main.foo : foo $ sherlodoc --print-cost ":moo" + Node node, (p='m') :: path + Node node, (p='o') :: path + Node node, (p='o') :: path + Node node, (p='+') :: path + _, [] 210 val Main.value : moo 213 val Main.produce : unit -> moo 217 val Main.produce_2' : unit -> unit -> moo $ sherlodoc --print-cost ":moo -> _" + Node node, (p='m') :: path + Node node, (p='o') :: path + Node node, (p='o') :: path + Node node, (p='-') :: path + _, [] 212 val Main.consume : moo -> unit 215 val Main.consume_2 : moo -> moo -> unit 221 val Main.consume_2_other : moo -> t -> unit $ sherlodoc --print-cost "modtype" + Node node, (p='e') :: path + Node node, (p='p') :: path + Node node, (p='y') :: path + Node node, (p='t') :: path + Node node, (p='d') :: path + Node node, (p='o') :: path + Node node, (p='m') :: path + _, [] 112 sig Main.Modtype 325 val Main.Modtype.v_modtype : foo $ sherlodoc --print-cost "S" + Node node, (p='s') :: path + _, [] 106 sig Main.S 216 mod Main.List 216 mod Main.Nest @@ -59,3 +149,7 @@ 333 val Main.Nest.nesting_priority : foo 1108 val Main.foo : foo 1154 doc page + $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" + Node node, (p='m') :: path + Node node, (p='n') :: path + [No results] From ad8445ed8080b62c56b84798f62da16a7c1bf2c2 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 16 Jun 2023 18:01:53 +0200 Subject: [PATCH 093/285] Tests update --- test/cram/base.t/run.t | 20 +++++----- test/cram/cli.t/run.t | 81 ---------------------------------------- test/cram/simple.t/run.t | 12 +++--- 3 files changed, 16 insertions(+), 97 deletions(-) diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 016af7591e..37a10eb477 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -3,15 +3,15 @@ 5.1M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 9.149565s - trie_with_array_occ:0.35s - trie_with_array:0.26s - Cache.Elt_array_occ_trie.memo:2.40s - Cache.Elt_array_trie.memo:2.17s + Indexing in 3.526566s + trie_with_array_occ:0.16s + trie_with_array:0.10s + Cache.Elt_array_occ_trie.memo:1.03s + Cache.Elt_array_trie.memo:1.33s - real 0m15.614s - user 0m15.322s - sys 0m0.237s + real 0m6.901s + user 0m6.772s + sys 0m0.110s $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null @@ -24,8 +24,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2972 db.js - 2240 db.js.gz + 2888 db.js + 2176 db.js.gz 1628 megaodocl.gz diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index edad7fdb9f..cc3126010e 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -9,78 +9,22 @@ $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') 2> /dev/null > /dev/null $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" - Node node, (p='e') :: path - Node node, (p='m') :: path - Node node, (p='a') :: path - Node node, (p='n') :: path - Node node, (p='_') :: path - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y _, [] val Main.unique_name : foo $ sherlodoc "multiple_hit" - Node node, (p='t') :: path - Node node, (p='i') :: path - Node node, (p='h') :: path - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y _, [] val Main.multiple_hit_1 : foo val Main.multiple_hit_2 : foo val Main.multiple_hit_3 : foo $ sherlodoc "name_conflict" - Node node, (p='t') :: path - Node node, (p='c') :: path - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y - Leaf (x :: xs, outcome), y :: ys when x = y _, [] type Main.name_conflict = foo val Main.name_conflict : foo $ sherlodoc "nesting_priority" - Node node, (p='y') :: path - Node node, (p='t') :: path - Node node, (p='i') :: path - Node node, (p='r') :: path - Node node, (p='o') :: path - Node node, (p='i') :: path - Node node, (p='r') :: path - Node node, (p='p') :: path - Node node, (p='_') :: path - Node node, (p='g') :: path - Node node, (p='n') :: path - Node node, (p='i') :: path - Node node, (p='t') :: path - Node node, (p='s') :: path - Node node, (p='e') :: path - Node node, (p='n') :: path _, [] val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo $ sherlodoc --print-cost "list" - Node node, (p='t') :: path - Node node, (p='s') :: path - Node node, (p='i') :: path - Node node, (p='l') :: path _, [] 109 mod Main.List 209 type Main.list @@ -90,49 +34,26 @@ 1108 val Main.foo : foo 1154 doc page $ sherlodoc --print-cost "list map" - Node node, (p='t') :: path - Node node, (p='s') :: path - Node node, (p='i') :: path - Node node, (p='l') :: path _, [] - Node node, (p='p') :: path - Node node, (p='a') :: path - Node node, (p='m') :: path _, [] 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t 423 val Main.Map.to_list : foo 2108 val Main.foo : foo $ sherlodoc --print-cost ":moo" - Node node, (p='m') :: path - Node node, (p='o') :: path - Node node, (p='o') :: path - Node node, (p='+') :: path _, [] 210 val Main.value : moo 213 val Main.produce : unit -> moo 217 val Main.produce_2' : unit -> unit -> moo $ sherlodoc --print-cost ":moo -> _" - Node node, (p='m') :: path - Node node, (p='o') :: path - Node node, (p='o') :: path - Node node, (p='-') :: path _, [] 212 val Main.consume : moo -> unit 215 val Main.consume_2 : moo -> moo -> unit 221 val Main.consume_2_other : moo -> t -> unit $ sherlodoc --print-cost "modtype" - Node node, (p='e') :: path - Node node, (p='p') :: path - Node node, (p='y') :: path - Node node, (p='t') :: path - Node node, (p='d') :: path - Node node, (p='o') :: path - Node node, (p='m') :: path _, [] 112 sig Main.Modtype 325 val Main.Modtype.v_modtype : foo $ sherlodoc --print-cost "S" - Node node, (p='s') :: path _, [] 106 sig Main.S 216 mod Main.List @@ -150,6 +71,4 @@ 1108 val Main.foo : foo 1154 doc page $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" - Node node, (p='m') :: path - Node node, (p='n') :: path [No results] diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index aa1d4319c4..7964e1584a 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -5,17 +5,17 @@ $ odoc link -I . page-page.odoc $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl - 8.0K megaodocl + 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.000979s + Indexing in 0.001100s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s Cache.Elt_array_trie.memo:0.00s $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.000850s + Indexing in 0.001721s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s @@ -31,9 +31,9 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 8 db.js - 4 db.js.gz - 4 megaodocl.gz + 12 db.js + 8 db.js.gz + 8 megaodocl.gz $ for f in $(find . -name '*.odocl'); do From 1983d3516ab09e9b745214b0e59353b140d4fb1f Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 16 Jun 2023 18:41:44 +0200 Subject: [PATCH 094/285] remove unwanted printing --- db/trie.ml | 2 -- test/cram/cli.t/run.t | 15 ++++----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/db/trie.ml b/db/trie.ml index c72b015f38..0023776d70 100644 --- a/db/trie.ml +++ b/db/trie.ml @@ -47,7 +47,6 @@ let rec add path leaf t = let rec find path t = match t, path with | _, [] -> - print_endline "_, []" ; Some t | Node node, p :: path -> begin match M.find p node.children with @@ -57,7 +56,6 @@ let rec find path t = | Leaf (x :: xs, outcome), y :: ys when x = y -> find ys (Leaf (xs, outcome)) | _ -> print_endline "_" ; - None let rec fold_map merge transform t = diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index cc3126010e..da0bd4e0b4 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -9,23 +9,18 @@ $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') 2> /dev/null > /dev/null $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" - _, [] val Main.unique_name : foo $ sherlodoc "multiple_hit" - _, [] val Main.multiple_hit_1 : foo val Main.multiple_hit_2 : foo val Main.multiple_hit_3 : foo $ sherlodoc "name_conflict" - _, [] type Main.name_conflict = foo val Main.name_conflict : foo $ sherlodoc "nesting_priority" - _, [] val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo $ sherlodoc --print-cost "list" - _, [] 109 mod Main.List 209 type Main.list 315 type Main.List.t = 'a list @@ -34,27 +29,21 @@ 1108 val Main.foo : foo 1154 doc page $ sherlodoc --print-cost "list map" - _, [] - _, [] 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t 423 val Main.Map.to_list : foo 2108 val Main.foo : foo $ sherlodoc --print-cost ":moo" - _, [] 210 val Main.value : moo 213 val Main.produce : unit -> moo 217 val Main.produce_2' : unit -> unit -> moo $ sherlodoc --print-cost ":moo -> _" - _, [] 212 val Main.consume : moo -> unit 215 val Main.consume_2 : moo -> moo -> unit 221 val Main.consume_2_other : moo -> t -> unit $ sherlodoc --print-cost "modtype" - _, [] 112 sig Main.Modtype 325 val Main.Modtype.v_modtype : foo $ sherlodoc --print-cost "S" - _, [] 106 sig Main.S 216 mod Main.List 216 mod Main.Nest @@ -72,3 +61,7 @@ 1154 doc page $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" [No results] + $ sherlodoc --print-cost "hidden" + [No results] + $ sherlodoc --print-cost ":mo" + [No results] From 9a49ebe00ce904d573004bd707102c4a65298511 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 19 Jun 2023 17:43:48 +0200 Subject: [PATCH 095/285] Returns results before type name is complete --- db/trie.ml | 17 +++++---- db/trie.mli | 2 +- query/query.ml | 75 ++++++++++++++++++++++++++++++++-------- test/cram/base.t/run.t | 2 +- test/cram/cli.t/run.t | 12 +++++-- test/cram/simple.t/run.t | 4 +-- 6 files changed, 86 insertions(+), 26 deletions(-) diff --git a/db/trie.ml b/db/trie.ml index 0023776d70..ff08ce710f 100644 --- a/db/trie.ml +++ b/db/trie.ml @@ -44,19 +44,24 @@ let rec add path leaf t = ; children = M.singleton y (Leaf (ys, outcome)) } -let rec find path t = + +let find path t = +let rec loop i path t = match t, path with | _, [] -> - Some t + Ok t | Node node, p :: path -> begin match M.find p node.children with - | child -> find path child - | exception Not_found -> None + | child -> loop (i + 1) path child + | exception Not_found -> Error (`Stopped_at (i, t)) end - | Leaf (x :: xs, outcome), y :: ys when x = y -> find ys (Leaf (xs, outcome)) + | Leaf (x :: xs, outcome), y :: ys when x = y -> loop (i + 1) ys (Leaf (xs, outcome)) | _ -> print_endline "_" ; - None + Error (`Stopped_at (i, t)) + + in + loop 0 path t let rec fold_map merge transform t = match t with diff --git a/db/trie.mli b/db/trie.mli index 5916911086..915a6901d2 100644 --- a/db/trie.mli +++ b/db/trie.mli @@ -9,7 +9,7 @@ type 'a t = val empty : 'a t val add : char list -> ('a option -> 'a) -> 'a t -> 'a t -val find : char list -> 'a t -> 'a t option +val find : char list -> 'a t -> ('a t, [> `Stopped_at of int * 'a t ]) result val fold_map : ('a -> 'a -> 'a) -> ('b -> 'a) -> 'b t -> 'a option val map_leaf : f:('a -> 'b) -> 'a t -> 'b t val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool diff --git a/query/query.ml b/query/query.ml index 1f311a108b..ffa6a6faf0 100644 --- a/query/query.ml +++ b/query/query.ml @@ -9,36 +9,67 @@ module Occ = Int.Map let inter_list xs = List.fold_left Succ.inter Succ.all xs -let collapse_count ~count occs = +let collapse_occ ~count occs = Occ.fold (fun k x acc -> if k < count then acc else Succ.union (Succ.of_array x) acc) occs Succ.empty -let collapse_trie ~count t = - match Trie.fold_map Succ.union (collapse_count ~count) t with +let collapse_trie_occ ~count t = + match Trie.fold_map Succ.union (collapse_occ ~count) t with | None -> Succ.empty | Some occ -> occ -let collapse_triechar t = +let collapse_trie t = match Trie.fold_map Succ.union Succ.of_array t with | None -> Succ.empty | Some s -> s +let rec collapse_trie_occ_polar ~parent_char ~polarity ~count t = + let open Trie in + match t with + | Leaf (_, leaf) -> + if parent_char = polarity then collapse_occ ~count leaf else Succ.empty + | Node { leaf = _; children; _ } -> + Char.Map.fold + (fun parent_char child acc -> + let res = + collapse_trie_occ_polar ~parent_char ~polarity ~count child + in + Succ.union acc res) + children Succ.empty + +let collapse_trie_occ_polar ~polarity ~count t = + let open Trie in + match t with + | Leaf _ -> Succ.empty + | Node { leaf = _; children; _ } -> + Char.Map.fold + (fun parent_char child acc -> + let res = + collapse_trie_occ_polar ~parent_char ~polarity ~count child + in + Succ.union acc res) + children Succ.empty + let collapse_trie_with_poly ~count name t = match name with | [ "POLY"; _ ] -> begin match t with - | Trie.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_count ~count s + | Trie.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s | _ -> Succ.empty end - | _ -> collapse_trie ~count t + | _ -> collapse_trie_occ ~count t -let find_succ trie name collapse = - match Trie.find name trie with - | Some trie -> collapse trie - | None -> Succ.empty +let _collapse_trie_with_poly_polar ~polarity ~count name t = + match name with + | [ "POLY"; _ ] -> begin + match t with + | Trie.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s + | _ -> Succ.empty + end + | _ -> collapse_trie_occ_polar ~polarity ~count t -let find_inter ~shards names = +let find_types ~shards names = List.fold_left (fun acc shard -> let db = shard.db_types in @@ -47,7 +78,18 @@ let find_inter ~shards names = @@ List.map (fun (name, count) -> let name' = List.concat_map Db.list_of_string name in - find_succ db name' (collapse_trie_with_poly ~count name)) + match Trie.find name' db with + | Ok trie -> collapse_trie_with_poly ~count name trie + | Error (`Stopped_at (i, sub_trie)) -> + let name_str = name' |> List.to_seq |> String.of_seq in + if i = String.length name_str - 1 + then + let polarity = name_str.[i] in + match polarity with + | '-' | '+' -> + collapse_trie_occ_polar ~polarity ~count sub_trie + | _ -> Succ.empty + else Succ.empty) (regroup names) in Succ.union acc r) @@ -63,7 +105,12 @@ let find_names ~(shards : Db.Elt.t array Db.t list) names = (fun acc shard -> let db_names = shard.db_names in let candidates = - List.map (fun name -> find_succ db_names name collapse_triechar) names + List.map + (fun name -> + match Trie.find name db_names with + | Ok trie -> collapse_trie trie + | Error _ -> Succ.empty) + names in let candidates = inter_list candidates in Succ.union acc candidates) @@ -81,7 +128,7 @@ let search ~(shards : Db.Elt.t array Db.t list) query_name query_typ = match query_typ with | None -> results_name | Some query_typ -> - let results_typ = find_inter ~shards query_typ in + let results_typ = find_types ~shards query_typ in Succ.inter results_name results_typ in results diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 37a10eb477..07c51d620f 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -1,7 +1,7 @@ $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 5.1M megaodocl - $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null + $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') Index_lib.main Indexing in 3.526566s trie_with_array_occ:0.16s diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index da0bd4e0b4..37c533f2ad 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -6,7 +6,13 @@ $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 4.0K megaodocl - $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') 2> /dev/null > /dev/null + $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') + Index_lib.main + Indexing in 0.001000s + trie_with_array_occ:0.00s + trie_with_array:0.00s + Cache.Elt_array_occ_trie.memo:0.00s + Cache.Elt_array_trie.memo:0.00s $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" val Main.unique_name : foo @@ -64,4 +70,6 @@ $ sherlodoc --print-cost "hidden" [No results] $ sherlodoc --print-cost ":mo" - [No results] + 217 val Main.value : moo + 220 val Main.produce : unit -> moo + 224 val Main.produce_2' : unit -> unit -> moo \ No newline at end of file diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 7964e1584a..674aa94590 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -8,14 +8,14 @@ 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.001100s + Indexing in 0.001068s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s Cache.Elt_array_trie.memo:0.00s $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.001721s + Indexing in 0.001206s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s From d0a258ebb4c363eacf3e28419e761c5cb550ca67 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 20 Jun 2023 11:19:24 +0200 Subject: [PATCH 096/285] Add support for typed search of extension constructors --- db/cache.ml | 6 ++-- db/elt.ml | 6 ++-- db/trie.ml | 1 - index/load_doc.ml | 17 +++++++---- query/query.ml | 4 +-- query/sort.ml | 14 +++++---- test/cram/base.t/run.t | 63 +++++++++++++++++++++++++++++++++++----- test/cram/cli.t/main.mli | 11 +++++++ test/cram/cli.t/run.t | 23 +++++++++++++-- test/cram/simple.t/run.t | 4 +-- 10 files changed, 118 insertions(+), 31 deletions(-) diff --git a/db/cache.ml b/db/cache.ml index f762530f90..e4a357eb1f 100644 --- a/db/cache.ml +++ b/db/cache.ml @@ -163,6 +163,9 @@ module Kind = Make (struct | Constructor type_ -> let uid, type_ = String_list_list.memo type_ in Constructor uid, Constructor type_ + | ExtensionConstructor type_ -> + let uid, type_ = String_list_list.memo type_ in + ExtensionConstructor uid, ExtensionConstructor type_ | Field type_ -> let uid, type_ = String_list_list.memo type_ in Field uid, Field type_ @@ -178,7 +181,6 @@ module Kind = Make (struct | Method -> Method, Method | Class -> Class, Class | TypeExtension -> TypeExtension, TypeExtension - | ExtensionConstructor -> ExtensionConstructor, ExtensionConstructor | ModuleType -> ModuleType, ModuleType end) @@ -206,7 +208,7 @@ module Elt = struct | Method -> 8 | Class -> 9 | TypeExtension -> 10 - | ExtensionConstructor -> 11 + | ExtensionConstructor _ -> 11 | ModuleType -> 12 let sub ~memo:_ Elt.{ name; kind; doc_html; score; pkg; rhs; url } = diff --git a/db/elt.ml b/db/elt.ml index db090938d9..c5771598a4 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -29,7 +29,7 @@ module Kind = struct | Method | Class | TypeExtension - | ExtensionConstructor + | ExtensionConstructor of 'a | ModuleType | Constructor of 'a | Field of 'a @@ -46,7 +46,7 @@ module Kind = struct let method_ = Method let class_ = Class let type_extension = TypeExtension - let extension_constructor = ExtensionConstructor + let extension_constructor type_path = ExtensionConstructor type_path let module_type = ModuleType let constructor type_path = Constructor type_path let field type_path = Field type_path @@ -61,7 +61,7 @@ module Kind = struct | Method -> "meth" | Class -> "class" | TypeExtension -> "type" - | ExtensionConstructor -> "cons" + | ExtensionConstructor _ -> "cons" | ModuleType -> "sig" | Constructor _ -> "cons" | Field _ -> "field" diff --git a/db/trie.ml b/db/trie.ml index ff08ce710f..c9bf44f38a 100644 --- a/db/trie.ml +++ b/db/trie.ml @@ -57,7 +57,6 @@ let rec loop i path t = end | Leaf (x :: xs, outcome), y :: ys when x = y -> loop (i + 1) ys (Leaf (xs, outcome)) | _ -> - print_endline "_" ; Error (`Stopped_at (i, t)) in diff --git a/index/load_doc.ml b/index/load_doc.ml index 0d8c787200..c6db634742 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -25,7 +25,7 @@ module Make (Storage : Db.Storage.S) = struct | Doc -> 400 | TypeDecl | Module -> 0 | Exception | Class_type | Method | Class | TypeExtension -> 1000 - | ExtensionConstructor | ModuleType -> 10 + | ExtensionConstructor _ | ModuleType -> 10 let cost ~name ~kind ~doc_html = let ignore_no_doc = @@ -191,7 +191,10 @@ module Make (Storage : Db.Storage.S) = struct | Method _ -> Method | Class _ -> Class | TypeExtension _ -> TypeExtension - | ExtensionConstructor _ -> ExtensionConstructor + | ExtensionConstructor { args; res } -> + let searchable_type = searchable_type_of_constructor args res in + let paths = paths ~prefix:[] ~sgn:Pos searchable_type in + Elt.Kind.extension_constructor paths | ModuleType -> ModuleType let convert_kind k = k |> convert_kind |> Cache.Kind_.memo @@ -215,9 +218,8 @@ module Make (Storage : Db.Storage.S) = struct | Method _ -> () | Class _ -> () | TypeExtension _ -> () - | ExtensionConstructor _ -> () | ModuleType -> () - | Constructor { args; res } -> + | ExtensionConstructor { args; res } | Constructor { args; res } -> let type_ = searchable_type_of_constructor args res in register_type_expr elt type_ | Field { mutable_ = _; parent_type; type_ } -> @@ -232,7 +234,12 @@ module Make (Storage : Db.Storage.S) = struct } = let open Odoc_search in let open Odoc_search.Entry in - if Odoc_model.Paths.Identifier.is_internal id + let is_type_extension = + match extra with + | TypeExtension _ -> true + | _ -> false + in + if Odoc_model.Paths.Identifier.is_internal id || is_type_extension then () else let full_name = id |> Pretty.fullname |> String.concat "." in diff --git a/query/query.ml b/query/query.ml index ffa6a6faf0..dade9c8b9a 100644 --- a/query/query.ml +++ b/query/query.ml @@ -53,7 +53,7 @@ let collapse_trie_occ_polar ~polarity ~count t = let collapse_trie_with_poly ~count name t = match name with - | [ "POLY"; _ ] -> begin + | [ "POLY"; ("+" | "-") ] -> begin match t with | Trie.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s | _ -> Succ.empty @@ -62,7 +62,7 @@ let collapse_trie_with_poly ~count name t = let _collapse_trie_with_poly_polar ~polarity ~count name t = match name with - | [ "POLY"; _ ] -> begin + | [ "POLY"; ("+" | "-") ] -> begin match t with | Trie.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s | _ -> Succ.empty diff --git a/query/sort.ml b/query/sort.ml index 146b2355cb..dbbc16e94f 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -199,9 +199,13 @@ module Reasoning = struct let open Elt in match query_type, elt.kind with | [], _ -> None - | _, Elt.Kind.(Constructor type_paths | Field type_paths | Val type_paths) - -> - Some (Type_distance.v query_type type_paths) + | ( _ + , Elt.Kind.( + ( ExtensionConstructor paths + | Constructor paths + | Field paths + | Val paths )) ) -> + Some (Type_distance.v query_type paths) | _ -> None let type_in_query query_type = @@ -210,7 +214,7 @@ module Reasoning = struct let type_in_elt elt = let open Elt in match elt.kind with - | Constructor _ | Field _ | Val _ -> true + | ExtensionConstructor _ | Constructor _ | Field _ | Val _ -> true | _ -> false let is_stdlib elt = @@ -227,7 +231,7 @@ module Reasoning = struct | Elt.Kind.Method -> Method | Elt.Kind.Class -> Class | Elt.Kind.TypeExtension -> TypeExtension - | Elt.Kind.ExtensionConstructor -> ExtensionConstructor + | Elt.Kind.ExtensionConstructor _ -> ExtensionConstructor | Elt.Kind.ModuleType -> ModuleType | Elt.Kind.Constructor _ -> Constructor | Elt.Kind.Field _ -> Field diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 07c51d620f..42ae50b6eb 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -2,16 +2,63 @@ $ du -sh megaodocl 5.1M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + Warning, resolved hidden path: Base__.Int63_emul.t Index_lib.main - Indexing in 3.526566s - trie_with_array_occ:0.16s - trie_with_array:0.10s - Cache.Elt_array_occ_trie.memo:1.03s - Cache.Elt_array_trie.memo:1.33s + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Int63_emul.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar + Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar + Warning, resolved hidden path: {For_generated_code}1.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Indexing in 3.142412s + trie_with_array_occ:0.15s + trie_with_array:0.09s + Cache.Elt_array_occ_trie.memo:0.68s + Cache.Elt_array_trie.memo:0.88s - real 0m6.901s - user 0m6.772s - sys 0m0.110s + real 0m5.366s + user 0m5.302s + sys 0m0.050s $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null diff --git a/test/cram/cli.t/main.mli b/test/cram/cli.t/main.mli index 5372817b43..941aec38dc 100644 --- a/test/cram/cli.t/main.mli +++ b/test/cram/cli.t/main.mli @@ -54,3 +54,14 @@ module S_to_S1 : sig end val hidden : foo (**/**) +val poly_1 : 'a -> 'b -> 'c + +val poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c + +type 'a boo + +val poly_param : 'a boo + +type extensible_type = .. + +type extensible_type += MyExtension of moo \ No newline at end of file diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 37c533f2ad..3f36f09df4 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -5,10 +5,10 @@ $ odoc link -I . page-page.odoc $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl - 4.0K megaodocl + 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') Index_lib.main - Indexing in 0.001000s + Indexing in 0.001179s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s @@ -46,6 +46,7 @@ 212 val Main.consume : moo -> unit 215 val Main.consume_2 : moo -> moo -> unit 221 val Main.consume_2_other : moo -> t -> unit + 266 cons Main.MyExtension : moo -> extensible_type $ sherlodoc --print-cost "modtype" 112 sig Main.Modtype 325 val Main.Modtype.v_modtype : foo @@ -61,15 +62,31 @@ 321 val Main.consume_2 : moo -> moo -> unit 323 val Main.Map.to_list : foo 327 val Main.consume_2_other : moo -> t -> unit + 327 type Main.extensible_type = .. 328 val Main.nesting_priority : foo 333 val Main.Nest.nesting_priority : foo + 373 cons Main.MyExtension : moo -> extensible_type 1108 val Main.foo : foo 1154 doc page $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" [No results] +TODO : get a result for the query bellow $ sherlodoc --print-cost "hidden" [No results] $ sherlodoc --print-cost ":mo" 217 val Main.value : moo 220 val Main.produce : unit -> moo - 224 val Main.produce_2' : unit -> unit -> moo \ No newline at end of file + 224 val Main.produce_2' : unit -> unit -> moo + $ sherlodoc ":'a" + val Main.poly_1 : 'a -> 'b -> 'c + val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + $ sherlodoc ": 'a -> 'b -> 'c " + [No results] + $ sherlodoc ": ('a -> 'b) -> 'a t -> 'b t" + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t +TODO : get a result for the query bellow + $ sherlodoc ": 'a bo" + [No results] + $ sherlodoc ":extensible_type" + cons Main.MyExtension : moo -> extensible_type diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 674aa94590..70e5e8f08d 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -8,14 +8,14 @@ 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.001068s + Indexing in 0.001682s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s Cache.Elt_array_trie.memo:0.00s $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.001206s + Indexing in 0.001114s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s From c842e03b8b7d0ec56b07434812b3d1beac4f3f47 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 20 Jun 2023 15:13:55 +0200 Subject: [PATCH 097/285] add new suffix tree algorithm --- db/suffix_tree.ml | 425 +++++++++++++++++++++++++++++++++++++++++++++ db/suffix_tree.mli | 20 +++ 2 files changed, 445 insertions(+) create mode 100644 db/suffix_tree.ml create mode 100644 db/suffix_tree.mli diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml new file mode 100644 index 0000000000..9fc1224bef --- /dev/null +++ b/db/suffix_tree.ml @@ -0,0 +1,425 @@ +module type SET = sig + type t + type elt + + val of_list : elt list -> t + val is_empty : t -> bool +end + +module Doc = struct + type 'a t = + { uid : 'a + ; text : string + } + + let length t = String.length t.text + 1 + + type 'a v = + | Terminal of 'a + | Char of char + + let get t i = + if i >= String.length t.text then Terminal t.uid else Char t.text.[i] + + let sub { text; _ } i = String.sub text i (String.length text - i) +end + +module Buf = struct + module Cache = Hashtbl.Make (struct + include String + + let hash = Hashtbl.hash + end) + + type t = + { buffer : Buffer.t + ; cache : int Cache.t + } + + let make () = { buffer = Buffer.create 16; cache = Cache.create 16 } + let contents t = Buffer.contents t.buffer + let get t i = Buffer.nth t.buffer i + + let add { buffer; cache } substr = + match Cache.find cache substr with + | start -> start + | exception Not_found -> + let start = Buffer.length buffer in + Buffer.add_string buffer substr ; + let stop = Buffer.length buffer in + assert (stop - start = String.length substr) ; + for idx = 1 to String.length substr - 1 do + Cache.add cache + (String.sub substr idx (String.length substr - idx)) + (start + idx) + done ; + start +end + +module Make (S : SET) = struct + module Terminals = struct + type t = S.elt list + + let empty = [] + let singleton x = [ x ] + + let add ~hint x xs = + match hint with + | Some (prev_xs, xxs) when prev_xs == xs -> xxs + | _ -> x :: xs + + let hash = Hashtbl.hash + let equal = List.equal ( == ) + + let mem x = function + | y :: _ -> x == y + | _ -> false + end + + module Char_map = Map.Make (Char) + + type node = + { mutable start : int + ; mutable len : int + ; mutable suffix_link : node option + ; mutable terminals : Terminals.t + ; mutable children : node Char_map.t + } + + type writer = + { buffer : Buf.t + ; root : node + } + + let make_root () = + { start = 0 + ; len = 0 + ; suffix_link = None + ; terminals = Terminals.empty + ; children = Char_map.empty + } + + let make () = { root = make_root (); buffer = Buf.make () } + + let split_at ~str node len = + let split_chr = Buf.get str (node.start + len) in + let new_node = + { start = node.start + ; len + ; suffix_link = None + ; terminals = Terminals.empty + ; children = Char_map.singleton split_chr node + } + in + node.start <- node.start + len + 1 ; + node.len <- node.len - 1 - len ; + new_node + + let lcp i_str i j_str j j_len = + let j_stop = j + j_len in + let rec go_lcp i j = + if i >= String.length i_str || j >= j_stop + then i + else + let i_chr, j_chr = i_str.[i], Buf.get j_str j in + if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1) + in + let i' = go_lcp i j in + i' - i + + let make_leaf ~prev_leaf ~buffer ~doc str_start = + let start = + match prev_leaf with + | None -> + let substr = Doc.sub doc (str_start - 1) in + let start = Buf.add buffer substr in + start + 1 + | Some (prev_leaf, _depth, _) -> + let doc_len = Doc.length doc in + prev_leaf.start + prev_leaf.len - (doc_len - str_start) + 1 + in + let len = Doc.length doc - str_start - 1 in + assert (start > 0) ; + { start + ; len + ; suffix_link = None + ; terminals = Terminals.singleton doc.Doc.uid + ; children = Char_map.empty + } + + let set_suffix_link ~prev ~depth node = + match prev with + | Some (prev, prev_depth) when depth = prev_depth -> + begin + match prev.suffix_link with + | None -> prev.suffix_link <- Some node + | Some node' -> assert (node == node') + end ; + None + | _ -> prev + + let add_document trie doc = + let root = trie.root in + let set_leaf ?debug:_ ~prev_leaf ~depth node = + if node == root + then None + else begin + begin + match prev_leaf with + | None -> () + | Some (prev_leaf, prev_depth, _) -> + assert (prev_depth = depth) ; + begin + match prev_leaf.suffix_link with + | None -> prev_leaf.suffix_link <- Some node + | Some node' -> assert (node' == node) + end + end ; + Some (node, depth - 1) + end + in + let rec go ~prev ~prev_leaf ~depth node i = + let prev = set_suffix_link ~prev ~depth node in + if i >= Doc.length doc + then assert (depth = 0) + else + let chr = Doc.get doc i in + let i, depth = i + 1, depth + 1 in + match chr with + | Terminal doc_uid -> + if not (Terminals.mem doc_uid node.terminals) + then begin + let hint = + Option.map + (fun (t, _, prev_terminals) -> prev_terminals, t.terminals) + prev_leaf + in + let prev_terminals = node.terminals in + node.terminals <- Terminals.add ~hint doc_uid node.terminals ; + let prev_leaf = + match set_leaf ~debug:"0" ~prev_leaf ~depth node with + | None -> None + | Some (t, depth) -> Some (t, depth, prev_terminals) + in + follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i + end + | Char chr -> begin + match Char_map.find chr node.children with + | child -> + assert (depth >= 0) ; + assert (i - depth >= 0) ; + assert (i < Doc.length doc) ; + let len = + lcp doc.Doc.text i trie.buffer child.start child.len + in + let i, depth = i + len, depth + len in + assert (i < Doc.length doc) ; + if len = child.len + then + if not (Char_map.is_empty child.children) + then go ~prev ~prev_leaf ~depth child i + else add_leaf ~prev_leaf ~node ~child ~depth ~i ~len + else begin + let new_child = split_at ~str:trie.buffer child len in + node.children <- Char_map.add chr new_child node.children ; + let prev = set_suffix_link ~prev ~depth new_child in + assert (prev = None) ; + add_leaf ~prev_leaf ~node ~child:new_child ~depth ~i ~len + end + | exception Not_found -> + let new_leaf = + make_leaf ~prev_leaf ~buffer:trie.buffer ~doc i + in + node.children <- Char_map.add chr new_leaf node.children ; + let prev_leaf = + set_leaf ~debug:"1" ~prev_leaf + ~depth:(depth + Doc.length doc - i) + new_leaf + in + let prev_leaf = + match prev_leaf with + | None -> None + | Some (t, depth) -> Some (t, depth, Terminals.empty) + in + follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i + end + and add_leaf ~prev_leaf ~node ~child ~depth ~i ~len = + match Doc.get doc i with + | Terminal doc_uid -> + if not (Terminals.mem doc_uid child.terminals) + then begin + let hint = + Option.map + (fun (t, _, prev_terminals) -> prev_terminals, t.terminals) + prev_leaf + in + let prev_terminals = child.terminals in + child.terminals <- Terminals.add ~hint doc_uid child.terminals ; + let prev_leaf = + match set_leaf ~debug:"2" ~prev_leaf ~depth:(depth + 1) child with + | None -> None + | Some (t, depth) -> Some (t, depth, prev_terminals) + in + assert (Doc.length doc - i = 1) ; + begin + match child.suffix_link with + | None -> + let i, depth = i - len, depth - len in + follow_suffix ~prev:None ~prev_leaf ~parent:node ~depth ~i + | Some next_child -> + let depth = depth - 1 in + go ~prev:None ~prev_leaf:None ~depth next_child i + end + end + | Char new_chr -> + let new_leaf = + make_leaf ~prev_leaf ~buffer:trie.buffer ~doc (i + 1) + in + let prev_leaf = + set_leaf ~debug:"3" ~prev_leaf + ~depth:(depth + Doc.length doc - i) + new_leaf + in + let prev_leaf = + match prev_leaf with + | None -> None + | Some (t, depth) -> Some (t, depth, Terminals.empty) + in + child.children <- Char_map.add new_chr new_leaf child.children ; + let prev = Some (child, depth - 1) in + let i, depth = i - len, depth - len in + follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i + and follow_suffix ~prev ~prev_leaf ~parent ~depth ~i = + match parent.suffix_link with + | None -> begin + let i = i - depth + 1 in + go ~prev:None ~prev_leaf ~depth:0 root i + end + | Some next -> + assert (depth >= 2) ; + assert (next != root) ; + go ~prev ~prev_leaf ~depth:(depth - 2) next (i - 1) + in + go ~prev:None ~prev_leaf:None ~depth:0 root 0 + + let add_suffixes t text elt = add_document t { Doc.text; uid = elt } + + module Automata = struct + module Uid = struct + let gen = ref 0 + + let make () = + let u = !gen in + gen := u + 1 ; + u + end + + module Hterm = Hashtbl.Make (Terminals) + + module T = struct + type node = + { start : int + ; len : int + ; terminals : S.t + ; children : node array + } + + type t = + { str : string + ; t : node + } + + let array_find ~str chr arr = + let rec go i = + if i >= Array.length arr + then raise Not_found + else + let node = arr.(i) in + if chr = str.[node.start - 1] then node else go (i + 1) + in + go 0 + + let lcp i_str i j_str j j_len = + let j_stop = j + j_len in + let rec go_lcp i j = + if i >= String.length i_str || j >= j_stop + then i + else + let i_chr, j_chr = i_str.[i], j_str.[j] in + if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1) + in + let i' = go_lcp i j in + i' - i + + let rec find ~str node pattern i = + if i >= String.length pattern + then node + else + let chr = pattern.[i] in + let child = array_find ~str chr node.children in + find_lcp ~str child pattern (i + 1) + + and find_lcp ~str child pattern i = + let n = lcp pattern i str child.start child.len in + if i + n = String.length pattern + then { child with start = child.start + n } + else if n = child.len + then find ~str child pattern (i + n) + else raise Not_found + + let find t pattern = + let child = find ~str:t.str t.t pattern 0 in + { str = t.str; t = child } + + let rec collapse acc t = + let acc = if S.is_empty t.terminals then acc else t.terminals :: acc in + Array.fold_left collapse acc t.children + + let collapse t = collapse [] t.t + end + + let export_terminals ~cache_term ts = + try Hterm.find cache_term ts + with Not_found -> + let result = Uid.make (), S.of_list ts in + Hterm.add cache_term ts result ; + result + + let rec export ~cache ~cache_term node = + let terminals_uid, terminals = + export_terminals ~cache_term node.terminals + in + let children = + Char_map.bindings + @@ Char_map.map (export ~cache ~cache_term) node.children + in + let children_uids = List.map (fun (chr, (uid, _)) -> chr, uid) children in + let key = node.start, node.len, terminals_uid, children_uids in + try Hashtbl.find cache key + with Not_found -> + let children = + Array.of_list @@ List.map (fun (_, (_, child)) -> child) children + in + let node = + { T.start = node.start; len = node.len; terminals; children } + in + let result = Uid.make (), node in + Hashtbl.add cache key result ; + result + + let clear ~str t = + let cache = Hashtbl.create 16 in + let cache_term = Hterm.create 16 in + let _, t = export ~cache ~cache_term t in + { T.str; t } + end + + type reader = Automata.T.t + + let export t = + let str = Buf.contents t.buffer in + Automata.clear ~str t.root + + let find = Automata.T.find + let to_sets = Automata.T.collapse +end diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli new file mode 100644 index 0000000000..65b90130d5 --- /dev/null +++ b/db/suffix_tree.mli @@ -0,0 +1,20 @@ +module type SET = sig + type t + type elt + + val of_list : elt list -> t + val is_empty : t -> bool +end + +module Make (S : SET) : sig + type writer + + val make : unit -> writer + val add_suffixes : writer -> string -> S.elt -> unit + + type reader + + val export : writer -> reader + val find : reader -> string -> reader + val to_sets : reader -> S.t list +end From d4f6c261280851e66311b347bcd67f00357f77b8 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 21 Jun 2023 13:56:16 +0200 Subject: [PATCH 098/285] Remove Hocc to fix bug regarding occurence higher than 1 --- common/list.ml | 4 ++++ common/pair.ml | 5 +++++ db/db.ml | 20 +++----------------- test/cram/base.t/run.t | 18 +++++++++--------- test/cram/cli.t/run.t | 5 +++-- test/cram/cli_poly.t/main.mli | 7 +++++++ test/cram/cli_poly.t/page.mld | 10 ++++++++++ test/cram/cli_poly.t/run.t | 22 ++++++++++++++++++++++ test/cram/simple.t/run.t | 4 ++-- 9 files changed, 65 insertions(+), 30 deletions(-) create mode 100644 common/list.ml create mode 100644 common/pair.ml create mode 100644 test/cram/cli_poly.t/main.mli create mode 100644 test/cram/cli_poly.t/page.mld create mode 100644 test/cram/cli_poly.t/run.t diff --git a/common/list.ml b/common/list.ml new file mode 100644 index 0000000000..73a51adc39 --- /dev/null +++ b/common/list.ml @@ -0,0 +1,4 @@ +include Stdlib.List + +let to_string ?(start="[") ?(sep="; ") ?(end_="]") a li = + start ^ (li |> map a |> String.concat sep ) ^ end_ \ No newline at end of file diff --git a/common/pair.ml b/common/pair.ml new file mode 100644 index 0000000000..9f288167e9 --- /dev/null +++ b/common/pair.ml @@ -0,0 +1,5 @@ +type ('a, 'b) t = 'a * 'b + +let to_string ?(start = "(") ?(end_ = ")") ?(sep = ", ") to_string_a to_string_b + (a, b) = + String.concat "" [ start; to_string_a a; sep; to_string_b b; end_ ] diff --git a/db/db.ml b/db/db.ml index 1a6733ed64..a380b5d0ab 100644 --- a/db/db.ml +++ b/db/db.ml @@ -97,13 +97,6 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let equal x y = Option.equal (fun x y -> x == y) x y end) - module Hocc = Hashtbl.Make (struct - type t = Elt.Set.t Occ.t option - - let hash = Hashtbl.hash - let equal x y = Option.equal (fun x y -> x == y) x y - end) - let set_add elt = function | None -> Elt.Set.singleton elt | Some s -> Elt.Set.add elt s @@ -122,29 +115,22 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let s = set_add ~hs elt s in Occ.add count s m - let candidates_add ~ho ~hs elt ~count opt = - try Hocc.find ho opt - with Not_found -> - let r = candidates_add ~hs ~count elt opt in - Hocc.add ho opt r ; - r - let store ~ho ~hs name elt ~count = + let store ~hs name elt ~count = let rec go db name = match name with | [] -> db | _ :: next -> incr load_counter ; - let db = Trie.add name (candidates_add ~ho ~hs elt ~count) db in + let db = Trie.add name (candidates_add ~hs elt ~count) db in go db next in db_types := go !db_types name let store_type_paths elt paths = - let ho = Hocc.create 16 in let hs = Hset.create 16 in List.iter - (fun (path, count) -> store ~ho ~hs ~count path elt) + (fun (path, count) -> store ~hs ~count path elt) (regroup_chars paths) let store_type_paths elt paths = diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 42ae50b6eb..9e1f5efc41 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -50,15 +50,15 @@ Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t - Indexing in 3.142412s - trie_with_array_occ:0.15s + Indexing in 3.984759s + trie_with_array_occ:0.18s trie_with_array:0.09s - Cache.Elt_array_occ_trie.memo:0.68s - Cache.Elt_array_trie.memo:0.88s + Cache.Elt_array_occ_trie.memo:0.92s + Cache.Elt_array_trie.memo:1.02s - real 0m5.366s - user 0m5.302s - sys 0m0.050s + real 0m6.693s + user 0m6.558s + sys 0m0.106s $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null @@ -71,8 +71,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2888 db.js - 2176 db.js.gz + 2896 db.js + 2184 db.js.gz 1628 megaodocl.gz diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 3f36f09df4..bd4c15a74d 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -8,7 +8,7 @@ 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') Index_lib.main - Indexing in 0.001179s + Indexing in 0.002140s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s @@ -82,7 +82,8 @@ TODO : get a result for the query bellow val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.List.map : ('a -> 'b) -> 'a t -> 'b t $ sherlodoc ": 'a -> 'b -> 'c " - [No results] + val Main.poly_1 : 'a -> 'b -> 'c + val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c $ sherlodoc ": ('a -> 'b) -> 'a t -> 'b t" val Main.List.map : ('a -> 'b) -> 'a t -> 'b t TODO : get a result for the query bellow diff --git a/test/cram/cli_poly.t/main.mli b/test/cram/cli_poly.t/main.mli new file mode 100644 index 0000000000..02fe405fc4 --- /dev/null +++ b/test/cram/cli_poly.t/main.mli @@ -0,0 +1,7 @@ + + +val poly_1 : 'a -> 'b -> 'c + + + + diff --git a/test/cram/cli_poly.t/page.mld b/test/cram/cli_poly.t/page.mld new file mode 100644 index 0000000000..37fe4527d8 --- /dev/null +++ b/test/cram/cli_poly.t/page.mld @@ -0,0 +1,10 @@ +{0 A title} + +A paragraph + +{v some verbatim v} + +{[and code]} + +- a list {e of} things +- bliblib diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t new file mode 100644 index 0000000000..d858e2d460 --- /dev/null +++ b/test/cram/cli_poly.t/run.t @@ -0,0 +1,22 @@ + $ ocamlc -c main.mli -bin-annot -I . + $ odoc compile -I . main.cmti + $ odoc compile -I . page.mld + $ odoc link -I . main.odoc + $ odoc link -I . page-page.odoc + $ cat $(find . -name '*.odocl') > megaodocl + $ du -sh megaodocl + 4.0K megaodocl + $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') + Index_lib.main + Indexing in 0.000579s + trie_with_array_occ:0.00s + trie_with_array:0.00s + Cache.Elt_array_occ_trie.memo:0.00s + Cache.Elt_array_trie.memo:0.00s + $ export SHERLODOC_DB=db.bin +TODO : get a result for the query bellow + $ sherlodoc ":'a" + val Main.poly_1 : 'a -> 'b -> 'c + $ sherlodoc ": 'a -> 'b -> 'c " + val Main.poly_1 : 'a -> 'b -> 'c +TODO : get a result for the query bellow diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 70e5e8f08d..0d381d4e7c 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -8,14 +8,14 @@ 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.001682s + Indexing in 0.002069s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s Cache.Elt_array_trie.memo:0.00s $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null Index_lib.main - Indexing in 0.001114s + Indexing in 0.001399s trie_with_array_occ:0.00s trie_with_array:0.00s Cache.Elt_array_occ_trie.memo:0.00s From b039c45ffdbdac1959a5e8a3b5d9b84896120c17 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 21 Jun 2023 17:25:50 +0200 Subject: [PATCH 099/285] WIP integrate suffix_tree --- cli/dune | 2 + cli/main.ml | 2 +- common/dune | 3 +- common/list.ml | 5 + common/string.ml | 11 + common/test/dune | 2 + common/test/test.ml | 2 +- db/{cache.ml => cache.ml_} | 2 +- db/{cache.mli => cache.mli_} | 2 +- db/db.ml | 134 ++--------- db/db.mli | 19 +- db/dune | 4 +- db/elt.ml | 20 +- db/occ.ml | 26 +++ db/storage.ml | 6 +- db/suffix_tree.ml | 88 ++++--- db/suffix_tree.mli | 11 +- db/trie.ml | 99 -------- db/trie.mli | 15 -- db/types.ml | 7 +- index/index_lib.ml | 3 +- index/load_doc.ml | 4 +- index/load_doc.mli | 1 - query/dune | 2 + query/query.ml | 129 +++++------ query/query.mli | 2 +- query/sort.ml | 2 +- query/succ.ml | 2 +- store/storage_ancient.ml | 5 +- test/cram/cli.t/run.t | 409 ++++++++++++++++++++++++++++++--- test/cram/cli_small.t/main.mli | 9 + test/cram/cli_small.t/run.t | 110 +++++++++ www/ui.ml | 17 +- 33 files changed, 750 insertions(+), 405 deletions(-) rename db/{cache.ml => cache.ml_} (99%) rename db/{cache.mli => cache.mli_} (98%) create mode 100644 db/occ.ml delete mode 100644 db/trie.ml delete mode 100644 db/trie.mli create mode 100644 test/cram/cli_small.t/main.mli create mode 100644 test/cram/cli_small.t/run.t diff --git a/cli/dune b/cli/dune index 729873e534..46e7aa7851 100644 --- a/cli/dune +++ b/cli/dune @@ -2,5 +2,7 @@ (executable (name main) + (flags + (:standard -open Common)) (public_name sherlodoc) (libraries cmdliner query storage_marshal)) diff --git a/cli/main.ml b/cli/main.ml index f38f9d7157..4279cb3da4 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -1,4 +1,4 @@ -open Common + let pp_or cond pp_true pp_false ppf = if cond then pp_true ppf else pp_false ppf diff --git a/common/dune b/common/dune index 35b990621c..9e53196cfa 100644 --- a/common/dune +++ b/common/dune @@ -1,2 +1,3 @@ (library - (name common)) + (name common) + (libraries pprint)) diff --git a/common/list.ml b/common/list.ml index 73a51adc39..7542b8819f 100644 --- a/common/list.ml +++ b/common/list.ml @@ -1,4 +1,9 @@ include Stdlib.List let to_string ?(start="[") ?(sep="; ") ?(end_="]") a li = + start ^ (li |> map a |> String.concat sep ) ^ end_ + + + +let pprint ?(start="[") ?(sep="; ") ?(end_="]") a li = start ^ (li |> map a |> String.concat sep ) ^ end_ \ No newline at end of file diff --git a/common/string.ml b/common/string.ml index ab153e88c4..de720f9239 100644 --- a/common/string.ml +++ b/common/string.ml @@ -2,3 +2,14 @@ include Stdlib.String let hash : t -> int = Hashtbl.hash let pp = Format.pp_print_string + +module Hashtbl = Hashtbl.Make (struct + type nonrec t = t + + let equal = equal + let hash = hash +end) + +let rev str = + let len = length str in + init len (fun i -> get str (len - i - 1)) diff --git a/common/test/dune b/common/test/dune index 303021488f..67ad57e47a 100644 --- a/common/test/dune +++ b/common/test/dune @@ -1,3 +1,5 @@ (test (name test) + (flags + (:standard -open Common)) (libraries alcotest common)) diff --git a/common/test/test.ml b/common/test/test.ml index 7c80b40fa0..6a1a3af2ad 100644 --- a/common/test/test.ml +++ b/common/test/test.ml @@ -1,4 +1,4 @@ -open Common + let rec succ_ge_reference i ~compare elt arr = Printf.printf "ref_succ_ge %i\n%!" i ; diff --git a/db/cache.ml b/db/cache.ml_ similarity index 99% rename from db/cache.ml rename to db/cache.ml_ index e4a357eb1f..9d318f111c 100644 --- a/db/cache.ml +++ b/db/cache.ml_ @@ -1,4 +1,4 @@ -open Common + type uid = int diff --git a/db/cache.mli b/db/cache.mli_ similarity index 98% rename from db/cache.mli rename to db/cache.mli_ index 6143bd10eb..8cb8645116 100644 --- a/db/cache.mli +++ b/db/cache.mli_ @@ -2,7 +2,7 @@ a nuumber a OCaml types. Every sharable element inside a type is also shared.*) -open Common + val clear : unit -> unit (** [clear ()] removes every value from the caches of every types. *) diff --git a/db/db.ml b/db/db.ml index a380b5d0ab..2f5c1a6aaf 100644 --- a/db/db.ml +++ b/db/db.ml @@ -1,57 +1,12 @@ -open Common module Elt = Elt module Types = Types module Storage_toplevel = Storage -module Trie = Trie -module Cache = Cache +module Suffix_tree = Suffix_tree include Types module Occ = Int.Map -let trie_with_array trie = - Trie.map_leaf ~f:(fun set -> set |> Elt.Set.to_seq |> Array.of_seq) trie - -let trie_with_set trie = - Trie.map_leaf ~f:(fun arr -> arr |> Array.to_seq |> Elt.Set.of_seq) trie - -let trie_with_array_occ trie = - Trie.map_leaf - ~f:(fun occs -> - occs |> Int.Map.map (fun set -> set |> Elt.Set.to_seq |> Array.of_seq)) - trie - -let trie_with_set_occ trie = - Trie.map_leaf - ~f:(fun occs -> - occs |> Int.Map.map (fun arr -> arr |> Array.to_seq |> Elt.Set.of_seq)) - trie - -let compact db = - let open Types in - let { db_types; db_names } = db in - let t0 = Unix.gettimeofday () in - let db_types = trie_with_array_occ db_types in - let t1 = Unix.gettimeofday () in - let db_names = trie_with_array db_names in - let t2 = Unix.gettimeofday () in - let db_types = Cache.Elt_array_occ_trie_.memo db_types in - let t3 = Unix.gettimeofday () in - let db_names = Cache.Elt_array_trie_.memo db_names in - let t4 = Unix.gettimeofday () in - Printf.printf - "trie_with_array_occ:%.2fs\n\ - trie_with_array:%.2fs\n\ - Cache.Elt_array_occ_trie.memo:%.2fs\n\ - Cache.Elt_array_trie.memo:%.2fs\n\ - %!" - (t1 -. t0) (t2 -. t1) (t3 -. t2) (t4 -. t3) ; - { db_types; db_names } - let list_of_string s = List.init (String.length s) (String.get s) -let list_of_string_rev s = - let len = String.length s in - List.init len (fun i -> String.get s (len - i - 1)) - module type S = sig type writer @@ -65,8 +20,8 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct type writer = Storage.writer let load_counter = ref 0 - let db_types = ref Trie.empty - let db_names = ref Trie.empty + let db_types = Suffix_tree.With_occ.make () + let db_names = Suffix_tree.With_elts.make () module Hset2 = Hashtbl.Make (struct type t = Elt.Set.t * Elt.Set.t @@ -84,75 +39,28 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let export h = load_counter := 0 ; - let db = { db_types = !db_types; db_names = !db_names } in - let db = compact db in - Storage.save ~db:h db ; - db_types := Trie.empty ; - db_names := Trie.empty - - module Hset = Hashtbl.Make (struct - type t = Elt.Set.t option - - let hash = Hashtbl.hash - let equal x y = Option.equal (fun x y -> x == y) x y - end) - - let set_add elt = function - | None -> Elt.Set.singleton elt - | Some s -> Elt.Set.add elt s - - let set_add ~hs elt opt = - try Hset.find hs opt - with Not_found -> - let r = set_add elt opt in - Hset.add hs opt r ; - r - - let candidates_add ~hs elt ~count = function - | None -> Occ.singleton count (set_add ~hs elt None) - | Some m -> - let s = Occ.find_opt count m in - let s = set_add ~hs elt s in - Occ.add count s m - - - let store ~hs name elt ~count = - let rec go db name = - match name with - | [] -> db - | _ :: next -> - incr load_counter ; - let db = Trie.add name (candidates_add ~hs elt ~count) db in - go db next + let db = + { db_types = Suffix_tree.With_occ.export db_types + ; db_names = Suffix_tree.With_elts.export db_names + } in - db_types := go !db_types name + PPrint.ToChannel.pretty 0.8 120 stdout + (Suffix_tree.With_elts.pprint db.db_names) ; + Storage.save ~db:h db - let store_type_paths elt paths = - let hs = Hset.create 16 in - List.iter - (fun (path, count) -> store ~hs ~count path elt) - (regroup_chars paths) + let store name elt ~count = + Suffix_tree.With_occ.add_suffixes db_types name (count, elt) let store_type_paths elt paths = - store_type_paths elt - (List.map - (fun xs -> - let xs = List.concat_map list_of_string xs in - xs) - paths) - - let store_chars name elt = - let hs = Hset.create 16 in - let rec go db = function - | [] -> db - | _ :: next as name -> - incr load_counter ; - let db = Trie.add name (set_add ~hs elt) db in - go db next - in - db_names := go !db_names name - - let store_word word elt = (word |> list_of_string_rev |> store_chars) elt + List.iter + (fun (path, count) -> + let word = String.concat "" path in + store ~count word elt) + (regroup paths) + + let store_word word elt = + let word = word |> String.lowercase_ascii in + Suffix_tree.With_elts.add_suffixes db_names word elt end module Storage = Storage diff --git a/db/db.mli b/db/db.mli index 5396a61e41..8ff48396bc 100644 --- a/db/db.mli +++ b/db/db.mli @@ -1,24 +1,15 @@ -open Common module Elt = Elt module Types = Types module Storage = Storage -module Trie = Trie -module Cache = Cache +module Suffix_tree = Suffix_tree -val trie_with_array : Elt.Set.t Trie.t -> Elt.t array Trie.t -val trie_with_set : Elt.t array Trie.t -> Elt.Set.t Trie.t +type t = Types.t = -val trie_with_array_occ : - Elt.Set.t Int.Map.t Trie.t -> Elt.t array Int.Map.t Trie.t - -val trie_with_set_occ : - Elt.t array Int.Map.t Trie.t -> Elt.Set.t Int.Map.t Trie.t - -type 'a t = 'a Types.t = - { db_types : 'a Int.Map.t Trie.t - ; db_names : 'a Trie.t + { db_types : Suffix_tree.With_occ.reader + ; db_names : Suffix_tree.With_elts.reader } + val list_of_string : string -> char list module type S = sig diff --git a/db/dune b/db/dune index bd45cbf0be..c9141627bf 100644 --- a/db/dune +++ b/db/dune @@ -1,3 +1,5 @@ (library + (flags + (:standard -open Common)) (name db) - (libraries unix tyxml common)) + (libraries unix tyxml common pprint)) diff --git a/db/elt.ml b/db/elt.ml index c5771598a4..343abdd1be 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -1,5 +1,3 @@ -open Common - type type_path = string list list (** A type can viewed as a tree. @@ -135,6 +133,24 @@ let ( >= ) e e' = compare e e' >= 0 module Set = Set.Make (T) +let pprint { name; _ } = + let open PPrint in + !^name + +(** Array of elts. For use in functors that require a type [t] and not ['a t].*) +module Array = struct + type elt = t + type nonrec t = t array + + let is_empty = Array.equal equal [||] + let of_list = Array.of_list + let pprint_elt = pprint + + let pprint arr = + let open PPrint in + braces @@ flow (break 1) (arr |> Array.map pprint |> Array.to_list) +end + let pkg_link { pkg; _ } = let open Option.O in let+ { name; version } = pkg in diff --git a/db/occ.ml b/db/occ.ml new file mode 100644 index 0000000000..5cfe859008 --- /dev/null +++ b/db/occ.ml @@ -0,0 +1,26 @@ +type t = Elt.Array.t Int.Map.t +type elt = int * Elt.t + +let is_empty = Int.Map.is_empty + +let of_list li = + List.fold_left + (fun acc (count, elt) -> + match Int.Map.find_opt count acc with + | None -> Int.Map.add count (Elt.Set.singleton elt) acc + | Some set -> Int.Map.add count (Elt.Set.add elt set) acc) + Int.Map.empty li + |> Int.Map.map (fun set -> set |> Elt.Set.to_seq |> Array.of_seq) + +let pprint_elt (count, elt) = + let open PPrint in + OCaml.int count ^^ space ^^ Elt.pprint elt + +let pprint t = + let open PPrint in + Int.Map.fold + (fun i arr doc -> + group + @@ group (parens (OCaml.int i ^^ space ^^ align (Elt.Array.pprint arr))) + ^^ break 1 ^^ doc) + t empty diff --git a/db/storage.ml b/db/storage.ml index 0bc896f65b..6c458cdf27 100644 --- a/db/storage.ml +++ b/db/storage.ml @@ -1,10 +1,10 @@ -type 'a db = 'a Types.t +type db = Types.t module type S = sig type writer val open_out : string -> writer - val save : db:writer -> Elt.t array db -> unit + val save : db:writer -> db -> unit val close_out : writer -> unit - val load : string -> Elt.t array db list + val load : string -> db list end diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index 9fc1224bef..a6fe607de3 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -4,6 +4,8 @@ module type SET = sig val of_list : elt list -> t val is_empty : t -> bool + val pprint : t -> PPrint.document + val pprint_elt : elt -> PPrint.document end module Doc = struct @@ -25,31 +27,28 @@ module Doc = struct end module Buf = struct - module Cache = Hashtbl.Make (struct - include String - - let hash = Hashtbl.hash - end) + (** This module allows to construct a big string such that if you add the same + string twice, the second addition is not performed. *) type t = { buffer : Buffer.t - ; cache : int Cache.t + ; cache : int String.Hashtbl.t } - let make () = { buffer = Buffer.create 16; cache = Cache.create 16 } + let make () = { buffer = Buffer.create 16; cache = String.Hashtbl.create 16 } let contents t = Buffer.contents t.buffer let get t i = Buffer.nth t.buffer i let add { buffer; cache } substr = - match Cache.find cache substr with - | start -> start - | exception Not_found -> + match String.Hashtbl.find_opt cache substr with + | Some start -> start + | None -> let start = Buffer.length buffer in Buffer.add_string buffer substr ; let stop = Buffer.length buffer in assert (stop - start = String.length substr) ; for idx = 1 to String.length substr - 1 do - Cache.add cache + String.Hashtbl.add cache (String.sub substr idx (String.length substr - idx)) (start + idx) done ; @@ -57,6 +56,8 @@ module Buf = struct end module Make (S : SET) = struct + (** Terminals is the temporary storage for the payload of the leafs. It is + converted into [S.t] after the suffix tree is built. *) module Terminals = struct type t = S.elt list @@ -71,19 +72,24 @@ module Make (S : SET) = struct let hash = Hashtbl.hash let equal = List.equal ( == ) - let mem x = function + let mem (x : S.elt) = function | y :: _ -> x == y | _ -> false - end - module Char_map = Map.Make (Char) + module Hashtbl = Hashtbl.Make (struct + type nonrec t = t + + let hash = hash + let equal = equal + end) + end type node = { mutable start : int ; mutable len : int ; mutable suffix_link : node option ; mutable terminals : Terminals.t - ; mutable children : node Char_map.t + ; mutable children : node Char.Map.t } type writer = @@ -96,7 +102,7 @@ module Make (S : SET) = struct ; len = 0 ; suffix_link = None ; terminals = Terminals.empty - ; children = Char_map.empty + ; children = Char.Map.empty } let make () = { root = make_root (); buffer = Buf.make () } @@ -108,7 +114,7 @@ module Make (S : SET) = struct ; len ; suffix_link = None ; terminals = Terminals.empty - ; children = Char_map.singleton split_chr node + ; children = Char.Map.singleton split_chr node } in node.start <- node.start + len + 1 ; @@ -144,7 +150,7 @@ module Make (S : SET) = struct ; len ; suffix_link = None ; terminals = Terminals.singleton doc.Doc.uid - ; children = Char_map.empty + ; children = Char.Map.empty } let set_suffix_link ~prev ~depth node = @@ -204,7 +210,7 @@ module Make (S : SET) = struct follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i end | Char chr -> begin - match Char_map.find chr node.children with + match Char.Map.find chr node.children with | child -> assert (depth >= 0) ; assert (i - depth >= 0) ; @@ -216,12 +222,12 @@ module Make (S : SET) = struct assert (i < Doc.length doc) ; if len = child.len then - if not (Char_map.is_empty child.children) + if not (Char.Map.is_empty child.children) then go ~prev ~prev_leaf ~depth child i else add_leaf ~prev_leaf ~node ~child ~depth ~i ~len else begin let new_child = split_at ~str:trie.buffer child len in - node.children <- Char_map.add chr new_child node.children ; + node.children <- Char.Map.add chr new_child node.children ; let prev = set_suffix_link ~prev ~depth new_child in assert (prev = None) ; add_leaf ~prev_leaf ~node ~child:new_child ~depth ~i ~len @@ -230,7 +236,7 @@ module Make (S : SET) = struct let new_leaf = make_leaf ~prev_leaf ~buffer:trie.buffer ~doc i in - node.children <- Char_map.add chr new_leaf node.children ; + node.children <- Char.Map.add chr new_leaf node.children ; let prev_leaf = set_leaf ~debug:"1" ~prev_leaf ~depth:(depth + Doc.length doc - i) @@ -285,7 +291,7 @@ module Make (S : SET) = struct | None -> None | Some (t, depth) -> Some (t, depth, Terminals.empty) in - child.children <- Char_map.add new_chr new_leaf child.children ; + child.children <- Char.Map.add new_chr new_leaf child.children ; let prev = Some (child, depth - 1) in let i, depth = i - len, depth - len in follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i @@ -305,6 +311,10 @@ module Make (S : SET) = struct let add_suffixes t text elt = add_document t { Doc.text; uid = elt } module Automata = struct + (** Automata is the most compact version that uses arrays for branching. It + is not practical to use it for constructing a suffix tree, but it is + better for serialiazing. *) + module Uid = struct let gen = ref 0 @@ -314,8 +324,6 @@ module Make (S : SET) = struct u end - module Hterm = Hashtbl.Make (Terminals) - module T = struct type node = { start : int @@ -371,6 +379,8 @@ module Make (S : SET) = struct let child = find ~str:t.str t.t pattern 0 in { str = t.str; t = child } + let find t pattern = try Some (find t pattern) with Not_found -> None + let rec collapse acc t = let acc = if S.is_empty t.terminals then acc else t.terminals :: acc in Array.fold_left collapse acc t.children @@ -379,10 +389,10 @@ module Make (S : SET) = struct end let export_terminals ~cache_term ts = - try Hterm.find cache_term ts + try Terminals.Hashtbl.find cache_term ts with Not_found -> let result = Uid.make (), S.of_list ts in - Hterm.add cache_term ts result ; + Terminals.Hashtbl.add cache_term ts result ; result let rec export ~cache ~cache_term node = @@ -390,8 +400,8 @@ module Make (S : SET) = struct export_terminals ~cache_term node.terminals in let children = - Char_map.bindings - @@ Char_map.map (export ~cache ~cache_term) node.children + Char.Map.bindings + @@ Char.Map.map (export ~cache ~cache_term) node.children in let children_uids = List.map (fun (chr, (uid, _)) -> chr, uid) children in let key = node.start, node.len, terminals_uid, children_uids in @@ -409,13 +419,28 @@ module Make (S : SET) = struct let clear ~str t = let cache = Hashtbl.create 16 in - let cache_term = Hterm.create 16 in + let cache_term = Terminals.Hashtbl.create 16 in let _, t = export ~cache ~cache_term t in { T.str; t } + + let pprint T.{ t; str } = + let open PPrint in + let rec node T.{ start; len; terminals; children } = + OCaml.string (String.sub str (start -1) (len )) ^^ space + ^^ align (S.pprint terminals) ^^ break 1 + ^^ nest 4 + (group + (Array.fold_left + (fun doc n -> doc ^^ break 1 ^^ group (node n)) + (empty) children)) + in + node t end type reader = Automata.T.t + let pprint = Automata.pprint + let export t = let str = Buf.contents t.buffer in Automata.clear ~str t.root @@ -423,3 +448,6 @@ module Make (S : SET) = struct let find = Automata.T.find let to_sets = Automata.T.collapse end + +module With_elts = Make (Elt.Array) +module With_occ = Make (Occ) diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index 65b90130d5..f112f24c47 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -4,17 +4,26 @@ module type SET = sig val of_list : elt list -> t val is_empty : t -> bool + val pprint : t -> PPrint.document + val pprint_elt : elt -> PPrint.document end module Make (S : SET) : sig type writer + (** A writer is an incomplete suffix tree. + You can add suffixes to it. *) val make : unit -> writer val add_suffixes : writer -> string -> S.elt -> unit type reader + (** A reader is a completed suffix tree. You can make queries on it.*) val export : writer -> reader - val find : reader -> string -> reader + val find : reader -> string -> reader option val to_sets : reader -> S.t list + val pprint : reader -> PPrint.document end + +module With_elts : module type of Make (Elt.Array) +module With_occ : module type of Make (Occ) diff --git a/db/trie.ml b/db/trie.ml deleted file mode 100644 index c9bf44f38a..0000000000 --- a/db/trie.ml +++ /dev/null @@ -1,99 +0,0 @@ -open Common -module M = Char.Map - -type 'a t = - | Leaf of char list * 'a - | Node of - { leaf : 'a option - ; children : 'a t M.t - } - -let empty = Node { leaf = None; children = M.empty } - -let rec add path leaf t = - match t, path with - | Node t, [] -> Node { t with leaf = Some (leaf t.leaf) } - | Node t, p :: path -> - let child = - match M.find p t.children with - | child -> add path leaf child - | exception Not_found -> Leaf (path, leaf None) - in - Node { t with children = M.add p child t.children } - | Leaf (x :: xs, outcome), y :: ys when x = y -> - if xs = ys - then Leaf (path, leaf (Some outcome)) - else - Node - { leaf = None - ; children = M.singleton x (add ys leaf (Leaf (xs, outcome))) - } - | Leaf (x :: xs, outcome), y :: ys -> - assert (x <> y) ; - let children = - M.add y (Leaf (ys, leaf None)) @@ M.singleton x (Leaf (xs, outcome)) - in - Node { leaf = None; children } - | Leaf ([], outcome), [] -> Leaf ([], leaf (Some outcome)) - | Leaf ([], outcome), y :: ys -> - Node - { leaf = Some outcome; children = M.singleton y (Leaf (ys, leaf None)) } - | Leaf (y :: ys, outcome), [] -> - Node - { leaf = Some (leaf None) - ; children = M.singleton y (Leaf (ys, outcome)) - } - - -let find path t = -let rec loop i path t = - match t, path with - | _, [] -> - Ok t - | Node node, p :: path -> begin - match M.find p node.children with - | child -> loop (i + 1) path child - | exception Not_found -> Error (`Stopped_at (i, t)) - end - | Leaf (x :: xs, outcome), y :: ys when x = y -> loop (i + 1) ys (Leaf (xs, outcome)) - | _ -> - Error (`Stopped_at (i, t)) - - in - loop 0 path t - -let rec fold_map merge transform t = - match t with - | Leaf (_, outcome) -> Some (transform outcome) - | Node { leaf; children; _ } -> - let leaf = - match leaf with - | None -> None - | Some leaf -> Some (transform leaf) - in - M.fold - (fun _ child acc -> - let res = fold_map merge transform child in - match acc, res with - | None, opt | opt, None -> opt - | Some acc, Some res -> Some (merge acc res)) - children leaf - -let rec map_leaf ~f t = - match t with - | Leaf (v, outcome) -> Leaf (v, f outcome) - | Node { leaf; children } -> - let leaf = Option.map f leaf in - let children = M.map (map_leaf ~f) children in - Node { leaf; children } - -let rec equal a_eq t1 t2 = - if t1 == t2 - then true - else - match t1, t2 with - | Leaf (chars, elt), Leaf (chars', elt') -> - List.equal Char.equal chars chars' && a_eq elt elt' - | Node { leaf; children }, Node { leaf = leaf'; children = children' } -> - Option.equal a_eq leaf leaf' && M.equal (equal a_eq) children children' - | _ -> false diff --git a/db/trie.mli b/db/trie.mli deleted file mode 100644 index 915a6901d2..0000000000 --- a/db/trie.mli +++ /dev/null @@ -1,15 +0,0 @@ -open Common - -type 'a t = - | Leaf of char list * 'a - | Node of - { leaf : 'a option - ; children : 'a t Char.Map.t - } - -val empty : 'a t -val add : char list -> ('a option -> 'a) -> 'a t -> 'a t -val find : char list -> 'a t -> ('a t, [> `Stopped_at of int * 'a t ]) result -val fold_map : ('a -> 'a -> 'a) -> ('b -> 'a) -> 'b t -> 'a option -val map_leaf : f:('a -> 'b) -> 'a t -> 'b t -val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool diff --git a/db/types.ml b/db/types.ml index 21b54422f2..3e6407d56f 100644 --- a/db/types.ml +++ b/db/types.ml @@ -1,4 +1,3 @@ -open Common let regroup lst = String_list_map.bindings @@ -31,7 +30,7 @@ let sgn_not = function | Neg -> Pos | Unknown -> Unknown -type 'a t = - { db_types : 'a Int.Map.t Trie.t - ; db_names : 'a Trie.t +type t = + { db_types : Suffix_tree.With_occ.reader + ; db_names : Suffix_tree.With_elts.reader } diff --git a/index/index_lib.ml b/index/index_lib.ml index 10efd2d87a..47794bc92c 100644 --- a/index/index_lib.ml +++ b/index/index_lib.ml @@ -1,13 +1,12 @@ module Storage = Db.Storage let main ~index_docstring ~index_name ~type_search ~index ~db_filename storage = - print_endline "Index_lib.main" ; let module Storage = (val storage : Storage.S) in let module Load_doc = Load_doc.Make (Storage) in let module Db = Load_doc.Db in let h = Storage.open_out db_filename in let flush () = - Load_doc.clear () ; + (* Load_doc.clear () ; *) Db.export h in let t0 = Unix.gettimeofday () in diff --git a/index/load_doc.ml b/index/load_doc.ml index c6db634742..2cf1363133 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -1,13 +1,11 @@ module Elt = Db.Elt module Db_common = Db -module Cache = Db.Cache module Make (Storage : Db.Storage.S) = struct module Types = Db.Types module Db = Db.Make (Storage) module ModuleName = Odoc_model.Names.ModuleName - let clear () = Cache.clear () let generic_cost ~ignore_no_doc name has_doc = String.length name @@ -197,7 +195,7 @@ module Make (Storage : Db.Storage.S) = struct Elt.Kind.extension_constructor paths | ModuleType -> ModuleType - let convert_kind k = k |> convert_kind |> Cache.Kind_.memo + let convert_kind k = k |> convert_kind (*|> Cache.Kind_.memo*) let register_type_expr elt type_ = let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in diff --git a/index/load_doc.mli b/index/load_doc.mli index 9e2abf8e40..41da2655f2 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -1,7 +1,6 @@ module Make (Storage : Db.Storage.S) : sig module Db : Db.S with type writer = Storage.writer - val clear : unit -> unit val run : index_docstring:bool diff --git a/query/dune b/query/dune index 0b3ee71d72..f7da7bb929 100644 --- a/query/dune +++ b/query/dune @@ -1,4 +1,6 @@ (library +(flags + (:standard -open Common)) (name query) (libraries lwt re db)) diff --git a/query/query.ml b/query/query.ml index dade9c8b9a..91333c09ac 100644 --- a/query/query.ml +++ b/query/query.ml @@ -1,9 +1,9 @@ -open Common module Parser = Query_parser module Succ = Succ module Sort = Sort module Storage = Db.Storage -module Trie = Db.Trie +module Tree = Db.Suffix_tree.With_elts +module Tree_occ = Db.Suffix_tree.With_occ open Db.Types module Occ = Int.Map @@ -15,60 +15,63 @@ let collapse_occ ~count occs = occs Succ.empty let collapse_trie_occ ~count t = - match Trie.fold_map Succ.union (collapse_occ ~count) t with - | None -> Succ.empty - | Some occ -> occ + t |> Tree_occ.to_sets + |> List.fold_left + (fun succ occ -> Succ.union succ (collapse_occ ~count occ)) + Succ.empty let collapse_trie t = - match Trie.fold_map Succ.union Succ.of_array t with - | None -> Succ.empty - | Some s -> s + t |> Tree.to_sets + |> List.fold_left + (fun succ arr -> Succ.union succ (Succ.of_array arr)) + Succ.empty -let rec collapse_trie_occ_polar ~parent_char ~polarity ~count t = - let open Trie in - match t with - | Leaf (_, leaf) -> - if parent_char = polarity then collapse_occ ~count leaf else Succ.empty - | Node { leaf = _; children; _ } -> - Char.Map.fold - (fun parent_char child acc -> - let res = - collapse_trie_occ_polar ~parent_char ~polarity ~count child - in - Succ.union acc res) - children Succ.empty +(*let rec collapse_trie_occ_polar ~parent_char ~polarity ~count t = + let open Tree in + match t with + | Leaf (_, leaf) -> + if parent_char = polarity then collapse_occ ~count leaf else Succ.empty + | Node { leaf = _; children; _ } -> + Char.Map.fold + (fun parent_char child acc -> + let res = + collapse_trie_occ_polar ~parent_char ~polarity ~count child + in + Succ.union acc res) + children Succ.empty -let collapse_trie_occ_polar ~polarity ~count t = - let open Trie in - match t with - | Leaf _ -> Succ.empty - | Node { leaf = _; children; _ } -> - Char.Map.fold - (fun parent_char child acc -> - let res = - collapse_trie_occ_polar ~parent_char ~polarity ~count child - in - Succ.union acc res) - children Succ.empty -let collapse_trie_with_poly ~count name t = - match name with - | [ "POLY"; ("+" | "-") ] -> begin - match t with - | Trie.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s - | _ -> Succ.empty - end - | _ -> collapse_trie_occ ~count t + let collapse_trie_occ_polar ~polarity ~count t = + let open Tree in + match t with + | Leaf _ -> Succ.empty + | Node { leaf = _; children; _ } -> + Char.Map.fold + (fun parent_char child acc -> + let res = + collapse_trie_occ_polar ~parent_char ~polarity ~count child + in + Succ.union acc res) + children Succ.empty -let _collapse_trie_with_poly_polar ~polarity ~count name t = - match name with - | [ "POLY"; ("+" | "-") ] -> begin - match t with - | Trie.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s - | _ -> Succ.empty - end - | _ -> collapse_trie_occ_polar ~polarity ~count t + let collapse_trie_with_poly ~count name t = + match name with + | [ "POLY"; ("+" | "-") ] -> begin + match t with + | Tree.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s + | _ -> Succ.empty + end + | _ -> collapse_trie_occ ~count t + let _collapse_trie_with_poly_polar ~polarity ~count name t = + match name with + | [ "POLY"; ("+" | "-") ] -> begin + match t with + | Tree.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s + | _ -> Succ.empty + end + | _ -> collapse_trie_occ_polar ~polarity ~count t +*) let find_types ~shards names = List.fold_left (fun acc shard -> @@ -77,9 +80,11 @@ let find_types ~shards names = inter_list @@ List.map (fun (name, count) -> - let name' = List.concat_map Db.list_of_string name in - match Trie.find name' db with - | Ok trie -> collapse_trie_with_poly ~count name trie + let name' = String.concat "" name in + match Tree_occ.find db name' with + | Some trie -> collapse_trie_occ ~count trie + | None -> Succ.empty + (* | Error (`Stopped_at (i, sub_trie)) -> let name_str = name' |> List.to_seq |> String.of_seq in if i = String.length name_str - 1 @@ -89,27 +94,23 @@ let find_types ~shards names = | '-' | '+' -> collapse_trie_occ_polar ~polarity ~count sub_trie | _ -> Succ.empty - else Succ.empty) + else Succ.empty*)) (regroup names) in Succ.union acc r) Succ.empty shards -let find_names ~(shards : Db.Elt.t array Db.t list) names = - let names = - List.map - (fun n -> List.rev (Db.list_of_string (String.lowercase_ascii n))) - names - in +let find_names ~(shards : Db.t list) names = + let names = List.map (fun n -> (*String.rev *)(String.lowercase_ascii n)) names in List.fold_left (fun acc shard -> let db_names = shard.db_names in let candidates = List.map (fun name -> - match Trie.find name db_names with - | Ok trie -> collapse_trie trie - | Error _ -> Succ.empty) + match Tree.find db_names name with + | Some trie -> collapse_trie trie + | None -> Succ.empty) names in let candidates = inter_list candidates in @@ -122,7 +123,7 @@ type t = ; limit : int } -let search ~(shards : Db.Elt.t array Db.t list) query_name query_typ = +let search ~(shards : Db.t list) query_name query_typ = let results_name = find_names ~shards query_name in let results = match query_typ with @@ -143,7 +144,7 @@ let match_packages ~packages results = | [] -> results | _ -> Seq.filter (match_packages ~packages) results -let api ~(shards : Db.Elt.t array Db.t list) params = +let api ~(shards : Db.t list) params = let query_name, query_typ, query_typ_arrow, pretty = Parser.of_string params.query in diff --git a/query/query.mli b/query/query.mli index bf553e4b68..47beb2f342 100644 --- a/query/query.mli +++ b/query/query.mli @@ -8,4 +8,4 @@ type t = ; limit : int } -val api : shards:Db.Elt.t array Db.t list -> t -> string * Db.Elt.t list +val api : shards: Db.t list -> t -> string * Db.Elt.t list diff --git a/query/sort.ml b/query/sort.ml index dbbc16e94f..555f7ada01 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -1,4 +1,4 @@ -open Common + module Elt = Db.Elt module Type_distance = struct diff --git a/query/succ.ml b/query/succ.ml index 09b8dcaf20..bfd1a2a386 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,5 +1,5 @@ open Db -open Common + type s = | All diff --git a/store/storage_ancient.ml b/store/storage_ancient.ml index efccde6e4d..a23498df53 100644 --- a/store/storage_ancient.ml +++ b/store/storage_ancient.ml @@ -1,4 +1,3 @@ -open Db let base_addr = 0x100000000000n @@ -12,13 +11,13 @@ let open_out filename = let ancient = Ancient.attach handle base_addr in { write_shard = 0; ancient } -let save ~db (t : Elt.t array Db.t) = +let save ~db (t : Db.t) = ignore (Ancient.share db.ancient db.write_shard t) ; db.write_shard <- db.write_shard + 1 let close_out db = Ancient.detach db.ancient -type reader = { shards : Elt.t array Db.t array } +type reader = { shards : Db.t array } let load_shard md shard = match Ancient.get md shard with diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index bd4c15a74d..a3f1ffc2b2 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,12 +7,382 @@ $ du -sh megaodocl 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Index_lib.main - Indexing in 0.002140s - trie_with_array_occ:0.00s - trie_with_array:0.00s - Cache.Elt_array_occ_trie.memo:0.00s - Cache.Elt_array_trie.memo:0.00s + Indexing in 0.000959s + "" {page page page page page page Main Main.foo Main.unique_name Main.multiple_hit_1 + Main.multiple_hit_2 Main.multiple_hit_3 Main.name_conflict Main.name_conflict Main.Nest + Main.Nest.nesting_priority Main.nesting_priority Main.Map Main.Map.to_list Main.list Main.List + Main.List.t Main.List.map Main.foo Main.moo Main.t Main.value Main.consume Main.consume_2 + Main.consume_2_other Main.produce Main.produce_2' Main.Modtype Main.Modtype.v_modtype Main.S + Main.S_to_S1 Main.poly_1 Main.poly_2 Main.boo Main.poly_param Main.extensible_type + Main.MyExtension} + + "" {Main.produce_2'} + "" {} + + "oo" {Main.boo} + "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "xtensible_type" {Main.extensible_type} + "oo" {Main.foo Main.foo} + "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} + "" {} + + "p" {Main.Map Main.List.map} "to_list" {Main.Map.to_list} + "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} + "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "extension" {Main.MyExtension} + "" {} + + "me_conflict" {Main.name_conflict Main.name_conflict} + "st" {Main.Nest} + + "nesting_priority" {Main.Nest.nesting_priority} + "ng_priority" {Main.Nest.nesting_priority Main.nesting_priority} + "" {} + + "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} + "oduce" {Main.produce} "2'" {Main.produce_2'} + "" {Main.S} "to_s1" {Main.S_to_S1} + "" {Main.List.t Main.t} "_list" {Main.Map.to_list} + "nique_name" {Main.unique_name} + "" {} "modtype" {Main.Modtype.v_modtype} "lue" {Main.value} + "" {Main.multiple_hit_1 Main.S_to_S1 Main.poly_1} + "" {Main.multiple_hit_2 Main.consume_2 Main.poly_2} + "" {Main.produce_2'} "other" {Main.consume_2_other} + "" {Main.multiple_hit_3} + "" {} + + "" {Main.multiple_hit_1 Main.poly_1} + "" {Main.multiple_hit_2 Main.consume_2 Main.poly_2} + "" {Main.produce_2'} "other" {Main.consume_2_other} + "" {Main.multiple_hit_3} + "onflict" {Main.name_conflict Main.name_conflict} + "it_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "ist" {Main.Map.to_list} + "odtype" {Main.Modtype.v_modtype} + "ame" {Main.unique_name} + "ther" {Main.consume_2_other} + "" {} "ram" {Main.poly_param} "iority" {Main.Nest.nesting_priority Main.nesting_priority} + "1" {Main.S_to_S1} + "" {} "_s1" {Main.S_to_S1} "pe" {Main.extensible_type} + "" {page page page Main.foo} + + "raph" {page} + "n" {Main} + + "" {} + + "oo" {Main.boo} + "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "xtensible_type" {Main.extensible_type} + "oo" {Main.foo Main.foo} + "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} + "" {} + + "p" {Main.Map} "to_list" {Main.Map.to_list} + "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} + "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "extension" {Main.MyExtension} + "" {} + + "me_conflict" {Main.name_conflict Main.name_conflict} + "st" {Main.Nest} + "nesting_priority" {Main.Nest.nesting_priority} "ng_priority" {Main.nesting_priority} + "" {} + + "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} + "oduce" {Main.produce} "2'" {Main.produce_2'} + "" {Main.S} "to_s1" {Main.S_to_S1} + "" {Main.t} + "nique_name" {Main.unique_name} + "alue" {Main.value} + "ue" {Main.value} + "" {Main.poly_param} "" {Main.unique_name} "conflict" {Main.name_conflict Main.name_conflict} + "d" {page} + "" {Main.Map Main.List.map Main.foo} "to_list" {Main.Map.to_list} "" {page} + "a" {} "raph" {page} "" {Main.poly_param} + "im" {page} + "" {page} + "tim" {page} "" {} "_type" {Main.extensible_type} "b" {page} "ib" {page} "o" {Main.boo} + "" {} + + "" {Main.produce} "2'" {Main.produce_2'} + "" {} + + "e" {page} + "" {} + + "lict" {Main.name_conflict Main.name_conflict} + "ume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "" {Main.name_conflict Main.name_conflict} + "" {page} + + "" {page} + "ype" {Main.Modtype Main.Modtype.v_modtype} "v_modtype" {Main.Modtype.v_modtype} + "ce" {Main.produce} "2'" {Main.produce_2'} + "" {page page page Main.unique_name Main.value Main.consume Main.produce Main.Modtype + Main.Modtype.v_modtype Main.extensible_type} + + "v_modtype" {Main.Modtype.v_modtype} + "" {} + + "" {Main.consume_2} "" {Main.produce_2'} "other" {Main.consume_2_other} + "onflict" {Main.name_conflict Main.name_conflict} + "it_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "ame" {Main.unique_name} + "ype" {Main.extensible_type} + "si" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} + "" {Main.consume_2_other} "atim" {page} + "t" {Main.Nest} + + "nesting_priority" {Main.Nest.nesting_priority} + "ng_priority" {Main.Nest.nesting_priority Main.nesting_priority} + "tensi" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} + "" {page} "ict" {Main.name_conflict Main.name_conflict} "o" {Main.foo Main.foo} + "" {} "priority" {Main.Nest.nesting_priority Main.nesting_priority} "aph" {page} "" {page} + "" {page} + + "r" {Main.consume_2_other} + "" {} + + "gs" {page} + "" {Main.foo} + "_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "" {} + + "" {page} "" {} "_type" {Main.extensible_type} "b" {page} + "t" {Main.name_conflict Main.name_conflict} + "" {page} + "" {Main} + + "" {} + + "oo" {Main.boo} + "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "xtensible_type" {Main.extensible_type} + "oo" {Main.foo Main.foo} + "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} + "" {} + + "p" {Main.Map} "to_list" {Main.Map.to_list} + "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} + "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "extension" {Main.MyExtension} + "" {} + + "me_conflict" {Main.name_conflict Main.name_conflict} + "st" {Main.Nest} + "nesting_priority" {Main.Nest.nesting_priority} "ng_priority" {Main.nesting_priority} + "" {} + + "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} + "oduce" {Main.produce} "2'" {Main.produce_2'} + "" {Main.S} "to_s1" {Main.S_to_S1} + "" {Main.t} + "nique_name" {Main.unique_name} + "alue" {Main.value} + "" {} "priority" {Main.Nest.nesting_priority Main.nesting_priority} "" {page} + "" {} "" {Main.MyExtension} "ity" {Main.Nest.nesting_priority Main.nesting_priority} + "le_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "ue_name" {Main.unique_name} + "" {Main.foo} + + "" {page Main.Map.to_list Main.list Main.List Main.foo} + "" {} "ap" {Main.List.map} "" {Main.List.t} + "" {} + + "" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "e" {page} + "" {Main.Nest.nesting_priority Main.nesting_priority} + "" {} + + "" {page} + + "" {} + + "it_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "ype" {Main.extensible_type} + "" {} + + "" {page} "ib" {page} + "t" {Main.name_conflict Main.name_conflict} + "t" {page Main.Map.to_list Main.list Main.List Main.foo} + "" {} "ap" {Main.List.map} "" {Main.List.t} + "iple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "e" {Main.value} + "_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} + "" {page Main.poly_param} + + "" {} + + "n" {Main} + + "" {} + + "oo" {Main.boo} + "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "xtensible_type" {Main.extensible_type} + "oo" {Main.foo Main.foo} + "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} + "" {} + + "p" {Main.Map} "to_list" {Main.Map.to_list} + "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} + "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "extension" {Main.MyExtension} + "" {} + + "me_conflict" {Main.name_conflict Main.name_conflict} + "st" {Main.Nest} + "nesting_priority" {Main.Nest.nesting_priority} "ng_priority" {Main.nesting_priority} + "" {} + + "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} + "oduce" {Main.produce} "2'" {Main.produce_2'} + "" {Main.S} "to_s1" {Main.S_to_S1} + "" {Main.t} + "nique_name" {Main.unique_name} + "alue" {Main.value} + "" {Main.Map Main.List.map Main.foo} "to_list" {Main.Map.to_list} + "" {page Main.unique_name Main.consume} + + "" {} + + "" {Main.consume_2} "other" {Main.consume_2_other} + "onflict" {Main.name_conflict Main.name_conflict} + "" {} + + "type" {Main.Modtype Main.Modtype.v_modtype} "v_modtype" {Main.Modtype.v_modtype} + "" {Main.moo} + "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "extension" {Main.MyExtension} + "" {Main Main.MyExtension} + + "" {} + + "oo" {Main.boo} + "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "xtensible_type" {Main.extensible_type} + "oo" {Main.foo Main.foo} + "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} + "" {} + + "p" {Main.Map} "to_list" {Main.Map.to_list} + "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} + "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "extension" {Main.MyExtension} + "" {} + + "me_conflict" {Main.name_conflict Main.name_conflict} + "st" {Main.Nest} + "nesting_priority" {Main.Nest.nesting_priority} "ng_priority" {Main.nesting_priority} + "" {} + + "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} + "oduce" {Main.produce} "2'" {Main.produce_2'} + "" {Main.S} "to_s1" {Main.S_to_S1} + "" {Main.t} + "nique_name" {Main.unique_name} + "alue" {Main.value} + "me" {Main.unique_name} "conflict" {Main.name_conflict Main.name_conflict} + "" {page} + "st" {Main.Nest} + + "nesting_priority" {Main.Nest.nesting_priority} + "ng_priority" {Main.Nest.nesting_priority Main.nesting_priority} + "lict" {Main.name_conflict Main.name_conflict} + "" {} "priority" {Main.Nest.nesting_priority Main.nesting_priority} "" {page} + "que_name" {Main.unique_name} + "" {} "" {Main.foo} "" {Main.foo} + "" {} + + "" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} + "me" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "" {Main.foo Main.foo Main.moo Main.boo} + + "" {} "ist" {Main.Map.to_list} "1" {Main.S_to_S1} + "" {} + + "" {page} + "ype" {Main.Modtype Main.Modtype.v_modtype} "v_modtype" {Main.Modtype.v_modtype} + "ce" {Main.produce} "2'" {Main.produce_2'} + "" {page} + "y_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} + "e" {page} + "" {Main.MyExtension} + + "lict" {Main.name_conflict Main.name_conflict} + "ume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "" {Main.foo Main.foo Main.moo Main.boo} + "" {Main.foo} "ty" {Main.Nest.nesting_priority Main.nesting_priority} + "" {Main.foo} "er" {Main.consume_2_other} + "" {Main.Map Main.List.map Main.foo} + + "to_list" {Main.Map.to_list} + "ra" {} "raph" {page} "" {Main.poly_param} + "" {Main.Modtype Main.Modtype.v_modtype Main.extensible_type} + "v_modtype" {Main.Modtype.v_modtype} + "" {page} + "e_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} + "" {} + + "ority" {Main.Nest.nesting_priority Main.nesting_priority} + "duce" {Main.produce} "2'" {Main.produce_2'} + "ue_name" {Main.unique_name} + "" {Main.foo Main.consume_2_other} + + "" {} "raph" {page} "" {Main.poly_param} "h" {page} + "atim" {page} + "" {} + + "rity" {Main.Nest.nesting_priority Main.nesting_priority} + "y" {Main.Nest.nesting_priority Main.nesting_priority} + "duce" {Main.produce} "2'" {Main.produce_2'} + "" {page Main.foo Main.S} + + "" {Main.S_to_S1} + "to_s1" {Main.S_to_S1} + "" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} + "me" {page} + "" {page Main.Nest Main.Map.to_list Main.list Main.List Main.foo} + + "" {} "ap" {Main.List.map} "esting_priority" {Main.Nest.nesting_priority} "" {Main.List.t} + "ng_priority" {Main.Nest.nesting_priority Main.nesting_priority} + "me" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "" {page Main.name_conflict Main.name_conflict Main.Nest Main.Map.to_list Main.list Main.List + Main.List.t Main.foo Main.t} + + "" {} "ap" {Main.List.map} "esting_priority" {Main.Nest.nesting_priority} "" {Main.List.t} + "" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "nsi" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} + "" {} "r" {Main.consume_2_other} "" {} "gs" {page} "" {Main.foo} + "" {} + + "" {page} + "g_priority" {Main.Nest.nesting_priority Main.nesting_priority} + "le_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "le" {page} + "e" {page} + "_" {} "ist" {Main.Map.to_list} "1" {Main.S_to_S1} + "" {Main.Nest.nesting_priority Main.nesting_priority} + + "e" {Main.Modtype Main.Modtype.v_modtype Main.extensible_type} + "v_modtype" {Main.Modtype.v_modtype} + "" {} + + "e" {Main.produce} "2'" {Main.produce_2'} + "" {Main.value} "name" {Main.unique_name} + "tiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} + "e" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} + "ique_name" {Main.unique_name} + "" {} "modtype" {Main.Modtype.v_modtype} "lue" {Main.value} "rbatim" {page} + "tensi" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} + "" {Main.Nest.nesting_priority Main.nesting_priority} + + "" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} + "xtension" {Main.MyExtension} + "e" {Main.Modtype Main.Modtype.v_modtype Main.extensible_type} + "v_modtype" {Main.Modtype.v_modtype} $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" val Main.unique_name : foo @@ -24,20 +394,15 @@ type Main.name_conflict = foo val Main.name_conflict : foo $ sherlodoc "nesting_priority" - val Main.nesting_priority : foo - val Main.Nest.nesting_priority : foo + [No results] $ sherlodoc --print-cost "list" - 109 mod Main.List - 209 type Main.list 315 type Main.List.t = 'a list 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 319 val Main.Map.to_list : foo - 1108 val Main.foo : foo - 1154 doc page + $ sherlodoc --print-cost "map" + 108 mod Main.Map + 320 val Main.Map.to_list : foo $ sherlodoc --print-cost "list map" - 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 423 val Main.Map.to_list : foo - 2108 val Main.foo : foo + [No results] $ sherlodoc --print-cost ":moo" 210 val Main.value : moo 213 val Main.produce : unit -> moo @@ -51,22 +416,15 @@ 112 sig Main.Modtype 325 val Main.Modtype.v_modtype : foo $ sherlodoc --print-cost "S" - 106 sig Main.S - 216 mod Main.List - 216 mod Main.Nest 216 mod Main.S_to_S1 - 316 type Main.list 318 type Main.List.t = 'a list 319 val Main.consume : moo -> unit 320 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t 321 val Main.consume_2 : moo -> moo -> unit - 323 val Main.Map.to_list : foo 327 val Main.consume_2_other : moo -> t -> unit 327 type Main.extensible_type = .. - 328 val Main.nesting_priority : foo 333 val Main.Nest.nesting_priority : foo 373 cons Main.MyExtension : moo -> extensible_type - 1108 val Main.foo : foo 1154 doc page $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" [No results] @@ -74,12 +432,11 @@ TODO : get a result for the query bellow $ sherlodoc --print-cost "hidden" [No results] $ sherlodoc --print-cost ":mo" - 217 val Main.value : moo - 220 val Main.produce : unit -> moo - 224 val Main.produce_2' : unit -> unit -> moo + [No results] $ sherlodoc ":'a" val Main.poly_1 : 'a -> 'b -> 'c val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c + val Main.poly_param : 'a boo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t $ sherlodoc ": 'a -> 'b -> 'c " val Main.poly_1 : 'a -> 'b -> 'c diff --git a/test/cram/cli_small.t/main.mli b/test/cram/cli_small.t/main.mli new file mode 100644 index 0000000000..a3685d09dc --- /dev/null +++ b/test/cram/cli_small.t/main.mli @@ -0,0 +1,9 @@ + +type 'a list + +module List : sig + type 'a t = 'a list + + val map : ('a -> 'b) -> 'a t -> 'b t +end + diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t new file mode 100644 index 0000000000..911b80e715 --- /dev/null +++ b/test/cram/cli_small.t/run.t @@ -0,0 +1,110 @@ + $ ocamlc -c main.mli -bin-annot -I . + $ odoc compile -I . main.cmti + $ odoc link -I . main.odoc + $ cat $(find . -name '*.odocl') > megaodocl + $ du -sh megaodocl + 4.0K megaodocl + $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') + Indexing in 0.000130s + index: internal error, uncaught exception: + Invalid_argument("String.sub / Bytes.sub") + + [125] + $ export SHERLODOC_DB=db.bin + $ sherlodoc "unique_name" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc "multiple_hit" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc "name_conflict" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc "nesting_priority" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc --print-cost "list" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc --print-cost "map" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc --print-cost "list map" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc --print-cost ":moo" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc --print-cost ":moo -> _" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc --print-cost "modtype" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc --print-cost "S" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] +TODO : get a result for the query bellow + $ sherlodoc --print-cost "hidden" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc --print-cost ":mo" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc ":'a" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc ": 'a -> 'b -> 'c " + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc ": ('a -> 'b) -> 'a t -> 'b t" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] +TODO : get a result for the query bellow + $ sherlodoc ": 'a bo" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] + $ sherlodoc ":extensible_type" + sherlodoc: internal error, uncaught exception: + End_of_file + + [125] diff --git a/www/ui.ml b/www/ui.ml index 7865f6bc8d..8b12b0830b 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -19,22 +19,7 @@ let render_elt elt = | Some rhs -> [ html_txt rhs ] | None -> [] in - let kind = - match elt.kind with - | Val _ -> "val " - | Doc -> "comment " - | TypeDecl -> "type " - | Module -> "module " - | Exception -> "exception " - | Class_type -> "class type" - | Method -> "method " - | Class -> "class " - | TypeExtension -> "type extension " - | ExtensionConstructor -> "ext constructor " - | ModuleType -> "module type " - | Constructor _ -> "constructor " - | Field _ -> "field " - in + let kind = Db.Elt.Kind.to_string elt.kind ^ " " in [ txt kind; a ~a:link [ em [ txt elt.name ] ] ] @ rhs let render_pkg elt = From 66d61079355bb915fdb21eac6ad0cbffe6a5de23 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 21 Jun 2023 18:14:21 +0200 Subject: [PATCH 100/285] Bugfix Still logs too much stuff --- common/int.ml | 1 + db/dune | 2 +- db/elt.ml | 11 ++- db/suffix_tree.ml | 7 +- test/cram/cli_small.t/run.t | 131 +++++++++--------------------------- 5 files changed, 45 insertions(+), 107 deletions(-) diff --git a/common/int.ml b/common/int.ml index c424efd1dc..d9c9e2e401 100644 --- a/common/int.ml +++ b/common/int.ml @@ -3,3 +3,4 @@ module Map = Map.Make (Stdlib.Int) let hash : int -> int = Hashtbl.hash let pp = Format.pp_print_int +let (=) = equal \ No newline at end of file diff --git a/db/dune b/db/dune index c9141627bf..3f54953bc5 100644 --- a/db/dune +++ b/db/dune @@ -2,4 +2,4 @@ (flags (:standard -open Common)) (name db) - (libraries unix tyxml common pprint)) + (libraries unix common pprint)) diff --git a/db/elt.ml b/db/elt.ml index 343abdd1be..1bafd082f5 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -135,15 +135,20 @@ module Set = Set.Make (T) let pprint { name; _ } = let open PPrint in - !^name + !^name (** Array of elts. For use in functors that require a type [t] and not ['a t].*) module Array = struct type elt = t type nonrec t = t array - let is_empty = Array.equal equal [||] - let of_list = Array.of_list + let is_empty arr = Int.(Array.length arr = 0) + + let of_list arr = + let arr = Array.of_list arr in + Array.sort compare arr ; + arr + let pprint_elt = pprint let pprint arr = diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index a6fe607de3..b80aac6a86 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -379,7 +379,9 @@ module Make (S : SET) = struct let child = find ~str:t.str t.t pattern 0 in { str = t.str; t = child } - let find t pattern = try Some (find t pattern) with Not_found -> None + let find t pattern = + print_endline pattern; + try Some (find t pattern) with Not_found -> None let rec collapse acc t = let acc = if S.is_empty t.terminals then acc else t.terminals :: acc in @@ -426,7 +428,8 @@ module Make (S : SET) = struct let pprint T.{ t; str } = let open PPrint in let rec node T.{ start; len; terminals; children } = - OCaml.string (String.sub str (start -1) (len )) ^^ space + let start, len = if start = 0 then start, len else start - 1 , len + 1 in + OCaml.string (String.sub str start (len )) ^^ space ^^ align (S.pprint terminals) ^^ break 1 ^^ nest 4 (group diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 911b80e715..f62250226a 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,106 +5,35 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.000130s - index: internal error, uncaught exception: - Invalid_argument("String.sub / Bytes.sub") - - [125] + Indexing in 0.000103s + "" {Main Main.List Main.list Main.List.t Main.List.map} + + "." {} + + "list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} + "map" {Main.List.map} + "t" {Main.List.t} + "a" {} + + "in" {Main} ".list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} + "p" {Main.List.map} + "i" {} + + "n" {Main} ".list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} + "st" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} + "list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} + "ma" {} + + "in" {Main} ".list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} + "p" {Main.List.map} + "n" {Main} ".list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} + "p" {Main.List.map} + "st" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} + "t" {Main.List Main.list Main.List.t} "." {} "map" {Main.List.map} "t" {Main.List.t} $ export SHERLODOC_DB=db.bin - $ sherlodoc "unique_name" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc "multiple_hit" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc "name_conflict" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc "nesting_priority" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] $ sherlodoc --print-cost "list" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc --print-cost "map" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc --print-cost "list map" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc --print-cost ":moo" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc --print-cost ":moo -> _" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc --print-cost "modtype" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc --print-cost "S" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] -TODO : get a result for the query bellow - $ sherlodoc --print-cost "hidden" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc --print-cost ":mo" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc ":'a" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc ": 'a -> 'b -> 'c " - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc ": ('a -> 'b) -> 'a t -> 'b t" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] -TODO : get a result for the query bellow - $ sherlodoc ": 'a bo" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] - $ sherlodoc ":extensible_type" - sherlodoc: internal error, uncaught exception: - End_of_file - - [125] + list + 109 mod Main.List + 209 type Main.list + 315 type Main.List.t = 'a list + 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t From d6a59121eac4f87b602b7f41993e84ddda26fd9e Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 25 Jun 2023 18:13:59 +0200 Subject: [PATCH 101/285] cleanup --- cli/dune | 2 - cli/main.ml | 9 +- common/array_map.ml | 45 -- common/char.ml | 5 - common/char_list_map.ml | 7 - common/common.ml | 13 - common/common_.ml | 4 - common/dune | 3 - common/int.ml | 6 - common/list.ml | 9 - common/map.ml | 560 ---------------------- common/option.ml | 12 - common/pair.ml | 5 - common/set.ml | 640 ------------------------- common/string.ml | 15 - common/string_list_map.ml | 7 - common/test/dune | 5 - common/test/test.ml | 93 ---- db/cache.ml_ | 331 ------------- db/cache.mli_ | 28 -- db/db.ml | 23 +- db/db.mli | 5 +- db/dune | 4 +- db/elt.ml | 50 +- db/occ.ml | 29 +- db/suffix_tree.ml | 61 +-- db/suffix_tree.mli | 3 - db/types.ml | 13 +- index/index_lib.ml | 2 +- index/load_doc.ml | 109 +++-- jsoo/dune | 2 +- common/array.ml => query/array_succ.ml | 28 +- query/dune | 2 - query/query.ml | 63 +-- query/succ.ml | 5 +- test/cram/base.t/run.t | 18 +- test/cram/cli.t/run.t | 399 +-------------- test/cram/cli_poly.t/run.t | 8 +- test/cram/cli_small.t/run.t | 28 +- test/cram/simple.t/run.t | 20 +- www/dune | 2 +- 41 files changed, 182 insertions(+), 2491 deletions(-) delete mode 100644 common/array_map.ml delete mode 100644 common/char.ml delete mode 100644 common/char_list_map.ml delete mode 100644 common/common.ml delete mode 100644 common/common_.ml delete mode 100644 common/dune delete mode 100644 common/int.ml delete mode 100644 common/list.ml delete mode 100644 common/map.ml delete mode 100644 common/option.ml delete mode 100644 common/pair.ml delete mode 100644 common/set.ml delete mode 100644 common/string.ml delete mode 100644 common/string_list_map.ml delete mode 100644 common/test/dune delete mode 100644 common/test/test.ml delete mode 100644 db/cache.ml_ delete mode 100644 db/cache.mli_ rename common/array.ml => query/array_succ.ml (72%) diff --git a/cli/dune b/cli/dune index 46e7aa7851..729873e534 100644 --- a/cli/dune +++ b/cli/dune @@ -2,7 +2,5 @@ (executable (name main) - (flags - (:standard -open Common)) (public_name sherlodoc) (libraries cmdliner query storage_marshal)) diff --git a/cli/main.ml b/cli/main.ml index 4279cb3da4..ddd4491bbf 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -1,5 +1,3 @@ - - let pp_or cond pp_true pp_false ppf = if cond then pp_true ppf else pp_false ppf let print_result ~print_cost @@ -7,8 +5,11 @@ let print_result ~print_cost let score = if print_cost then string_of_int score ^ " " else "" in let kind = kind |> Db.Elt.Kind.to_string |> Unescape.string in let name = Unescape.string name in - let rhs = Option.map Unescape.string rhs in - Format.printf "%s%s %s%a\n" score kind name (Option.pp String.pp) rhs + let pp_rhs h = function + | None -> () + | Some rhs -> Format.fprintf h "%s" (Unescape.string rhs) + in + Format.printf "%s%s %s%a\n" score kind name pp_rhs rhs let search ~print_cost ~db query = match Query.(api ~shards:db { query; packages = []; limit = 50 }) with diff --git a/common/array_map.ml b/common/array_map.ml deleted file mode 100644 index d32c07562c..0000000000 --- a/common/array_map.ml +++ /dev/null @@ -1,45 +0,0 @@ -module type S = sig - type key - type 'a t - - val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool - val of_seq : (key * 'a) Seq.t -> 'a t - val to_array : 'a t -> (key * 'a) array - val find : key:key -> 'a t -> 'a option - val map : f:('a -> 'b) -> 'a t -> 'b t - val fold : f:(key:key -> acc:'b -> 'a -> 'b) -> init:'b -> 'a t -> 'b -end - -module Make (Key : Map.OrderedType) : S with type key = Key.t = struct - type key = Key.t - type 'a t = (key * 'a) array - - let equal eq_a = - Array.equal (fun (k, v) (k', v') -> Key.compare k k' = 0 && eq_a v v') - - let to_array arr = arr - - let of_seq seq = - let arr = seq |> Array.of_seq in - Array.fast_sort (fun (k, _) (k', _) -> Key.compare k k') arr ; - arr - - let rec find ~key arr lo hi = - if lo = hi - then None - else - let mid = (lo + hi) / 2 in - let key', v = arr.(mid) in - let comp = Key.compare key key' in - if comp = 0 - then Some v - else if comp < 0 - then find ~key arr lo mid - else find ~key arr mid hi - - let find ~key arr = find ~key arr 0 (Array.length arr) - let map ~f arr = Array.map (fun (k, v) -> k, f v) arr - - let fold ~f ~init arr = - Array.fold_left (fun acc (key, v) -> f ~key ~acc v) init arr -end diff --git a/common/char.ml b/common/char.ml deleted file mode 100644 index 1f87eddaf2..0000000000 --- a/common/char.ml +++ /dev/null @@ -1,5 +0,0 @@ -include Stdlib.Char -module Map = Map.Make (Stdlib.Char) -module Array_map = Array_map.Make (Stdlib.Char) - -let hash : char -> int = Hashtbl.hash diff --git a/common/char_list_map.ml b/common/char_list_map.ml deleted file mode 100644 index efbcb8d141..0000000000 --- a/common/char_list_map.ml +++ /dev/null @@ -1,7 +0,0 @@ -module Self = Map.Make (struct - type t = char list - - let compare = List.compare Char.compare -end) - -include Self diff --git a/common/common.ml b/common/common.ml deleted file mode 100644 index b098a7a0c5..0000000000 --- a/common/common.ml +++ /dev/null @@ -1,13 +0,0 @@ -(** Stdlib extensions and common data structures *) - -include Common_ -module Array = Array -module Char_list_map = Char_list_map -module Char = Char -module Int = Int -module List = List -module Map = Map -module Option = Option -module Set = Set -module String_list_map = String_list_map -module String = String diff --git a/common/common_.ml b/common/common_.ml deleted file mode 100644 index 96b079b2da..0000000000 --- a/common/common_.ml +++ /dev/null @@ -1,4 +0,0 @@ -let le ~compare v v' = compare v v' <= 0 -let lt ~compare v v' = compare v v' < 0 -let ge ~compare v v' = compare v v' >= 0 -let gt ~compare v v' = compare v v' > 0 diff --git a/common/dune b/common/dune deleted file mode 100644 index 9e53196cfa..0000000000 --- a/common/dune +++ /dev/null @@ -1,3 +0,0 @@ -(library - (name common) - (libraries pprint)) diff --git a/common/int.ml b/common/int.ml deleted file mode 100644 index d9c9e2e401..0000000000 --- a/common/int.ml +++ /dev/null @@ -1,6 +0,0 @@ -include Stdlib.Int -module Map = Map.Make (Stdlib.Int) - -let hash : int -> int = Hashtbl.hash -let pp = Format.pp_print_int -let (=) = equal \ No newline at end of file diff --git a/common/list.ml b/common/list.ml deleted file mode 100644 index 7542b8819f..0000000000 --- a/common/list.ml +++ /dev/null @@ -1,9 +0,0 @@ -include Stdlib.List - -let to_string ?(start="[") ?(sep="; ") ?(end_="]") a li = - start ^ (li |> map a |> String.concat sep ) ^ end_ - - - -let pprint ?(start="[") ?(sep="; ") ?(end_="]") a li = - start ^ (li |> map a |> String.concat sep ) ^ end_ \ No newline at end of file diff --git a/common/map.ml b/common/map.ml deleted file mode 100644 index e34a51c1ce..0000000000 --- a/common/map.ml +++ /dev/null @@ -1,560 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) -(* *) -(* Copyright 1996 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) -[@@@warning "-9"] - -module type OrderedType = sig - type t - - val compare : t -> t -> int -end - -module type S = sig - type key - - type !+'a t = - | Empty - | Node of - { l : 'a t - ; v : key - ; d : 'a - ; r : 'a t - ; h : int - } - - val empty : 'a t - val add : key -> 'a -> 'a t -> 'a t - val add_to_list : key -> 'a -> 'a list t -> 'a list t - val update : key -> ('a option -> 'a option) -> 'a t -> 'a t - val singleton : key -> 'a -> 'a t - val remove : key -> 'a t -> 'a t - - val merge : - (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t - - val union : (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t - val cardinal : 'a t -> int - val bindings : 'a t -> (key * 'a) list - val min_binding : 'a t -> key * 'a - val min_binding_opt : 'a t -> (key * 'a) option - val max_binding : 'a t -> key * 'a - val max_binding_opt : 'a t -> (key * 'a) option - val choose : 'a t -> key * 'a - val choose_opt : 'a t -> (key * 'a) option - val find : key -> 'a t -> 'a - val find_opt : key -> 'a t -> 'a option - val find_first : (key -> bool) -> 'a t -> key * 'a - val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option - val find_last : (key -> bool) -> 'a t -> key * 'a - val find_last_opt : (key -> bool) -> 'a t -> (key * 'a) option - val iter : (key -> 'a -> unit) -> 'a t -> unit - val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b - val map : ('a -> 'b) -> 'a t -> 'b t - val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t - val filter : (key -> 'a -> bool) -> 'a t -> 'a t - val filter_map : (key -> 'a -> 'b option) -> 'a t -> 'b t - val partition : (key -> 'a -> bool) -> 'a t -> 'a t * 'a t - val split : key -> 'a t -> 'a t * 'a option * 'a t - val is_empty : 'a t -> bool - val mem : key -> 'a t -> bool - val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool - val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int - val for_all : (key -> 'a -> bool) -> 'a t -> bool - val exists : (key -> 'a -> bool) -> 'a t -> bool - val to_list : 'a t -> (key * 'a) list - val of_list : (key * 'a) list -> 'a t - val to_seq : 'a t -> (key * 'a) Seq.t - val to_rev_seq : 'a t -> (key * 'a) Seq.t - val to_seq_from : key -> 'a t -> (key * 'a) Seq.t - val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t - val of_seq : (key * 'a) Seq.t -> 'a t -end - -module Make (Ord : OrderedType) = struct - type key = Ord.t - - type 'a t = - | Empty - | Node of - { l : 'a t - ; v : key - ; d : 'a - ; r : 'a t - ; h : int - } - - let height = function - | Empty -> 0 - | Node { h } -> h - - let create l x d r = - let hl = height l and hr = height r in - Node { l; v = x; d; r; h = (if hl >= hr then hl + 1 else hr + 1) } - - let singleton x d = Node { l = Empty; v = x; d; r = Empty; h = 1 } - - let bal l x d r = - let hl = - match l with - | Empty -> 0 - | Node { h } -> h - in - let hr = - match r with - | Empty -> 0 - | Node { h } -> h - in - if hl > hr + 2 - then begin - match l with - | Empty -> invalid_arg "Map.bal" - | Node { l = ll; v = lv; d = ld; r = lr } -> - if height ll >= height lr - then create ll lv ld (create lr x d r) - else begin - match lr with - | Empty -> invalid_arg "Map.bal" - | Node { l = lrl; v = lrv; d = lrd; r = lrr } -> - create (create ll lv ld lrl) lrv lrd (create lrr x d r) - end - end - else if hr > hl + 2 - then begin - match r with - | Empty -> invalid_arg "Map.bal" - | Node { l = rl; v = rv; d = rd; r = rr } -> - if height rr >= height rl - then create (create l x d rl) rv rd rr - else begin - match rl with - | Empty -> invalid_arg "Map.bal" - | Node { l = rll; v = rlv; d = rld; r = rlr } -> - create (create l x d rll) rlv rld (create rlr rv rd rr) - end - end - else Node { l; v = x; d; r; h = (if hl >= hr then hl + 1 else hr + 1) } - - let empty = Empty - - let is_empty = function - | Empty -> true - | _ -> false - - let rec add x data = function - | Empty -> Node { l = Empty; v = x; d = data; r = Empty; h = 1 } - | Node { l; v; d; r; h } as m -> - let c = Ord.compare x v in - if c = 0 - then if d == data then m else Node { l; v = x; d = data; r; h } - else if c < 0 - then - let ll = add x data l in - if l == ll then m else bal ll v d r - else - let rr = add x data r in - if r == rr then m else bal l v d rr - - let rec find x = function - | Empty -> raise Not_found - | Node { l; v; d; r } -> - let c = Ord.compare x v in - if c = 0 then d else find x (if c < 0 then l else r) - - let rec find_first_aux v0 d0 f = function - | Empty -> v0, d0 - | Node { l; v; d; r } -> - if f v then find_first_aux v d f l else find_first_aux v0 d0 f r - - let rec find_first f = function - | Empty -> raise Not_found - | Node { l; v; d; r } -> - if f v then find_first_aux v d f l else find_first f r - - let rec find_first_opt_aux v0 d0 f = function - | Empty -> Some (v0, d0) - | Node { l; v; d; r } -> - if f v then find_first_opt_aux v d f l else find_first_opt_aux v0 d0 f r - - let rec find_first_opt f = function - | Empty -> None - | Node { l; v; d; r } -> - if f v then find_first_opt_aux v d f l else find_first_opt f r - - let rec find_last_aux v0 d0 f = function - | Empty -> v0, d0 - | Node { l; v; d; r } -> - if f v then find_last_aux v d f r else find_last_aux v0 d0 f l - - let rec find_last f = function - | Empty -> raise Not_found - | Node { l; v; d; r } -> - if f v then find_last_aux v d f r else find_last f l - - let rec find_last_opt_aux v0 d0 f = function - | Empty -> Some (v0, d0) - | Node { l; v; d; r } -> - if f v then find_last_opt_aux v d f r else find_last_opt_aux v0 d0 f l - - let rec find_last_opt f = function - | Empty -> None - | Node { l; v; d; r } -> - if f v then find_last_opt_aux v d f r else find_last_opt f l - - let rec find_opt x = function - | Empty -> None - | Node { l; v; d; r } -> - let c = Ord.compare x v in - if c = 0 then Some d else find_opt x (if c < 0 then l else r) - - let rec mem x = function - | Empty -> false - | Node { l; v; r } -> - let c = Ord.compare x v in - c = 0 || mem x (if c < 0 then l else r) - - let rec min_binding = function - | Empty -> raise Not_found - | Node { l = Empty; v; d } -> v, d - | Node { l } -> min_binding l - - let rec min_binding_opt = function - | Empty -> None - | Node { l = Empty; v; d } -> Some (v, d) - | Node { l } -> min_binding_opt l - - let rec max_binding = function - | Empty -> raise Not_found - | Node { v; d; r = Empty } -> v, d - | Node { r } -> max_binding r - - let rec max_binding_opt = function - | Empty -> None - | Node { v; d; r = Empty } -> Some (v, d) - | Node { r } -> max_binding_opt r - - let rec remove_min_binding = function - | Empty -> invalid_arg "Map.remove_min_elt" - | Node { l = Empty; r } -> r - | Node { l; v; d; r } -> bal (remove_min_binding l) v d r - - let merge t1 t2 = - match t1, t2 with - | Empty, t -> t - | t, Empty -> t - | _, _ -> - let x, d = min_binding t2 in - bal t1 x d (remove_min_binding t2) - - let rec remove x = function - | Empty -> Empty - | Node { l; v; d; r } as m -> - let c = Ord.compare x v in - if c = 0 - then merge l r - else if c < 0 - then - let ll = remove x l in - if l == ll then m else bal ll v d r - else - let rr = remove x r in - if r == rr then m else bal l v d rr - - let rec update x f = function - | Empty -> begin - match f None with - | None -> Empty - | Some data -> Node { l = Empty; v = x; d = data; r = Empty; h = 1 } - end - | Node { l; v; d; r; h } as m -> - let c = Ord.compare x v in - if c = 0 - then begin - match f (Some d) with - | None -> merge l r - | Some data -> - if d == data then m else Node { l; v = x; d = data; r; h } - end - else if c < 0 - then - let ll = update x f l in - if l == ll then m else bal ll v d r - else - let rr = update x f r in - if r == rr then m else bal l v d rr - - let add_to_list x data m = - let add = function - | None -> Some [ data ] - | Some l -> Some (data :: l) - in - update x add m - - let rec iter f = function - | Empty -> () - | Node { l; v; d; r } -> - iter f l ; - f v d ; - iter f r - - let rec map f = function - | Empty -> Empty - | Node { l; v; d; r; h } -> - let l' = map f l in - let d' = f d in - let r' = map f r in - Node { l = l'; v; d = d'; r = r'; h } - - let rec mapi f = function - | Empty -> Empty - | Node { l; v; d; r; h } -> - let l' = mapi f l in - let d' = f v d in - let r' = mapi f r in - Node { l = l'; v; d = d'; r = r'; h } - - let rec fold f m accu = - match m with - | Empty -> accu - | Node { l; v; d; r } -> fold f r (f v d (fold f l accu)) - - let rec for_all p = function - | Empty -> true - | Node { l; v; d; r } -> p v d && for_all p l && for_all p r - - let rec exists p = function - | Empty -> false - | Node { l; v; d; r } -> p v d || exists p l || exists p r - - (* Beware: those two functions assume that the added k is *strictly* - smaller (or bigger) than all the present keys in the tree; it - does not test for equality with the current min (or max) key. - - Indeed, they are only used during the "join" operation which - respects this precondition. - *) - - let rec add_min_binding k x = function - | Empty -> singleton k x - | Node { l; v; d; r } -> bal (add_min_binding k x l) v d r - - let rec add_max_binding k x = function - | Empty -> singleton k x - | Node { l; v; d; r } -> bal l v d (add_max_binding k x r) - - (* Same as create and bal, but no assumptions are made on the - relative heights of l and r. *) - - let rec join l v d r = - match l, r with - | Empty, _ -> add_min_binding v d r - | _, Empty -> add_max_binding v d l - | ( Node { l = ll; v = lv; d = ld; r = lr; h = lh } - , Node { l = rl; v = rv; d = rd; r = rr; h = rh } ) -> - if lh > rh + 2 - then bal ll lv ld (join lr v d r) - else if rh > lh + 2 - then bal (join l v d rl) rv rd rr - else create l v d r - - (* Merge two trees l and r into one. - All elements of l must precede the elements of r. - No assumption on the heights of l and r. *) - - let concat t1 t2 = - match t1, t2 with - | Empty, t -> t - | t, Empty -> t - | _, _ -> - let x, d = min_binding t2 in - join t1 x d (remove_min_binding t2) - - let concat_or_join t1 v d t2 = - match d with - | Some d -> join t1 v d t2 - | None -> concat t1 t2 - - let rec split x = function - | Empty -> Empty, None, Empty - | Node { l; v; d; r } -> - let c = Ord.compare x v in - if c = 0 - then l, Some d, r - else if c < 0 - then - let ll, pres, rl = split x l in - ll, pres, join rl v d r - else - let lr, pres, rr = split x r in - join l v d lr, pres, rr - - let rec merge f s1 s2 = - match s1, s2 with - | Empty, Empty -> Empty - | Node { l = l1; v = v1; d = d1; r = r1; h = h1 }, _ when h1 >= height s2 -> - let l2, d2, r2 = split v1 s2 in - concat_or_join (merge f l1 l2) v1 (f v1 (Some d1) d2) (merge f r1 r2) - | _, Node { l = l2; v = v2; d = d2; r = r2 } -> - let l1, d1, r1 = split v2 s1 in - concat_or_join (merge f l1 l2) v2 (f v2 d1 (Some d2)) (merge f r1 r2) - | _ -> assert false - - let rec union f s1 s2 = - match s1, s2 with - | Empty, s | s, Empty -> s - | ( Node { l = l1; v = v1; d = d1; r = r1; h = h1 } - , Node { l = l2; v = v2; d = d2; r = r2; h = h2 } ) -> ( - if h1 >= h2 - then - let l2, d2, r2 = split v1 s2 in - let l = union f l1 l2 and r = union f r1 r2 in - match d2 with - | None -> join l v1 d1 r - | Some d2 -> concat_or_join l v1 (f v1 d1 d2) r - else - let l1, d1, r1 = split v2 s1 in - let l = union f l1 l2 and r = union f r1 r2 in - match d1 with - | None -> join l v2 d2 r - | Some d1 -> concat_or_join l v2 (f v2 d1 d2) r) - - let rec filter p = function - | Empty -> Empty - | Node { l; v; d; r } as m -> - (* call [p] in the expected left-to-right order *) - let l' = filter p l in - let pvd = p v d in - let r' = filter p r in - if pvd - then if l == l' && r == r' then m else join l' v d r' - else concat l' r' - - let rec filter_map f = function - | Empty -> Empty - | Node { l; v; d; r } -> - (* call [f] in the expected left-to-right order *) - let l' = filter_map f l in - let fvd = f v d in - let r' = filter_map f r in - begin - match fvd with - | Some d' -> join l' v d' r' - | None -> concat l' r' - end - - let rec partition p = function - | Empty -> Empty, Empty - | Node { l; v; d; r } -> - (* call [p] in the expected left-to-right order *) - let lt, lf = partition p l in - let pvd = p v d in - let rt, rf = partition p r in - if pvd - then join lt v d rt, concat lf rf - else concat lt rt, join lf v d rf - - type 'a enumeration = - | End - | More of key * 'a * 'a t * 'a enumeration - - let rec cons_enum m e = - match m with - | Empty -> e - | Node { l; v; d; r } -> cons_enum l (More (v, d, r, e)) - - let compare cmp m1 m2 = - if m1 == m2 - then 0 - else - let rec compare_aux e1 e2 = - match e1, e2 with - | End, End -> 0 - | End, _ -> -1 - | _, End -> 1 - | More (v1, d1, r1, e1), More (v2, d2, r2, e2) -> - let c = Ord.compare v1 v2 in - if c <> 0 - then c - else - let c = cmp d1 d2 in - if c <> 0 - then c - else compare_aux (cons_enum r1 e1) (cons_enum r2 e2) - in - compare_aux (cons_enum m1 End) (cons_enum m2 End) - - let equal cmp m1 m2 = - if m1 == m2 - then true - else - let rec equal_aux e1 e2 = - match e1, e2 with - | End, End -> true - | End, _ -> false - | _, End -> false - | More (v1, d1, r1, e1), More (v2, d2, r2, e2) -> - Ord.compare v1 v2 = 0 - && cmp d1 d2 - && equal_aux (cons_enum r1 e1) (cons_enum r2 e2) - in - equal_aux (cons_enum m1 End) (cons_enum m2 End) - - let rec cardinal = function - | Empty -> 0 - | Node { l; r } -> cardinal l + 1 + cardinal r - - let rec bindings_aux accu = function - | Empty -> accu - | Node { l; v; d; r } -> bindings_aux ((v, d) :: bindings_aux accu r) l - - let bindings s = bindings_aux [] s - let choose = min_binding - let choose_opt = min_binding_opt - let to_list = bindings - let of_list bs = List.fold_left (fun m (k, v) -> add k v m) empty bs - let add_seq i m = Seq.fold_left (fun m (k, v) -> add k v m) m i - let of_seq i = add_seq i empty - - let rec seq_of_enum_ c () = - match c with - | End -> Seq.Nil - | More (k, v, t, rest) -> Seq.Cons ((k, v), seq_of_enum_ (cons_enum t rest)) - - let to_seq m = seq_of_enum_ (cons_enum m End) - - let rec snoc_enum s e = - match s with - | Empty -> e - | Node { l; v; d; r } -> snoc_enum r (More (v, d, l, e)) - - let rec rev_seq_of_enum_ c () = - match c with - | End -> Seq.Nil - | More (k, v, t, rest) -> - Seq.Cons ((k, v), rev_seq_of_enum_ (snoc_enum t rest)) - - let to_rev_seq c = rev_seq_of_enum_ (snoc_enum c End) - - let to_seq_from low m = - let rec aux low m c = - match m with - | Empty -> c - | Node { l; v; d; r; _ } -> begin - match Ord.compare v low with - | 0 -> More (v, d, r, c) - | n when n < 0 -> aux low r c - | _ -> aux low l (More (v, d, r, c)) - end - in - seq_of_enum_ (aux low m End) -end diff --git a/common/option.ml b/common/option.ml deleted file mode 100644 index 6d7123168e..0000000000 --- a/common/option.ml +++ /dev/null @@ -1,12 +0,0 @@ -include Stdlib.Option - -module O = struct - let ( let* ) = bind - let ( let+ ) v f = map f v -end - -let hash hash_a = function - | Some a -> Hashtbl.hash (Some (hash_a a)) - | None -> Hashtbl.hash None - -let pp = Format.pp_print_option diff --git a/common/pair.ml b/common/pair.ml deleted file mode 100644 index 9f288167e9..0000000000 --- a/common/pair.ml +++ /dev/null @@ -1,5 +0,0 @@ -type ('a, 'b) t = 'a * 'b - -let to_string ?(start = "(") ?(end_ = ")") ?(sep = ", ") to_string_a to_string_b - (a, b) = - String.concat "" [ start; to_string_a a; sep; to_string_b b; end_ ] diff --git a/common/set.ml b/common/set.ml deleted file mode 100644 index 3b51db8247..0000000000 --- a/common/set.ml +++ /dev/null @@ -1,640 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) -(* *) -(* Copyright 1996 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) -[@@@warning "-9"] - -(* Sets over ordered types *) - -module type OrderedType = sig - type t - - val compare : t -> t -> int -end - -module type S = sig - type elt - - type t = - | Empty - | Node of - { l : t - ; v : elt - ; r : t - ; h : int - } - - val empty : t - val add : elt -> t -> t - val singleton : elt -> t - val remove : elt -> t -> t - val union : t -> t -> t - val inter : t -> t -> t - val disjoint : t -> t -> bool - val diff : t -> t -> t - val cardinal : t -> int - val elements : t -> elt list - val min_elt : t -> elt - val min_elt_opt : t -> elt option - val max_elt : t -> elt - val max_elt_opt : t -> elt option - val choose : t -> elt - val choose_opt : t -> elt option - val find : elt -> t -> elt - val find_opt : elt -> t -> elt option - val find_first : (elt -> bool) -> t -> elt - val find_first_opt : (elt -> bool) -> t -> elt option - val find_last : (elt -> bool) -> t -> elt - val find_last_opt : (elt -> bool) -> t -> elt option - val iter : (elt -> unit) -> t -> unit - val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a - val map : (elt -> elt) -> t -> t - val filter : (elt -> bool) -> t -> t - val filter_map : (elt -> elt option) -> t -> t - val partition : (elt -> bool) -> t -> t * t - val split : elt -> t -> t * bool * t - val is_empty : t -> bool - val mem : elt -> t -> bool - val equal : t -> t -> bool - val compare : t -> t -> int - val subset : t -> t -> bool - val for_all : (elt -> bool) -> t -> bool - val exists : (elt -> bool) -> t -> bool - val to_list : t -> elt list - val of_list : elt list -> t - val to_seq_from : elt -> t -> elt Seq.t - val to_seq : t -> elt Seq.t - val to_rev_seq : t -> elt Seq.t - val add_seq : elt Seq.t -> t -> t - val of_seq : elt Seq.t -> t -end - -module Make (Ord : OrderedType) = struct - type elt = Ord.t - - type t = - | Empty - | Node of - { l : t - ; v : elt - ; r : t - ; h : int - } - - (* Sets are represented by balanced binary trees (the heights of the - children differ by at most 2 *) - - let height = function - | Empty -> 0 - | Node { h } -> h - - (* Creates a new node with left son l, value v and right son r. - We must have all elements of l < v < all elements of r. - l and r must be balanced and | height l - height r | <= 2. - Inline expansion of height for better speed. *) - - let create l v r = - let hl = - match l with - | Empty -> 0 - | Node { h } -> h - in - let hr = - match r with - | Empty -> 0 - | Node { h } -> h - in - Node { l; v; r; h = (if hl >= hr then hl + 1 else hr + 1) } - - (* Same as create, but performs one step of rebalancing if necessary. - Assumes l and r balanced and | height l - height r | <= 3. - Inline expansion of create for better speed in the most frequent case - where no rebalancing is required. *) - - let bal l v r = - let hl = - match l with - | Empty -> 0 - | Node { h } -> h - in - let hr = - match r with - | Empty -> 0 - | Node { h } -> h - in - if hl > hr + 2 - then begin - match l with - | Empty -> invalid_arg "Set.bal" - | Node { l = ll; v = lv; r = lr } -> - if height ll >= height lr - then create ll lv (create lr v r) - else begin - match lr with - | Empty -> invalid_arg "Set.bal" - | Node { l = lrl; v = lrv; r = lrr } -> - create (create ll lv lrl) lrv (create lrr v r) - end - end - else if hr > hl + 2 - then begin - match r with - | Empty -> invalid_arg "Set.bal" - | Node { l = rl; v = rv; r = rr } -> - if height rr >= height rl - then create (create l v rl) rv rr - else begin - match rl with - | Empty -> invalid_arg "Set.bal" - | Node { l = rll; v = rlv; r = rlr } -> - create (create l v rll) rlv (create rlr rv rr) - end - end - else Node { l; v; r; h = (if hl >= hr then hl + 1 else hr + 1) } - - (* Insertion of one element *) - - let rec add x = function - | Empty -> Node { l = Empty; v = x; r = Empty; h = 1 } - | Node { l; v; r } as t -> - let c = Ord.compare x v in - if c = 0 - then t - else if c < 0 - then - let ll = add x l in - if l == ll then t else bal ll v r - else - let rr = add x r in - if r == rr then t else bal l v rr - - let singleton x = Node { l = Empty; v = x; r = Empty; h = 1 } - - (* Beware: those two functions assume that the added v is *strictly* - smaller (or bigger) than all the present elements in the tree; it - does not test for equality with the current min (or max) element. - Indeed, they are only used during the "join" operation which - respects this precondition. - *) - - let rec add_min_element x = function - | Empty -> singleton x - | Node { l; v; r } -> bal (add_min_element x l) v r - - let rec add_max_element x = function - | Empty -> singleton x - | Node { l; v; r } -> bal l v (add_max_element x r) - - (* Same as create and bal, but no assumptions are made on the - relative heights of l and r. *) - - let rec join l v r = - match l, r with - | Empty, _ -> add_min_element v r - | _, Empty -> add_max_element v l - | ( Node { l = ll; v = lv; r = lr; h = lh } - , Node { l = rl; v = rv; r = rr; h = rh } ) -> - if lh > rh + 2 - then bal ll lv (join lr v r) - else if rh > lh + 2 - then bal (join l v rl) rv rr - else create l v r - - (* Smallest and greatest element of a set *) - - let rec min_elt = function - | Empty -> raise Not_found - | Node { l = Empty; v } -> v - | Node { l } -> min_elt l - - let rec min_elt_opt = function - | Empty -> None - | Node { l = Empty; v } -> Some v - | Node { l } -> min_elt_opt l - - let rec max_elt = function - | Empty -> raise Not_found - | Node { v; r = Empty } -> v - | Node { r } -> max_elt r - - let rec max_elt_opt = function - | Empty -> None - | Node { v; r = Empty } -> Some v - | Node { r } -> max_elt_opt r - - (* Remove the smallest element of the given set *) - - let rec remove_min_elt = function - | Empty -> invalid_arg "Set.remove_min_elt" - | Node { l = Empty; r } -> r - | Node { l; v; r } -> bal (remove_min_elt l) v r - - (* Merge two trees l and r into one. - All elements of l must precede the elements of r. - Assume | height l - height r | <= 2. *) - - let merge t1 t2 = - match t1, t2 with - | Empty, t -> t - | t, Empty -> t - | _, _ -> bal t1 (min_elt t2) (remove_min_elt t2) - - (* Merge two trees l and r into one. - All elements of l must precede the elements of r. - No assumption on the heights of l and r. *) - - let concat t1 t2 = - match t1, t2 with - | Empty, t -> t - | t, Empty -> t - | _, _ -> join t1 (min_elt t2) (remove_min_elt t2) - - (* Splitting. split x s returns a triple (l, present, r) where - - l is the set of elements of s that are < x - - r is the set of elements of s that are > x - - present is false if s contains no element equal to x, - or true if s contains an element equal to x. *) - - let rec split x = function - | Empty -> Empty, false, Empty - | Node { l; v; r } -> - let c = Ord.compare x v in - if c = 0 - then l, true, r - else if c < 0 - then - let ll, pres, rl = split x l in - ll, pres, join rl v r - else - let lr, pres, rr = split x r in - join l v lr, pres, rr - - (* Implementation of the set operations *) - - let empty = Empty - - let is_empty = function - | Empty -> true - | _ -> false - - let rec mem x = function - | Empty -> false - | Node { l; v; r } -> - let c = Ord.compare x v in - c = 0 || mem x (if c < 0 then l else r) - - let rec remove x = function - | Empty -> Empty - | Node { l; v; r } as t -> - let c = Ord.compare x v in - if c = 0 - then merge l r - else if c < 0 - then - let ll = remove x l in - if l == ll then t else bal ll v r - else - let rr = remove x r in - if r == rr then t else bal l v rr - - let rec union s1 s2 = - match s1, s2 with - | Empty, t2 -> t2 - | t1, Empty -> t1 - | ( Node { l = l1; v = v1; r = r1; h = h1 } - , Node { l = l2; v = v2; r = r2; h = h2 } ) -> - if h1 >= h2 - then - if h2 = 1 - then add v2 s1 - else begin - let l2, _, r2 = split v1 s2 in - join (union l1 l2) v1 (union r1 r2) - end - else if h1 = 1 - then add v1 s2 - else begin - let l1, _, r1 = split v2 s1 in - join (union l1 l2) v2 (union r1 r2) - end - - let rec inter s1 s2 = - match s1, s2 with - | Empty, _ -> Empty - | _, Empty -> Empty - | Node { l = l1; v = v1; r = r1 }, t2 -> ( - match split v1 t2 with - | l2, false, r2 -> concat (inter l1 l2) (inter r1 r2) - | l2, true, r2 -> join (inter l1 l2) v1 (inter r1 r2)) - - (* Same as split, but compute the left and right subtrees - only if the pivot element is not in the set. The right subtree - is computed on demand. *) - - type split_bis = - | Found - | NotFound of t * (unit -> t) - - let rec split_bis x = function - | Empty -> NotFound (Empty, fun () -> Empty) - | Node { l; v; r; _ } -> ( - let c = Ord.compare x v in - if c = 0 - then Found - else if c < 0 - then - match split_bis x l with - | Found -> Found - | NotFound (ll, rl) -> NotFound (ll, fun () -> join (rl ()) v r) - else - match split_bis x r with - | Found -> Found - | NotFound (lr, rr) -> NotFound (join l v lr, rr)) - - let rec disjoint s1 s2 = - match s1, s2 with - | Empty, _ | _, Empty -> true - | Node { l = l1; v = v1; r = r1 }, t2 -> ( - if s1 == s2 - then false - else - match split_bis v1 t2 with - | NotFound (l2, r2) -> disjoint l1 l2 && disjoint r1 (r2 ()) - | Found -> false) - - let rec diff s1 s2 = - match s1, s2 with - | Empty, _ -> Empty - | t1, Empty -> t1 - | Node { l = l1; v = v1; r = r1 }, t2 -> ( - match split v1 t2 with - | l2, false, r2 -> join (diff l1 l2) v1 (diff r1 r2) - | l2, true, r2 -> concat (diff l1 l2) (diff r1 r2)) - - type enumeration = - | End - | More of elt * t * enumeration - - let rec cons_enum s e = - match s with - | Empty -> e - | Node { l; v; r } -> cons_enum l (More (v, r, e)) - - let rec compare_aux e1 e2 = - match e1, e2 with - | End, End -> 0 - | End, _ -> -1 - | _, End -> 1 - | More (v1, r1, e1), More (v2, r2, e2) -> - let c = Ord.compare v1 v2 in - if c <> 0 then c else compare_aux (cons_enum r1 e1) (cons_enum r2 e2) - - let compare s1 s2 = - if s1 == s2 then 0 else compare_aux (cons_enum s1 End) (cons_enum s2 End) - - let equal s1 s2 = compare s1 s2 = 0 - - let rec subset s1 s2 = - match s1, s2 with - | Empty, _ -> true - | _, Empty -> false - | Node { l = l1; v = v1; r = r1 }, (Node { l = l2; v = v2; r = r2 } as t2) - -> - let c = Ord.compare v1 v2 in - if c = 0 - then subset l1 l2 && subset r1 r2 - else if c < 0 - then - subset (Node { l = l1; v = v1; r = Empty; h = 0 }) l2 && subset r1 t2 - else - subset (Node { l = Empty; v = v1; r = r1; h = 0 }) r2 && subset l1 t2 - - let rec iter f = function - | Empty -> () - | Node { l; v; r } -> - iter f l ; - f v ; - iter f r - - let rec fold f s accu = - match s with - | Empty -> accu - | Node { l; v; r } -> fold f r (f v (fold f l accu)) - - let rec for_all p = function - | Empty -> true - | Node { l; v; r } -> p v && for_all p l && for_all p r - - let rec exists p = function - | Empty -> false - | Node { l; v; r } -> p v || exists p l || exists p r - - let rec filter p = function - | Empty -> Empty - | Node { l; v; r } as t -> - (* call [p] in the expected left-to-right order *) - let l' = filter p l in - let pv = p v in - let r' = filter p r in - if pv - then if l == l' && r == r' then t else join l' v r' - else concat l' r' - - let rec partition p = function - | Empty -> Empty, Empty - | Node { l; v; r } -> - (* call [p] in the expected left-to-right order *) - let lt, lf = partition p l in - let pv = p v in - let rt, rf = partition p r in - if pv then join lt v rt, concat lf rf else concat lt rt, join lf v rf - - let rec cardinal = function - | Empty -> 0 - | Node { l; r } -> cardinal l + 1 + cardinal r - - let rec elements_aux accu = function - | Empty -> accu - | Node { l; v; r } -> elements_aux (v :: elements_aux accu r) l - - let elements s = elements_aux [] s - let choose = min_elt - let choose_opt = min_elt_opt - - let rec find x = function - | Empty -> raise Not_found - | Node { l; v; r } -> - let c = Ord.compare x v in - if c = 0 then v else find x (if c < 0 then l else r) - - let rec find_first_aux v0 f = function - | Empty -> v0 - | Node { l; v; r } -> - if f v then find_first_aux v f l else find_first_aux v0 f r - - let rec find_first f = function - | Empty -> raise Not_found - | Node { l; v; r } -> if f v then find_first_aux v f l else find_first f r - - let rec find_first_opt_aux v0 f = function - | Empty -> Some v0 - | Node { l; v; r } -> - if f v then find_first_opt_aux v f l else find_first_opt_aux v0 f r - - let rec find_first_opt f = function - | Empty -> None - | Node { l; v; r } -> - if f v then find_first_opt_aux v f l else find_first_opt f r - - let rec find_last_aux v0 f = function - | Empty -> v0 - | Node { l; v; r } -> - if f v then find_last_aux v f r else find_last_aux v0 f l - - let rec find_last f = function - | Empty -> raise Not_found - | Node { l; v; r } -> if f v then find_last_aux v f r else find_last f l - - let rec find_last_opt_aux v0 f = function - | Empty -> Some v0 - | Node { l; v; r } -> - if f v then find_last_opt_aux v f r else find_last_opt_aux v0 f l - - let rec find_last_opt f = function - | Empty -> None - | Node { l; v; r } -> - if f v then find_last_opt_aux v f r else find_last_opt f l - - let rec find_opt x = function - | Empty -> None - | Node { l; v; r } -> - let c = Ord.compare x v in - if c = 0 then Some v else find_opt x (if c < 0 then l else r) - - let try_join l v r = - (* [join l v r] can only be called when (elements of l < v < - elements of r); use [try_join l v r] when this property may - not hold, but you hope it does hold in the common case *) - if (l = Empty || Ord.compare (max_elt l) v < 0) - && (r = Empty || Ord.compare v (min_elt r) < 0) - then join l v r - else union l (add v r) - - let rec map f = function - | Empty -> Empty - | Node { l; v; r } as t -> - (* enforce left-to-right evaluation order *) - let l' = map f l in - let v' = f v in - let r' = map f r in - if l == l' && v == v' && r == r' then t else try_join l' v' r' - - let try_concat t1 t2 = - match t1, t2 with - | Empty, t -> t - | t, Empty -> t - | _, _ -> try_join t1 (min_elt t2) (remove_min_elt t2) - - let rec filter_map f = function - | Empty -> Empty - | Node { l; v; r } as t -> - (* enforce left-to-right evaluation order *) - let l' = filter_map f l in - let v' = f v in - let r' = filter_map f r in - begin - match v' with - | Some v' -> - if l == l' && v == v' && r == r' then t else try_join l' v' r' - | None -> try_concat l' r' - end - - let of_sorted_list l = - let rec sub n l = - match n, l with - | 0, l -> Empty, l - | 1, x0 :: l -> Node { l = Empty; v = x0; r = Empty; h = 1 }, l - | 2, x0 :: x1 :: l -> - ( Node - { l = Node { l = Empty; v = x0; r = Empty; h = 1 } - ; v = x1 - ; r = Empty - ; h = 2 - } - , l ) - | 3, x0 :: x1 :: x2 :: l -> - ( Node - { l = Node { l = Empty; v = x0; r = Empty; h = 1 } - ; v = x1 - ; r = Node { l = Empty; v = x2; r = Empty; h = 1 } - ; h = 2 - } - , l ) - | n, l -> ( - let nl = n / 2 in - let left, l = sub nl l in - match l with - | [] -> assert false - | mid :: l -> - let right, l = sub (n - nl - 1) l in - create left mid right, l) - in - fst (sub (List.length l) l) - - let to_list = elements - - let of_list l = - match l with - | [] -> empty - | [ x0 ] -> singleton x0 - | [ x0; x1 ] -> add x1 (singleton x0) - | [ x0; x1; x2 ] -> add x2 (add x1 (singleton x0)) - | [ x0; x1; x2; x3 ] -> add x3 (add x2 (add x1 (singleton x0))) - | [ x0; x1; x2; x3; x4 ] -> add x4 (add x3 (add x2 (add x1 (singleton x0)))) - | _ -> of_sorted_list (List.sort_uniq Ord.compare l) - - let add_seq i m = Seq.fold_left (fun s x -> add x s) m i - let of_seq i = add_seq i empty - - let rec seq_of_enum_ c () = - match c with - | End -> Seq.Nil - | More (x, t, rest) -> Seq.Cons (x, seq_of_enum_ (cons_enum t rest)) - - let to_seq c = seq_of_enum_ (cons_enum c End) - - let rec snoc_enum s e = - match s with - | Empty -> e - | Node { l; v; r } -> snoc_enum r (More (v, l, e)) - - let rec rev_seq_of_enum_ c () = - match c with - | End -> Seq.Nil - | More (x, t, rest) -> Seq.Cons (x, rev_seq_of_enum_ (snoc_enum t rest)) - - let to_rev_seq c = rev_seq_of_enum_ (snoc_enum c End) - - let to_seq_from low s = - let rec aux low s c = - match s with - | Empty -> c - | Node { l; r; v; _ } -> begin - match Ord.compare v low with - | 0 -> More (v, r, c) - | n when n < 0 -> aux low r c - | _ -> aux low l (More (v, r, c)) - end - in - seq_of_enum_ (aux low s End) -end diff --git a/common/string.ml b/common/string.ml deleted file mode 100644 index de720f9239..0000000000 --- a/common/string.ml +++ /dev/null @@ -1,15 +0,0 @@ -include Stdlib.String - -let hash : t -> int = Hashtbl.hash -let pp = Format.pp_print_string - -module Hashtbl = Hashtbl.Make (struct - type nonrec t = t - - let equal = equal - let hash = hash -end) - -let rev str = - let len = length str in - init len (fun i -> get str (len - i - 1)) diff --git a/common/string_list_map.ml b/common/string_list_map.ml deleted file mode 100644 index 03e636ba75..0000000000 --- a/common/string_list_map.ml +++ /dev/null @@ -1,7 +0,0 @@ -module Self = Map.Make (struct - type t = string list - - let compare = List.compare String.compare -end) - -include Self diff --git a/common/test/dune b/common/test/dune deleted file mode 100644 index 67ad57e47a..0000000000 --- a/common/test/dune +++ /dev/null @@ -1,5 +0,0 @@ -(test - (name test) - (flags - (:standard -open Common)) - (libraries alcotest common)) diff --git a/common/test/test.ml b/common/test/test.ml deleted file mode 100644 index 6a1a3af2ad..0000000000 --- a/common/test/test.ml +++ /dev/null @@ -1,93 +0,0 @@ - - -let rec succ_ge_reference i ~compare elt arr = - Printf.printf "ref_succ_ge %i\n%!" i ; - if i = Array.length arr - then None - else if ge ~compare arr.(i) elt - then Some arr.(i) - else succ_ge_reference (i + 1) ~compare elt arr - -let rec succ_gt_reference i ~compare elt arr = - if i = Array.length arr - then None - else if gt ~compare arr.(i) elt - then Some arr.(i) - else succ_gt_reference (i + 1) ~compare elt arr - -let succ_ge_reference ~compare elt arr = succ_ge_reference 0 ~compare elt arr -let succ_gt_reference ~compare elt arr = succ_gt_reference 0 ~compare elt arr - -let test_succ_ge elt arr () = - Alcotest.(check (option int)) - "same int option" - (succ_ge_reference ~compare:Int.compare elt arr) - (Array.succ_ge ~compare:Int.compare elt arr) - -let test_succ_gt elt arr () = - Alcotest.(check (option int)) - "same int option" - (succ_gt_reference ~compare:Int.compare elt arr) - (Array.succ_gt ~compare:Int.compare elt arr) - -let () = Random.init 123 - -(* The tests *) - -let random_array size = - let r = - List.init size (fun _ -> Random.full_int (size * 2)) - |> List.sort_uniq Int.compare |> Array.of_list - in - - r - -let test_ge a b = - Alcotest.test_case (Printf.sprintf "ge %i %i" a b) `Quick (fun () -> - Alcotest.(check bool) "same bool" (ge ~compare:Int.compare a b) (a >= b)) - -let test_gt a b = - Alcotest.test_case (Printf.sprintf "gt %i %i" a b) `Quick (fun () -> - Alcotest.(check bool) "same bool" (gt ~compare:Int.compare a b) (a > b)) - -let test_lt a b = - Alcotest.test_case (Printf.sprintf "lt %i %i" a b) `Quick (fun () -> - Alcotest.(check bool) "same bool" (lt ~compare:Int.compare a b) (a < b)) - -let test_le a b = - Alcotest.test_case (Printf.sprintf "le %i %i" a b) `Quick (fun () -> - Alcotest.(check bool) "same bool" (le ~compare:Int.compare a b) (a <= b)) - -let test_operators = - (let a = 12 and b = 12 in - [ test_ge a b; test_gt a b; test_le a b; test_lt a b ]) - @ (let a = 12 and b = 14 in - [ test_ge a b; test_gt a b; test_le a b; test_lt a b ]) - @ - let a = 15 and b = 10 in - [ test_ge a b; test_gt a b; test_le a b; test_lt a b ] - -let tests_arr name test = - List.init 50 (fun i -> - let elt = Random.full_int ((i * 2) + 1) in - let arr = random_array i in - let arr_string = - if i <= 5 - then - "[|" - ^ (arr |> Array.to_list |> List.map string_of_int - |> String.concat "; ") - ^ "|]" - else "[|...|]" - in - Alcotest.test_case - (Printf.sprintf "%s %i %s " name elt arr_string) - `Quick (test elt arr)) - -let tests_succ_ge = tests_arr "succ_ge" test_succ_ge -let tests_succ_gt = tests_arr "succ_gt" test_succ_gt - -let () = - let open Alcotest in - run "Common" - [ "Common", test_operators; "Array", tests_succ_ge @ tests_succ_gt ] diff --git a/db/cache.ml_ b/db/cache.ml_ deleted file mode 100644 index 9d318f111c..0000000000 --- a/db/cache.ml_ +++ /dev/null @@ -1,331 +0,0 @@ - - -type uid = int - -let clears = ref [] -let clear () = Common.List.iter (fun f -> f ()) !clears - -module type Cached = sig - type t - - val memo : t -> t -end - -(** The result of the [Make] functor. [equal] and [hash] are reexported for - composability with other functors. *) -module type Memo = sig - type t - - val memo : t -> uid * t -end - -(** This module specifies what is need to construct a cache. *) -module type Cachable = sig - type t - type key - - val sub : memo:(t -> uid * t) -> t -> key * t - (** [sub ~memo (v : t)] is [(k, v')]. [v'] should be equal to [v], and [k] a - hashable shallow copy of [v]. - For every subvalue [vs] of type [t] we have [ks, vs' = memo vs]. - In [k], [vs] is replaced by [ks]. - In [v], [vs] is replaced by [vs']. - - and subvalues [a] of type [A.t] by [A.memo a]. *) -end - -(** Builds a cache from an cachable type.*) -module Make (Elt : Cachable) : Memo with type t = Elt.t = struct - type t = Elt.t - - let equal = ( = ) - let hash = Hashtbl.hash - - let new_uid = - let i = ref 0 in - fun () -> - let r = !i in - i := r + 1 ; - r - - module H = Hashtbl.Make (struct - type t = Elt.key - - let equal = equal - let hash = hash - end) - - let cache : (int * t) H.t = H.create 16 - let () = clears := (fun () -> H.clear cache) :: !clears - - let rec memo elt : int * t = - let key, elt = Elt.sub ~memo elt in - match H.find cache key with - | uid, elt -> uid, elt - | exception Not_found -> - let uid = new_uid () in - - H.add cache key (uid, elt) ; - uid, elt -end - -(** Does not build a cache, but exposes functions that caches that subvalues of - a given cache. This is useful for big value with a lot of subvalues, an - expansive [hash] and [equal] function, and not a lot of opportunities for - sharing. *) -(*module Make_sub_only (Elt : Cachable) : Memo with type t = Elt.t = struct - type t = Elt.t - type key = Elt.key - - let equal = Elt.equal - let hash = Elt.hash - let rec memo str = Elt.sub ~memo str - end -*) - -module Strip (Memo : Memo) : Cached with type t = Memo.t = struct - type t = Memo.t - - let memo elt = - let _, elt = Memo.memo elt in - elt -end - -(** This module does not use {!Make} because it does not actually cache anything, - its just here for composition. *) -module Char = struct - type t = char - - let memo c = Char.code c, c - - module Map = Char.Map - module Array_map = Char.Array_map -end - -module String = Make (struct - type t = string - type key = string - - let sub ~memo:_ str = str, str -end) - -module Option (A : Memo) = Make (struct - type t = A.t option - type key = uid option - - let sub ~memo:_ opt = - match opt with - | Some a -> - let uid, a = A.memo a in - Some uid, Some a - | None -> None, None -end) - -module List (A : Memo) = Make (struct - type t = A.t list - - type key = - | Empty - | Cons of uid * uid - - let sub ~memo lst = - match lst with - | [] -> Empty, [] - | elt :: li -> - let uid_elt, elt = A.memo elt in - let uid_li, li = memo li in - Cons (uid_elt, uid_li), elt :: li -end) - -module Array (A : Memo) = Make (struct - type t = A.t array - type key = uid array - - let sub ~memo:_ arr = - let arr = Array.map A.memo arr in - let key = Array.map (fun (key, _) -> key) arr in - let arr = Array.map (fun (_, elt) -> elt) arr in - key, arr -end) - -module Char_list = List (Char) -module String_list = List (String) -module String_list_list = List (String_list) -module String_option = Option (String) - -module Kind = Make (struct - type t = Elt.Kind.t - type key = uid Elt.Kind.abstract - - let sub ~memo:_ k = - let open Elt.Kind in - match k with - | Constructor type_ -> - let uid, type_ = String_list_list.memo type_ in - Constructor uid, Constructor type_ - | ExtensionConstructor type_ -> - let uid, type_ = String_list_list.memo type_ in - ExtensionConstructor uid, ExtensionConstructor type_ - | Field type_ -> - let uid, type_ = String_list_list.memo type_ in - Field uid, Field type_ - | Val type_ -> - let uid, type_ = String_list_list.memo type_ in - Val uid, Val type_ - (* the below looks like it could be [k -> (k, k) but it does not because of typing issues] *) - | Doc -> Doc, Doc - | TypeDecl -> TypeDecl, TypeDecl - | Module -> Module, Module - | Exception -> Exception, Exception - | Class_type -> Class_type, Class_type - | Method -> Method, Method - | Class -> Class, Class - | TypeExtension -> TypeExtension, TypeExtension - | ModuleType -> ModuleType, ModuleType -end) - -module Elt = struct - include Make (struct - type t = Elt.t - - type key = - { name : uid - ; kind : int - } - - let int_of_kind = - let open Elt.Kind in - function - | Constructor _ -> 0 - | Field _ -> 1 - | Val _ -> 2 - (* the below looks like it could be [k -> (k, k) but it does not because of typing issues] *) - | Doc -> 3 - | TypeDecl -> 4 - | Module -> 5 - | Exception -> 6 - | Class_type -> 7 - | Method -> 8 - | Class -> 9 - | TypeExtension -> 10 - | ExtensionConstructor _ -> 11 - | ModuleType -> 12 - - let sub ~memo:_ Elt.{ name; kind; doc_html; score; pkg; rhs; url } = - let uid_name, name = String.memo name in - let _uid_rhs, rhs = String_option.memo rhs in - (*let _uid_kind, kind = Kind.memo kind in*) - ( { name = uid_name; kind = int_of_kind kind } - , Elt.{ name; kind; doc_html; pkg; rhs; score; url } ) - end) - - module Set = Elt.Set -end - -module Elt_array = Array (Elt) - -module Set (A : Memo) (S : Set.S with type elt = A.t) = Make (struct - type t = S.t - - type key = - | Empty - | Node of - { l : uid - ; v : uid - ; r : uid - ; h : int - } - - let sub ~memo set = - match set with - | S.Empty -> Empty, S.Empty - | S.Node { l; v; r; h } -> - (* This shares subset. Not actually very useful on tested exemples. *) - let uid_l, l = memo l in - let uid_v, v = A.memo v in - let uid_r, r = memo r in - Node { l = uid_l; v = uid_v; r = uid_r; h }, S.Node { l; v; r; h } -end) - -module Map (A : Memo) (M : Map.S) = Make (struct - type t = A.t M.t - - type key = - | Empty - | Node of - { l : uid - ; v : M.key - ; d : uid - ; r : uid - ; h : int - } - - let sub ~memo m = - match m with - | M.Empty -> Empty, M.Empty - | M.Node { l; v; d; r; h } -> - (* This shares submaps ! *) - let uid_l, l = memo l in - let uid_d, d = A.memo d in - let uid_r, r = memo r in - Node { l = uid_l; v; d = uid_d; r = uid_r; h }, M.Node { l; v; d; r; h } -end) - -module Elt_set = Set (Elt) (Elt.Set) -module Elt_set_option = Option (Elt_set) -module Char_map (A : Memo) = Map (A) (Char.Map) -module Int_map (A : Memo) = Map (A) (Int.Map) -module Elt_array_occ = Int_map (Elt_array) -module Elt_set_occ = Int_map (Elt_set) -module Elt_set_char_map = Char_map (Elt_set) - -module Trie (A : Memo) : Memo with type t = A.t Trie.t = struct - module A_option = Option (A) - - (* Here [Make_sub_only] is good enough. Using [Make] instead slows down the - [Base] test by 50s for a 20ko gain. *) - module rec M : (Memo with type t = A.t Trie.t) = Make (struct - type t = A.t Trie.t - - type key = - | Leaf of uid * uid - | Node of - { leaf : uid - ; children : uid - } - - let sub ~memo:_ trie : key * _ = - let open Trie in - match trie with - | Leaf (chars, elts) -> - let uid_chars, chars = Char_list.memo chars in - let uid_elts, elts = A.memo elts in - Leaf (uid_chars, uid_elts), Trie.Leaf (chars, elts) - | Node { leaf; children } -> - let uid_leaf, leaf = A_option.memo leaf in - let uid_children, children = Children.memo children in - ( Node { leaf = uid_leaf; children = uid_children } - , Trie.Node { leaf; children } ) - end) - - and Children : (Memo with type t = A.t Trie.t Char.Map.t) = Char_map (M) - - include M -end - -module Elt_set_trie = Trie (Elt_set) -module Elt_set_occ_trie = Trie (Elt_set_occ) -module Elt_array_trie = Trie (Elt_array) -module Elt_array_occ_trie = Trie (Elt_array_occ) - -(* Hiding the uids *) -module String_ = Strip (String) -module Char_list_ = Strip (Char_list) -module String_list_ = Strip (String_list) -module String_list_list_ = Strip (String_list_list) -module Kind_ = Strip (Kind) -module Elt_array_ = Strip (Elt_array) -module Elt_set_trie_ = Strip (Elt_set_trie) -module Elt_set_occ_trie_ = Strip (Elt_set_occ_trie) -module Elt_array_trie_ = Strip (Elt_array_trie) -module Elt_array_occ_trie_ = Strip (Elt_array_occ_trie) diff --git a/db/cache.mli_ b/db/cache.mli_ deleted file mode 100644 index 8cb8645116..0000000000 --- a/db/cache.mli_ +++ /dev/null @@ -1,28 +0,0 @@ -(** This module provides a way to do memory-sharing after the fact, for - a nuumber a OCaml types. - Every sharable element inside a type is also shared.*) - - - -val clear : unit -> unit -(** [clear ()] removes every value from the caches of every types. *) - -(** A type [t] and its [memo] function. *) -module type Cached = sig - type t - - val memo : t -> t - (** [memo v] is [v] with the maximum amount of shared memory. As side effect - is to register [v] and its subvalues to be shared in the future. *) -end - -module String_ : Cached with type t = string -module Char_list_ : Cached with type t = char list -module String_list_ : Cached with type t = string list -module String_list_list_ : Cached with type t = string list list -module Kind_ : Cached with type t = Elt.Kind.t -module Elt_array_ : Cached with type t = Elt.t array -module Elt_set_trie_ : Cached with type t = Elt.Set.t Trie.t -module Elt_set_occ_trie_ : Cached with type t = Elt.Set.t Int.Map.t Trie.t -module Elt_array_trie_ : Cached with type t = Elt.t Array.t Trie.t -module Elt_array_occ_trie_ : Cached with type t = Elt.t Array.t Int.Map.t Trie.t diff --git a/db/db.ml b/db/db.ml index 2f5c1a6aaf..ffee44fea4 100644 --- a/db/db.ml +++ b/db/db.ml @@ -2,10 +2,8 @@ module Elt = Elt module Types = Types module Storage_toplevel = Storage module Suffix_tree = Suffix_tree +module Occ = Occ include Types -module Occ = Int.Map - -let list_of_string s = List.init (String.length s) (String.get s) module type S = sig type writer @@ -23,29 +21,16 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct let db_types = Suffix_tree.With_occ.make () let db_names = Suffix_tree.With_elts.make () - module Hset2 = Hashtbl.Make (struct - type t = Elt.Set.t * Elt.Set.t - - let hash = Hashtbl.hash - let equal (a, b) (a', b') = a == a' && b == b' - end) - - module Hocc2 = Hashtbl.Make (struct - type t = Elt.Set.t Occ.t * Elt.Set.t Occ.t - - let hash = Hashtbl.hash - let equal (a, b) (a', b') = a == a' && b == b' - end) - let export h = load_counter := 0 ; + let t0 = Unix.gettimeofday () in let db = { db_types = Suffix_tree.With_occ.export db_types ; db_names = Suffix_tree.With_elts.export db_names } in - PPrint.ToChannel.pretty 0.8 120 stdout - (Suffix_tree.With_elts.pprint db.db_names) ; + let t1 = Unix.gettimeofday () in + Format.printf "Export in %fms@." (1000.0 *. (t1 -. t0)) ; Storage.save ~db:h db let store name elt ~count = diff --git a/db/db.mli b/db/db.mli index 8ff48396bc..c3e0c4e03f 100644 --- a/db/db.mli +++ b/db/db.mli @@ -2,16 +2,13 @@ module Elt = Elt module Types = Types module Storage = Storage module Suffix_tree = Suffix_tree +module Occ = Occ type t = Types.t = - { db_types : Suffix_tree.With_occ.reader ; db_names : Suffix_tree.With_elts.reader } - -val list_of_string : string -> char list - module type S = sig type writer diff --git a/db/dune b/db/dune index 3f54953bc5..aada4a6e19 100644 --- a/db/dune +++ b/db/dune @@ -1,5 +1,3 @@ (library - (flags - (:standard -open Common)) (name db) - (libraries unix common pprint)) + (libraries unix)) diff --git a/db/elt.ml b/db/elt.ml index 1bafd082f5..cda0ceecb2 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -72,14 +72,7 @@ module Package = struct ; version : string } - let hash { name; version } = - Hashtbl.hash (String.hash name, String.hash version) - - let equal = ( = ) - - let v ~name ~version = let version = version in - - { name; version } + let v ~name ~version = { name; version } end type package = Package.t = @@ -125,51 +118,38 @@ end include T let equal a b = structural_compare a b = 0 -let ( = ) = equal -let ( < ) e e' = compare e e' < 0 -let ( <= ) e e' = compare e e' <= 0 -let ( > ) e e' = compare e e' > 0 -let ( >= ) e e' = compare e e' >= 0 module Set = Set.Make (T) -let pprint { name; _ } = - let open PPrint in - !^name - (** Array of elts. For use in functors that require a type [t] and not ['a t].*) module Array = struct type elt = t type nonrec t = t array - let is_empty arr = Int.(Array.length arr = 0) + let is_empty arr = Array.length arr = 0 let of_list arr = let arr = Array.of_list arr in Array.sort compare arr ; arr - - let pprint_elt = pprint - - let pprint arr = - let open PPrint in - braces @@ flow (break 1) (arr |> Array.map pprint |> Array.to_list) end let pkg_link { pkg; _ } = - let open Option.O in - let+ { name; version } = pkg in - Printf.sprintf "https://ocaml.org/p/%s/%s" name version + match pkg with + | None -> None + | Some { name; version } -> + Some (Printf.sprintf "https://ocaml.org/p/%s/%s" name version) let link t = - let open Option.O in - let name, path = - match List.rev (String.split_on_char '.' t.name) with - | name :: path -> name, String.concat "/" (List.rev path) - | _ -> "", "" - in - let+ pkg_link = pkg_link t in - pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name + match pkg_link t with + | None -> None + | Some pkg_link -> + let name, path = + match List.rev (String.split_on_char '.' t.name) with + | name :: path -> name, String.concat "/" (List.rev path) + | _ -> "", "" + in + Some (pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name) let v ~name ~kind ~score ~rhs ~doc_html ~url ?(pkg = None) () = { name; kind; url; score; doc_html; pkg; rhs } diff --git a/db/occ.ml b/db/occ.ml index 5cfe859008..512a37aabe 100644 --- a/db/occ.ml +++ b/db/occ.ml @@ -1,26 +1,15 @@ -type t = Elt.Array.t Int.Map.t +module Int_map = Map.Make (Int) + +type t = Elt.Array.t Int_map.t type elt = int * Elt.t -let is_empty = Int.Map.is_empty +let is_empty = Int_map.is_empty let of_list li = List.fold_left (fun acc (count, elt) -> - match Int.Map.find_opt count acc with - | None -> Int.Map.add count (Elt.Set.singleton elt) acc - | Some set -> Int.Map.add count (Elt.Set.add elt set) acc) - Int.Map.empty li - |> Int.Map.map (fun set -> set |> Elt.Set.to_seq |> Array.of_seq) - -let pprint_elt (count, elt) = - let open PPrint in - OCaml.int count ^^ space ^^ Elt.pprint elt - -let pprint t = - let open PPrint in - Int.Map.fold - (fun i arr doc -> - group - @@ group (parens (OCaml.int i ^^ space ^^ align (Elt.Array.pprint arr))) - ^^ break 1 ^^ doc) - t empty + match Int_map.find_opt count acc with + | None -> Int_map.add count (Elt.Set.singleton elt) acc + | Some set -> Int_map.add count (Elt.Set.add elt set) acc) + Int_map.empty li + |> Int_map.map (fun set -> set |> Elt.Set.to_seq |> Array.of_seq) diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index b80aac6a86..c6d222e630 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -4,8 +4,6 @@ module type SET = sig val of_list : elt list -> t val is_empty : t -> bool - val pprint : t -> PPrint.document - val pprint_elt : elt -> PPrint.document end module Doc = struct @@ -30,17 +28,24 @@ module Buf = struct (** This module allows to construct a big string such that if you add the same string twice, the second addition is not performed. *) + module String_hashtbl = Hashtbl.Make (struct + type t = string + + let equal = String.equal + let hash = Hashtbl.hash + end) + type t = { buffer : Buffer.t - ; cache : int String.Hashtbl.t + ; cache : int String_hashtbl.t } - let make () = { buffer = Buffer.create 16; cache = String.Hashtbl.create 16 } + let make () = { buffer = Buffer.create 16; cache = String_hashtbl.create 16 } let contents t = Buffer.contents t.buffer let get t i = Buffer.nth t.buffer i let add { buffer; cache } substr = - match String.Hashtbl.find_opt cache substr with + match String_hashtbl.find_opt cache substr with | Some start -> start | None -> let start = Buffer.length buffer in @@ -48,7 +53,7 @@ module Buf = struct let stop = Buffer.length buffer in assert (stop - start = String.length substr) ; for idx = 1 to String.length substr - 1 do - String.Hashtbl.add cache + String_hashtbl.add cache (String.sub substr idx (String.length substr - idx)) (start + idx) done ; @@ -84,12 +89,14 @@ module Make (S : SET) = struct end) end + module Char_map = Map.Make (Char) + type node = { mutable start : int ; mutable len : int ; mutable suffix_link : node option ; mutable terminals : Terminals.t - ; mutable children : node Char.Map.t + ; mutable children : node Char_map.t } type writer = @@ -102,7 +109,7 @@ module Make (S : SET) = struct ; len = 0 ; suffix_link = None ; terminals = Terminals.empty - ; children = Char.Map.empty + ; children = Char_map.empty } let make () = { root = make_root (); buffer = Buf.make () } @@ -114,7 +121,7 @@ module Make (S : SET) = struct ; len ; suffix_link = None ; terminals = Terminals.empty - ; children = Char.Map.singleton split_chr node + ; children = Char_map.singleton split_chr node } in node.start <- node.start + len + 1 ; @@ -150,7 +157,7 @@ module Make (S : SET) = struct ; len ; suffix_link = None ; terminals = Terminals.singleton doc.Doc.uid - ; children = Char.Map.empty + ; children = Char_map.empty } let set_suffix_link ~prev ~depth node = @@ -210,7 +217,7 @@ module Make (S : SET) = struct follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i end | Char chr -> begin - match Char.Map.find chr node.children with + match Char_map.find chr node.children with | child -> assert (depth >= 0) ; assert (i - depth >= 0) ; @@ -222,12 +229,12 @@ module Make (S : SET) = struct assert (i < Doc.length doc) ; if len = child.len then - if not (Char.Map.is_empty child.children) + if not (Char_map.is_empty child.children) then go ~prev ~prev_leaf ~depth child i else add_leaf ~prev_leaf ~node ~child ~depth ~i ~len else begin let new_child = split_at ~str:trie.buffer child len in - node.children <- Char.Map.add chr new_child node.children ; + node.children <- Char_map.add chr new_child node.children ; let prev = set_suffix_link ~prev ~depth new_child in assert (prev = None) ; add_leaf ~prev_leaf ~node ~child:new_child ~depth ~i ~len @@ -236,7 +243,7 @@ module Make (S : SET) = struct let new_leaf = make_leaf ~prev_leaf ~buffer:trie.buffer ~doc i in - node.children <- Char.Map.add chr new_leaf node.children ; + node.children <- Char_map.add chr new_leaf node.children ; let prev_leaf = set_leaf ~debug:"1" ~prev_leaf ~depth:(depth + Doc.length doc - i) @@ -291,7 +298,7 @@ module Make (S : SET) = struct | None -> None | Some (t, depth) -> Some (t, depth, Terminals.empty) in - child.children <- Char.Map.add new_chr new_leaf child.children ; + child.children <- Char_map.add new_chr new_leaf child.children ; let prev = Some (child, depth - 1) in let i, depth = i - len, depth - len in follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i @@ -379,9 +386,7 @@ module Make (S : SET) = struct let child = find ~str:t.str t.t pattern 0 in { str = t.str; t = child } - let find t pattern = - print_endline pattern; - try Some (find t pattern) with Not_found -> None + let find t pattern = try Some (find t pattern) with Not_found -> None let rec collapse acc t = let acc = if S.is_empty t.terminals then acc else t.terminals :: acc in @@ -402,8 +407,8 @@ module Make (S : SET) = struct export_terminals ~cache_term node.terminals in let children = - Char.Map.bindings - @@ Char.Map.map (export ~cache ~cache_term) node.children + Char_map.bindings + @@ Char_map.map (export ~cache ~cache_term) node.children in let children_uids = List.map (fun (chr, (uid, _)) -> chr, uid) children in let key = node.start, node.len, terminals_uid, children_uids in @@ -424,26 +429,10 @@ module Make (S : SET) = struct let cache_term = Terminals.Hashtbl.create 16 in let _, t = export ~cache ~cache_term t in { T.str; t } - - let pprint T.{ t; str } = - let open PPrint in - let rec node T.{ start; len; terminals; children } = - let start, len = if start = 0 then start, len else start - 1 , len + 1 in - OCaml.string (String.sub str start (len )) ^^ space - ^^ align (S.pprint terminals) ^^ break 1 - ^^ nest 4 - (group - (Array.fold_left - (fun doc n -> doc ^^ break 1 ^^ group (node n)) - (empty) children)) - in - node t end type reader = Automata.T.t - let pprint = Automata.pprint - let export t = let str = Buf.contents t.buffer in Automata.clear ~str t.root diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index f112f24c47..b01a07d3d6 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -4,8 +4,6 @@ module type SET = sig val of_list : elt list -> t val is_empty : t -> bool - val pprint : t -> PPrint.document - val pprint_elt : elt -> PPrint.document end module Make (S : SET) : sig @@ -22,7 +20,6 @@ module Make (S : SET) : sig val export : writer -> reader val find : reader -> string -> reader option val to_sets : reader -> S.t list - val pprint : reader -> PPrint.document end module With_elts : module type of Make (Elt.Array) diff --git a/db/types.ml b/db/types.ml index 3e6407d56f..358a7a2d21 100644 --- a/db/types.ml +++ b/db/types.ml @@ -1,3 +1,8 @@ +module String_list_map = Map.Make (struct + type t = string list + + let compare = List.compare String.compare +end) let regroup lst = String_list_map.bindings @@ -7,14 +12,6 @@ let regroup lst = String_list_map.add s (count + 1) acc) String_list_map.empty lst -let regroup_chars lst = - Char_list_map.bindings - @@ List.fold_left - (fun acc s -> - let count = try Char_list_map.find s acc with Not_found -> 0 in - Char_list_map.add s (count + 1) acc) - Char_list_map.empty lst - type sgn = | Pos | Neg diff --git a/index/index_lib.ml b/index/index_lib.ml index 47794bc92c..21d060440f 100644 --- a/index/index_lib.ml +++ b/index/index_lib.ml @@ -12,6 +12,6 @@ let main ~index_docstring ~index_name ~type_search ~index ~db_filename storage = let t0 = Unix.gettimeofday () in Load_doc.run ~index_docstring ~index_name ~type_search ~index ; let t1 = Unix.gettimeofday () in - Format.printf "Indexing in %fs@." (t1 -. t0) ; + Format.printf "Indexing in %fms@." (1000.0 *. (t1 -. t0)) ; flush () ; Storage.close_out h diff --git a/index/load_doc.ml b/index/load_doc.ml index 2cf1363133..09e98dfdcd 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -6,7 +6,6 @@ module Make (Storage : Db.Storage.S) = struct module Db = Db.Make (Storage) module ModuleName = Odoc_model.Names.ModuleName - let generic_cost ~ignore_no_doc name has_doc = String.length name (* + (5 * List.length path) TODO : restore depth based ordering *) @@ -67,43 +66,63 @@ module Make (Storage : Db.Storage.S) = struct (** for scoring *) let rec paths ~prefix ~sgn t = - let r = - match t with - | Odoc_model.Lang.TypeExpr.Var _ -> - let poly = "POLY" in - [ poly :: Types.string_of_sgn sgn :: prefix ] - | Any -> - let poly = "POLY" in - [ poly :: Types.string_of_sgn sgn :: prefix ] - | Arrow (_, a, b) -> - let prefix_left = "->0" :: prefix in - let prefix_right = "->1" :: prefix in - List.rev_append - (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) - (paths ~prefix:prefix_right ~sgn b) - | Constr (name, args) -> - let name = fullname name in - let prefix = name :: Types.string_of_sgn sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - paths ~prefix ~sgn arg) - args - end - | Tuple args -> - rev_concat - @@ List.mapi (fun i arg -> - let prefix = (string_of_int i ^ "*") :: prefix in - paths ~prefix ~sgn arg) - @@ args - | _ -> [] - in - r + match t with + | Odoc_model.Lang.TypeExpr.Var _ -> + let poly = "POLY" in + [ poly :: Types.string_of_sgn sgn :: prefix ] + | Any -> + let poly = "POLY" in + [ poly :: Types.string_of_sgn sgn :: prefix ] + | Arrow (_, a, b) -> + let prefix_left = "->0" :: prefix in + let prefix_right = "->1" :: prefix in + List.rev_append + (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) + (paths ~prefix:prefix_right ~sgn b) + | Constr (name, args) -> + let name = fullname name in + let prefix = name :: Types.string_of_sgn sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + paths ~prefix ~sgn arg) + args + end + | Tuple args -> + rev_concat + @@ List.mapi (fun i arg -> + let prefix = (string_of_int i ^ "*") :: prefix in + paths ~prefix ~sgn arg) + @@ args + | _ -> [] + + let hcons_tbl = Hashtbl.create 16 + let uid_generator = ref 0 + + let rec hcons = function + | [] -> -1, [] + | x :: xs -> ( + let uid_xs, xs = hcons xs in + match Hashtbl.find hcons_tbl (uid_xs, x) with + | xxs -> xxs + | exception Not_found -> + let uid = !uid_generator in + uid_generator := uid + 1 ; + let result = uid, x :: xs in + Hashtbl.add hcons_tbl (uid_xs, x) result ; + result) + + let paths typ = + List.map + (fun xs -> + let _, xs = hcons xs in + xs) + (paths ~prefix:[] ~sgn:Pos typ) (** for indexing *) let rec type_paths ~prefix ~sgn = function @@ -170,18 +189,14 @@ module Make (Storage : Db.Storage.S) = struct | TypeDecl _ -> Elt.Kind.TypeDecl | Module -> Elt.Kind.Module | Value { value = _; type_ } -> - let paths = paths ~prefix:[] ~sgn:Pos type_ in + let paths = paths type_ in Elt.Kind.val_ paths | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = paths ~prefix:[] ~sgn:Pos searchable_type in + let paths = paths searchable_type in Elt.Kind.constructor paths | Field { mutable_ = _; parent_type; type_ } -> - let paths = - type_ - |> searchable_type_of_record parent_type - |> paths ~prefix:[] ~sgn:Pos - in + let paths = type_ |> searchable_type_of_record parent_type |> paths in Elt.Kind.field paths | Doc _ -> Doc | Exception _ -> Exception @@ -191,12 +206,10 @@ module Make (Storage : Db.Storage.S) = struct | TypeExtension _ -> TypeExtension | ExtensionConstructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = paths ~prefix:[] ~sgn:Pos searchable_type in + let paths = paths searchable_type in Elt.Kind.extension_constructor paths | ModuleType -> ModuleType - let convert_kind k = k |> convert_kind (*|> Cache.Kind_.memo*) - let register_type_expr elt type_ = let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in Db.store_type_paths elt type_paths diff --git a/jsoo/dune b/jsoo/dune index d1727d5e14..37511c5483 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -1,4 +1,4 @@ (executable (name main) (modes js) - (libraries common tyxml query storage_js brr checkseum.ocaml odoc.search)) + (libraries tyxml query storage_js brr checkseum.ocaml odoc.search)) diff --git a/common/array.ml b/query/array_succ.ml similarity index 72% rename from common/array.ml rename to query/array_succ.ml index 10557551ca..fc2ca98d6f 100644 --- a/common/array.ml +++ b/query/array_succ.ml @@ -1,14 +1,8 @@ -open Common_ -include Stdlib.Array - -let equal (a : 'a -> 'a -> bool) arr arr' = - if arr == arr' then true else length arr = length arr' && for_all2 a arr arr' - -let hash (a : 'a -> int) arr = Hashtbl.hash (map a arr) +let get = Array.get let rec succ_ge ~compare elt arr lo hi = let elt_lo = get arr lo in - if ge ~compare elt_lo elt + if compare elt_lo elt >= 0 then elt_lo else if lo = hi then (* in that case, above branch should have been triggered *) @@ -16,7 +10,7 @@ let rec succ_ge ~compare elt arr lo hi = else if lo = hi - 1 then ( let elt_hi = get arr hi in - assert (ge ~compare elt_hi elt) ; + assert (compare elt_hi elt >= 0) ; elt_hi) else let mid = (lo + hi) / 2 in @@ -29,17 +23,17 @@ let rec succ_ge ~compare elt arr lo hi = else succ_ge ~compare elt arr mid hi let succ_ge ~compare elt arr = - if length arr = 0 + if Array.length arr = 0 then None else - let lo = 0 and hi = length arr in - if not (ge ~compare (get arr (hi - 1)) elt) + let lo = 0 and hi = Array.length arr in + if not (compare (get arr (hi - 1)) elt >= 0) then None else Some (succ_ge ~compare elt arr lo hi) let rec succ_gt ~compare elt arr lo hi = let elt_lo = get arr lo in - if gt ~compare elt_lo elt + if compare elt_lo elt > 0 then elt_lo else if lo = hi then (* in that case, above branch should have been triggered *) @@ -48,7 +42,7 @@ let rec succ_gt ~compare elt arr lo hi = then ( (* lo is already checked above *) let elt_hi = get arr hi in - assert (gt ~compare elt_hi elt) ; + assert (compare elt_hi elt > 0) ; elt_hi) else let mid = (lo + hi) / 2 in @@ -61,11 +55,11 @@ let rec succ_gt ~compare elt arr lo hi = else succ_gt ~compare elt arr mid hi let succ_gt ~compare elt arr = - if length arr = 0 + if Array.length arr = 0 then None else - let lo = 0 and hi = length arr in - if not (gt ~compare (get arr (hi - 1)) elt) + let lo = 0 and hi = Array.length arr in + if not (compare (get arr (hi - 1)) elt > 0) then None else Some (succ_gt ~compare elt arr lo hi) diff --git a/query/dune b/query/dune index f7da7bb929..0b3ee71d72 100644 --- a/query/dune +++ b/query/dune @@ -1,6 +1,4 @@ (library -(flags - (:standard -open Common)) (name query) (libraries lwt re db)) diff --git a/query/query.ml b/query/query.ml index 91333c09ac..e2e426309e 100644 --- a/query/query.ml +++ b/query/query.ml @@ -5,7 +5,7 @@ module Storage = Db.Storage module Tree = Db.Suffix_tree.With_elts module Tree_occ = Db.Suffix_tree.With_occ open Db.Types -module Occ = Int.Map +module Occ = Db.Occ.Int_map let inter_list xs = List.fold_left Succ.inter Succ.all xs @@ -26,52 +26,6 @@ let collapse_trie t = (fun succ arr -> Succ.union succ (Succ.of_array arr)) Succ.empty -(*let rec collapse_trie_occ_polar ~parent_char ~polarity ~count t = - let open Tree in - match t with - | Leaf (_, leaf) -> - if parent_char = polarity then collapse_occ ~count leaf else Succ.empty - | Node { leaf = _; children; _ } -> - Char.Map.fold - (fun parent_char child acc -> - let res = - collapse_trie_occ_polar ~parent_char ~polarity ~count child - in - Succ.union acc res) - children Succ.empty - - - let collapse_trie_occ_polar ~polarity ~count t = - let open Tree in - match t with - | Leaf _ -> Succ.empty - | Node { leaf = _; children; _ } -> - Char.Map.fold - (fun parent_char child acc -> - let res = - collapse_trie_occ_polar ~parent_char ~polarity ~count child - in - Succ.union acc res) - children Succ.empty - - let collapse_trie_with_poly ~count name t = - match name with - | [ "POLY"; ("+" | "-") ] -> begin - match t with - | Tree.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s - | _ -> Succ.empty - end - | _ -> collapse_trie_occ ~count t - - let _collapse_trie_with_poly_polar ~polarity ~count name t = - match name with - | [ "POLY"; ("+" | "-") ] -> begin - match t with - | Tree.Leaf ([], s) | Node { leaf = Some s; _ } -> collapse_occ ~count s - | _ -> Succ.empty - end - | _ -> collapse_trie_occ_polar ~polarity ~count t -*) let find_types ~shards names = List.fold_left (fun acc shard -> @@ -83,25 +37,14 @@ let find_types ~shards names = let name' = String.concat "" name in match Tree_occ.find db name' with | Some trie -> collapse_trie_occ ~count trie - | None -> Succ.empty - (* - | Error (`Stopped_at (i, sub_trie)) -> - let name_str = name' |> List.to_seq |> String.of_seq in - if i = String.length name_str - 1 - then - let polarity = name_str.[i] in - match polarity with - | '-' | '+' -> - collapse_trie_occ_polar ~polarity ~count sub_trie - | _ -> Succ.empty - else Succ.empty*)) + | None -> Succ.empty) (regroup names) in Succ.union acc r) Succ.empty shards let find_names ~(shards : Db.t list) names = - let names = List.map (fun n -> (*String.rev *)(String.lowercase_ascii n)) names in + let names = List.map String.lowercase_ascii names in List.fold_left (fun acc shard -> let db_names = shard.db_names in diff --git a/query/succ.ml b/query/succ.ml index bfd1a2a386..c0101c0a39 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,6 +1,5 @@ open Db - type s = | All | Empty @@ -47,7 +46,7 @@ let rec succ_ge elt = function | All -> elt | Empty -> raise Not_found | Array s -> - let out = Array.succ_ge_exn ~compare:Elt.compare elt s in + let out = Array_succ.succ_ge_exn ~compare:Elt.compare elt s in begin match Elt.compare elt out with | 0 -> elt @@ -77,7 +76,7 @@ let rec succ_ge elt = function let rec succ_gt elt = function | All -> invalid_arg "Succ.succ_gt All" | Empty -> raise Not_found - | Array s -> Array.succ_gt_exn ~compare:Elt.compare elt s + | Array s -> Array_succ.succ_gt_exn ~compare:Elt.compare elt s | Inter (a, _b) -> succ_gt elt a | Union (a, b) -> begin match succ_gt_opt elt a, succ_gt_opt elt b with diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 9e1f5efc41..de417f8d9b 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -3,7 +3,6 @@ 5.1M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') Warning, resolved hidden path: Base__.Int63_emul.t - Index_lib.main Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t @@ -50,15 +49,10 @@ Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t - Indexing in 3.984759s - trie_with_array_occ:0.18s - trie_with_array:0.09s - Cache.Elt_array_occ_trie.memo:0.92s - Cache.Elt_array_trie.memo:1.02s - - real 0m6.693s - user 0m6.558s - sys 0m0.106s + Indexing in 658.329010ms + Export in 614.521980ms + 1.60user 0.05system 0:01.65elapsed 100%CPU (0avgtext+0avgdata 190028maxresident)k + 0inputs+6408outputs (0major+52927minor)pagefaults 0swaps $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null @@ -71,8 +65,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2896 db.js - 2184 db.js.gz + 3200 db.js + 2412 db.js.gz 1628 megaodocl.gz diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index a3f1ffc2b2..ccc6d0c1ff 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,382 +7,8 @@ $ du -sh megaodocl 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.000959s - "" {page page page page page page Main Main.foo Main.unique_name Main.multiple_hit_1 - Main.multiple_hit_2 Main.multiple_hit_3 Main.name_conflict Main.name_conflict Main.Nest - Main.Nest.nesting_priority Main.nesting_priority Main.Map Main.Map.to_list Main.list Main.List - Main.List.t Main.List.map Main.foo Main.moo Main.t Main.value Main.consume Main.consume_2 - Main.consume_2_other Main.produce Main.produce_2' Main.Modtype Main.Modtype.v_modtype Main.S - Main.S_to_S1 Main.poly_1 Main.poly_2 Main.boo Main.poly_param Main.extensible_type - Main.MyExtension} - - "" {Main.produce_2'} - "" {} - - "oo" {Main.boo} - "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "xtensible_type" {Main.extensible_type} - "oo" {Main.foo Main.foo} - "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} - "" {} - - "p" {Main.Map Main.List.map} "to_list" {Main.Map.to_list} - "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} - "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "extension" {Main.MyExtension} - "" {} - - "me_conflict" {Main.name_conflict Main.name_conflict} - "st" {Main.Nest} - - "nesting_priority" {Main.Nest.nesting_priority} - "ng_priority" {Main.Nest.nesting_priority Main.nesting_priority} - "" {} - - "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} - "oduce" {Main.produce} "2'" {Main.produce_2'} - "" {Main.S} "to_s1" {Main.S_to_S1} - "" {Main.List.t Main.t} "_list" {Main.Map.to_list} - "nique_name" {Main.unique_name} - "" {} "modtype" {Main.Modtype.v_modtype} "lue" {Main.value} - "" {Main.multiple_hit_1 Main.S_to_S1 Main.poly_1} - "" {Main.multiple_hit_2 Main.consume_2 Main.poly_2} - "" {Main.produce_2'} "other" {Main.consume_2_other} - "" {Main.multiple_hit_3} - "" {} - - "" {Main.multiple_hit_1 Main.poly_1} - "" {Main.multiple_hit_2 Main.consume_2 Main.poly_2} - "" {Main.produce_2'} "other" {Main.consume_2_other} - "" {Main.multiple_hit_3} - "onflict" {Main.name_conflict Main.name_conflict} - "it_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "ist" {Main.Map.to_list} - "odtype" {Main.Modtype.v_modtype} - "ame" {Main.unique_name} - "ther" {Main.consume_2_other} - "" {} "ram" {Main.poly_param} "iority" {Main.Nest.nesting_priority Main.nesting_priority} - "1" {Main.S_to_S1} - "" {} "_s1" {Main.S_to_S1} "pe" {Main.extensible_type} - "" {page page page Main.foo} - - "raph" {page} - "n" {Main} - - "" {} - - "oo" {Main.boo} - "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "xtensible_type" {Main.extensible_type} - "oo" {Main.foo Main.foo} - "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} - "" {} - - "p" {Main.Map} "to_list" {Main.Map.to_list} - "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} - "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "extension" {Main.MyExtension} - "" {} - - "me_conflict" {Main.name_conflict Main.name_conflict} - "st" {Main.Nest} - "nesting_priority" {Main.Nest.nesting_priority} "ng_priority" {Main.nesting_priority} - "" {} - - "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} - "oduce" {Main.produce} "2'" {Main.produce_2'} - "" {Main.S} "to_s1" {Main.S_to_S1} - "" {Main.t} - "nique_name" {Main.unique_name} - "alue" {Main.value} - "ue" {Main.value} - "" {Main.poly_param} "" {Main.unique_name} "conflict" {Main.name_conflict Main.name_conflict} - "d" {page} - "" {Main.Map Main.List.map Main.foo} "to_list" {Main.Map.to_list} "" {page} - "a" {} "raph" {page} "" {Main.poly_param} - "im" {page} - "" {page} - "tim" {page} "" {} "_type" {Main.extensible_type} "b" {page} "ib" {page} "o" {Main.boo} - "" {} - - "" {Main.produce} "2'" {Main.produce_2'} - "" {} - - "e" {page} - "" {} - - "lict" {Main.name_conflict Main.name_conflict} - "ume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "" {Main.name_conflict Main.name_conflict} - "" {page} - - "" {page} - "ype" {Main.Modtype Main.Modtype.v_modtype} "v_modtype" {Main.Modtype.v_modtype} - "ce" {Main.produce} "2'" {Main.produce_2'} - "" {page page page Main.unique_name Main.value Main.consume Main.produce Main.Modtype - Main.Modtype.v_modtype Main.extensible_type} - - "v_modtype" {Main.Modtype.v_modtype} - "" {} - - "" {Main.consume_2} "" {Main.produce_2'} "other" {Main.consume_2_other} - "onflict" {Main.name_conflict Main.name_conflict} - "it_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "ame" {Main.unique_name} - "ype" {Main.extensible_type} - "si" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} - "" {Main.consume_2_other} "atim" {page} - "t" {Main.Nest} - - "nesting_priority" {Main.Nest.nesting_priority} - "ng_priority" {Main.Nest.nesting_priority Main.nesting_priority} - "tensi" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} - "" {page} "ict" {Main.name_conflict Main.name_conflict} "o" {Main.foo Main.foo} - "" {} "priority" {Main.Nest.nesting_priority Main.nesting_priority} "aph" {page} "" {page} - "" {page} - - "r" {Main.consume_2_other} - "" {} - - "gs" {page} - "" {Main.foo} - "_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "" {} - - "" {page} "" {} "_type" {Main.extensible_type} "b" {page} - "t" {Main.name_conflict Main.name_conflict} - "" {page} - "" {Main} - - "" {} - - "oo" {Main.boo} - "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "xtensible_type" {Main.extensible_type} - "oo" {Main.foo Main.foo} - "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} - "" {} - - "p" {Main.Map} "to_list" {Main.Map.to_list} - "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} - "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "extension" {Main.MyExtension} - "" {} - - "me_conflict" {Main.name_conflict Main.name_conflict} - "st" {Main.Nest} - "nesting_priority" {Main.Nest.nesting_priority} "ng_priority" {Main.nesting_priority} - "" {} - - "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} - "oduce" {Main.produce} "2'" {Main.produce_2'} - "" {Main.S} "to_s1" {Main.S_to_S1} - "" {Main.t} - "nique_name" {Main.unique_name} - "alue" {Main.value} - "" {} "priority" {Main.Nest.nesting_priority Main.nesting_priority} "" {page} - "" {} "" {Main.MyExtension} "ity" {Main.Nest.nesting_priority Main.nesting_priority} - "le_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "ue_name" {Main.unique_name} - "" {Main.foo} - - "" {page Main.Map.to_list Main.list Main.List Main.foo} - "" {} "ap" {Main.List.map} "" {Main.List.t} - "" {} - - "" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "e" {page} - "" {Main.Nest.nesting_priority Main.nesting_priority} - "" {} - - "" {page} - - "" {} - - "it_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "ype" {Main.extensible_type} - "" {} - - "" {page} "ib" {page} - "t" {Main.name_conflict Main.name_conflict} - "t" {page Main.Map.to_list Main.list Main.List Main.foo} - "" {} "ap" {Main.List.map} "" {Main.List.t} - "iple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "e" {Main.value} - "_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} - "" {page Main.poly_param} - - "" {} - - "n" {Main} - - "" {} - - "oo" {Main.boo} - "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "xtensible_type" {Main.extensible_type} - "oo" {Main.foo Main.foo} - "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} - "" {} - - "p" {Main.Map} "to_list" {Main.Map.to_list} - "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} - "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "extension" {Main.MyExtension} - "" {} - - "me_conflict" {Main.name_conflict Main.name_conflict} - "st" {Main.Nest} - "nesting_priority" {Main.Nest.nesting_priority} "ng_priority" {Main.nesting_priority} - "" {} - - "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} - "oduce" {Main.produce} "2'" {Main.produce_2'} - "" {Main.S} "to_s1" {Main.S_to_S1} - "" {Main.t} - "nique_name" {Main.unique_name} - "alue" {Main.value} - "" {Main.Map Main.List.map Main.foo} "to_list" {Main.Map.to_list} - "" {page Main.unique_name Main.consume} - - "" {} - - "" {Main.consume_2} "other" {Main.consume_2_other} - "onflict" {Main.name_conflict Main.name_conflict} - "" {} - - "type" {Main.Modtype Main.Modtype.v_modtype} "v_modtype" {Main.Modtype.v_modtype} - "" {Main.moo} - "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "extension" {Main.MyExtension} - "" {Main Main.MyExtension} - - "" {} - - "oo" {Main.boo} - "onsume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "xtensible_type" {Main.extensible_type} - "oo" {Main.foo Main.foo} - "ist" {Main.list Main.List} "" {} "ap" {Main.List.map} "" {Main.List.t} - "" {} - - "p" {Main.Map} "to_list" {Main.Map.to_list} - "" {} "type" {Main.Modtype} "v_modtype" {Main.Modtype.v_modtype} "" {Main.moo} - "ltiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "extension" {Main.MyExtension} - "" {} - - "me_conflict" {Main.name_conflict Main.name_conflict} - "st" {Main.Nest} - "nesting_priority" {Main.Nest.nesting_priority} "ng_priority" {Main.nesting_priority} - "" {} - - "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} - "oduce" {Main.produce} "2'" {Main.produce_2'} - "" {Main.S} "to_s1" {Main.S_to_S1} - "" {Main.t} - "nique_name" {Main.unique_name} - "alue" {Main.value} - "me" {Main.unique_name} "conflict" {Main.name_conflict Main.name_conflict} - "" {page} - "st" {Main.Nest} - - "nesting_priority" {Main.Nest.nesting_priority} - "ng_priority" {Main.Nest.nesting_priority Main.nesting_priority} - "lict" {Main.name_conflict Main.name_conflict} - "" {} "priority" {Main.Nest.nesting_priority Main.nesting_priority} "" {page} - "que_name" {Main.unique_name} - "" {} "" {Main.foo} "" {Main.foo} - "" {} - - "" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} - "me" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "" {Main.foo Main.foo Main.moo Main.boo} - - "" {} "ist" {Main.Map.to_list} "1" {Main.S_to_S1} - "" {} - - "" {page} - "ype" {Main.Modtype Main.Modtype.v_modtype} "v_modtype" {Main.Modtype.v_modtype} - "ce" {Main.produce} "2'" {Main.produce_2'} - "" {page} - "y_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} - "e" {page} - "" {Main.MyExtension} - - "lict" {Main.name_conflict Main.name_conflict} - "ume" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "" {Main.foo Main.foo Main.moo Main.boo} - "" {Main.foo} "ty" {Main.Nest.nesting_priority Main.nesting_priority} - "" {Main.foo} "er" {Main.consume_2_other} - "" {Main.Map Main.List.map Main.foo} - - "to_list" {Main.Map.to_list} - "ra" {} "raph" {page} "" {Main.poly_param} - "" {Main.Modtype Main.Modtype.v_modtype Main.extensible_type} - "v_modtype" {Main.Modtype.v_modtype} - "" {page} - "e_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "ly_" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} - "" {} - - "ority" {Main.Nest.nesting_priority Main.nesting_priority} - "duce" {Main.produce} "2'" {Main.produce_2'} - "ue_name" {Main.unique_name} - "" {Main.foo Main.consume_2_other} - - "" {} "raph" {page} "" {Main.poly_param} "h" {page} - "atim" {page} - "" {} - - "rity" {Main.Nest.nesting_priority Main.nesting_priority} - "y" {Main.Nest.nesting_priority Main.nesting_priority} - "duce" {Main.produce} "2'" {Main.produce_2'} - "" {page Main.foo Main.S} - - "" {Main.S_to_S1} - "to_s1" {Main.S_to_S1} - "" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} - "me" {page} - "" {page Main.Nest Main.Map.to_list Main.list Main.List Main.foo} - - "" {} "ap" {Main.List.map} "esting_priority" {Main.Nest.nesting_priority} "" {Main.List.t} - "ng_priority" {Main.Nest.nesting_priority Main.nesting_priority} - "me" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "" {page Main.name_conflict Main.name_conflict Main.Nest Main.Map.to_list Main.list Main.List - Main.List.t Main.foo Main.t} - - "" {} "ap" {Main.List.map} "esting_priority" {Main.Nest.nesting_priority} "" {Main.List.t} - "" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "nsi" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} - "" {} "r" {Main.consume_2_other} "" {} "gs" {page} "" {Main.foo} - "" {} - - "" {page} - "g_priority" {Main.Nest.nesting_priority Main.nesting_priority} - "le_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "le" {page} - "e" {page} - "_" {} "ist" {Main.Map.to_list} "1" {Main.S_to_S1} - "" {Main.Nest.nesting_priority Main.nesting_priority} - - "e" {Main.Modtype Main.Modtype.v_modtype Main.extensible_type} - "v_modtype" {Main.Modtype.v_modtype} - "" {} - - "e" {Main.produce} "2'" {Main.produce_2'} - "" {Main.value} "name" {Main.unique_name} - "tiple_hit_" {} "" {Main.multiple_hit_1} "" {Main.multiple_hit_2} "" {Main.multiple_hit_3} - "e" {Main.consume} "2" {Main.consume_2} "other" {Main.consume_2_other} - "ique_name" {Main.unique_name} - "" {} "modtype" {Main.Modtype.v_modtype} "lue" {Main.value} "rbatim" {page} - "tensi" {} "le_type" {Main.extensible_type} "n" {Main.MyExtension} - "" {Main.Nest.nesting_priority Main.nesting_priority} - - "" {} "" {Main.poly_1} "" {Main.poly_2} "aram" {Main.poly_param} - "xtension" {Main.MyExtension} - "e" {Main.Modtype Main.Modtype.v_modtype Main.extensible_type} - "v_modtype" {Main.Modtype.v_modtype} + Indexing in 1.405954ms + Export in 0.463009ms $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" val Main.unique_name : foo @@ -394,15 +20,25 @@ type Main.name_conflict = foo val Main.name_conflict : foo $ sherlodoc "nesting_priority" - [No results] + val Main.nesting_priority : foo + val Main.Nest.nesting_priority : foo $ sherlodoc --print-cost "list" + 109 mod Main.List + 209 type Main.list 315 type Main.List.t = 'a list 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 319 val Main.Map.to_list : foo + 1108 val Main.foo : foo + 1154 doc page $ sherlodoc --print-cost "map" 108 mod Main.Map + 213 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t 320 val Main.Map.to_list : foo + 1108 val Main.foo : foo $ sherlodoc --print-cost "list map" - [No results] + 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 423 val Main.Map.to_list : foo + 2108 val Main.foo : foo $ sherlodoc --print-cost ":moo" 210 val Main.value : moo 213 val Main.produce : unit -> moo @@ -416,15 +52,22 @@ 112 sig Main.Modtype 325 val Main.Modtype.v_modtype : foo $ sherlodoc --print-cost "S" + 106 sig Main.S + 216 mod Main.List + 216 mod Main.Nest 216 mod Main.S_to_S1 + 316 type Main.list 318 type Main.List.t = 'a list 319 val Main.consume : moo -> unit 320 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t 321 val Main.consume_2 : moo -> moo -> unit + 323 val Main.Map.to_list : foo 327 val Main.consume_2_other : moo -> t -> unit 327 type Main.extensible_type = .. + 328 val Main.nesting_priority : foo 333 val Main.Nest.nesting_priority : foo 373 cons Main.MyExtension : moo -> extensible_type + 1108 val Main.foo : foo 1154 doc page $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" [No results] diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index d858e2d460..d97d83a3cb 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -7,12 +7,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Index_lib.main - Indexing in 0.000579s - trie_with_array_occ:0.00s - trie_with_array:0.00s - Cache.Elt_array_occ_trie.memo:0.00s - Cache.Elt_array_trie.memo:0.00s + Indexing in 0.602961ms + Export in 0.049114ms $ export SHERLODOC_DB=db.bin TODO : get a result for the query bellow $ sherlodoc ":'a" diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index f62250226a..7f8aed977d 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,34 +5,10 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.000103s - "" {Main Main.List Main.list Main.List.t Main.List.map} - - "." {} - - "list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} - "map" {Main.List.map} - "t" {Main.List.t} - "a" {} - - "in" {Main} ".list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} - "p" {Main.List.map} - "i" {} - - "n" {Main} ".list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} - "st" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} - "list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} - "ma" {} - - "in" {Main} ".list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} - "p" {Main.List.map} - "n" {Main} ".list" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} - "p" {Main.List.map} - "st" {Main.List Main.list} "." {} "map" {Main.List.map} "t" {Main.List.t} - "t" {Main.List Main.list Main.List.t} "." {} "map" {Main.List.map} "t" {Main.List.t} + Indexing in 0.160933ms + Export in 0.089884ms $ export SHERLODOC_DB=db.bin $ sherlodoc --print-cost "list" - list 109 mod Main.List 209 type Main.list 315 type Main.List.t = 'a list diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 0d381d4e7c..398676b253 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -7,19 +7,11 @@ $ du -sh megaodocl 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - Index_lib.main - Indexing in 0.002069s - trie_with_array_occ:0.00s - trie_with_array:0.00s - Cache.Elt_array_occ_trie.memo:0.00s - Cache.Elt_array_trie.memo:0.00s + Indexing in 0.874996ms + Export in 0.494003ms $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null - Index_lib.main - Indexing in 0.001399s - trie_with_array_occ:0.00s - trie_with_array:0.00s - Cache.Elt_array_occ_trie.memo:0.00s - Cache.Elt_array_trie.memo:0.00s + Indexing in 0.792980ms + Export in 0.483990ms $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -31,7 +23,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 12 db.js + 8 db.js 8 db.js.gz 8 megaodocl.gz @@ -43,7 +35,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cat db.js ../../../jsoo/main.bc.js > html/index.js $ cp sherlodoc_db.bin html $ du -sh html/index.js - 13M html/index.js + 12M html/index.js $ ls html Main fonts diff --git a/www/dune b/www/dune index cc56b73a47..d2c4eff609 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,3 @@ (executable (name www) - (libraries cmdliner dream db query storage_ancient storage_marshal)) + (libraries cmdliner dream tyxml db query storage_ancient storage_marshal)) From 2cda1ab59ed0f0862eb7c48fdec22f3ab58d2ff0 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 25 Jun 2023 19:37:11 +0200 Subject: [PATCH 102/285] tokenize docstring --- db/db.ml | 4 +--- index/load_doc.ml | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/db/db.ml b/db/db.ml index ffee44fea4..a20ccb797c 100644 --- a/db/db.ml +++ b/db/db.ml @@ -43,9 +43,7 @@ module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct store ~count word elt) (regroup paths) - let store_word word elt = - let word = word |> String.lowercase_ascii in - Suffix_tree.With_elts.add_suffixes db_names word elt + let store_word word elt = Suffix_tree.With_elts.add_suffixes db_names word elt end module Storage = Storage diff --git a/index/load_doc.ml b/index/load_doc.ml index 09e98dfdcd..abec0de146 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -155,9 +155,30 @@ module Make (Storage : Db.Storage.S) = struct let type_paths ~prefix ~sgn t = type_paths ~prefix ~sgn t + let with_tokenizer str fn = + let str = String.lowercase_ascii str in + let buf = Buffer.create 16 in + let flush () = + let word = Buffer.contents buf in + if word <> "" then fn word ; + Buffer.clear buf + in + let rec go i = + if i >= String.length str + then flush () + else + let chr = str.[i] in + if (chr >= 'a' && chr <= 'z') + || (chr >= '0' && chr <= '9') + || chr = '_' || chr = '@' + then Buffer.add_char buf chr + else flush () ; + go (i + 1) + in + go 0 + let register_doc elt doc_txt = - let doc_words = String.split_on_char ' ' doc_txt in - List.iter (fun word -> Db.store_word word elt) doc_words + with_tokenizer doc_txt @@ fun word -> Db.store_word word elt let register_full_name name elt = let name = String.lowercase_ascii name in From 7fe96354929b5bdcf18e2934684caaa1d67dc780 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 25 Jun 2023 19:55:29 +0200 Subject: [PATCH 103/285] db without storage functor --- db/db.ml | 76 +++---- db/db.mli | 18 +- db/types.ml | 4 +- index/index_lib.ml | 9 +- index/load_doc.ml | 518 ++++++++++++++++++++++----------------------- index/load_doc.mli | 18 +- 6 files changed, 311 insertions(+), 332 deletions(-) diff --git a/db/db.ml b/db/db.ml index a20ccb797c..2ef928563f 100644 --- a/db/db.ml +++ b/db/db.ml @@ -3,47 +3,39 @@ module Types = Types module Storage_toplevel = Storage module Suffix_tree = Suffix_tree module Occ = Occ +module Storage = Storage include Types -module type S = sig - type writer - - val export : writer -> unit - val store_type_paths : Elt.t -> string list list -> unit - val store_word : string -> Elt.t -> unit - val load_counter : int ref -end - -module Make (Storage : Storage.S) : S with type writer = Storage.writer = struct - type writer = Storage.writer - - let load_counter = ref 0 - let db_types = Suffix_tree.With_occ.make () - let db_names = Suffix_tree.With_elts.make () - - let export h = - load_counter := 0 ; - let t0 = Unix.gettimeofday () in - let db = - { db_types = Suffix_tree.With_occ.export db_types - ; db_names = Suffix_tree.With_elts.export db_names - } - in - let t1 = Unix.gettimeofday () in - Format.printf "Export in %fms@." (1000.0 *. (t1 -. t0)) ; - Storage.save ~db:h db - - let store name elt ~count = - Suffix_tree.With_occ.add_suffixes db_types name (count, elt) - - let store_type_paths elt paths = - List.iter - (fun (path, count) -> - let word = String.concat "" path in - store ~count word elt) - (regroup paths) - - let store_word word elt = Suffix_tree.With_elts.add_suffixes db_names word elt -end - -module Storage = Storage +type writer = + { writer_names : Suffix_tree.With_elts.writer + ; writer_types : Suffix_tree.With_occ.writer + } + +let make () = + { writer_names = Suffix_tree.With_elts.make () + ; writer_types = Suffix_tree.With_occ.make () + } + +let export db = + let t0 = Unix.gettimeofday () in + let db = + { db_names = Suffix_tree.With_elts.export db.writer_names + ; db_types = Suffix_tree.With_occ.export db.writer_types + } + in + let t1 = Unix.gettimeofday () in + Format.printf "Export in %fms@." (1000.0 *. (t1 -. t0)) ; + db + +let store db name elt ~count = + Suffix_tree.With_occ.add_suffixes db.writer_types name (count, elt) + +let store_type_paths db elt paths = + List.iter + (fun (path, count) -> + let word = String.concat "" path in + store db ~count word elt) + (regroup paths) + +let store_word db word elt = + Suffix_tree.With_elts.add_suffixes db.writer_names word elt diff --git a/db/db.mli b/db/db.mli index c3e0c4e03f..994bcd466a 100644 --- a/db/db.mli +++ b/db/db.mli @@ -5,17 +5,13 @@ module Suffix_tree = Suffix_tree module Occ = Occ type t = Types.t = - { db_types : Suffix_tree.With_occ.reader - ; db_names : Suffix_tree.With_elts.reader + { db_names : Suffix_tree.With_elts.reader + ; db_types : Suffix_tree.With_occ.reader } -module type S = sig - type writer +type writer - val export : writer -> unit - val store_type_paths : Elt.t -> string list list -> unit - val store_word : string -> Elt.t -> unit - val load_counter : int ref -end - -module Make (Storage : Storage.S) : S with type writer = Storage.writer +val make : unit -> writer +val export : writer -> t +val store_type_paths : writer -> Elt.t -> string list list -> unit +val store_word : writer -> string -> Elt.t -> unit diff --git a/db/types.ml b/db/types.ml index 358a7a2d21..5b6730b95a 100644 --- a/db/types.ml +++ b/db/types.ml @@ -28,6 +28,6 @@ let sgn_not = function | Unknown -> Unknown type t = - { db_types : Suffix_tree.With_occ.reader - ; db_names : Suffix_tree.With_elts.reader + { db_names : Suffix_tree.With_elts.reader + ; db_types : Suffix_tree.With_occ.reader } diff --git a/index/index_lib.ml b/index/index_lib.ml index 21d060440f..0fad45e81d 100644 --- a/index/index_lib.ml +++ b/index/index_lib.ml @@ -2,15 +2,14 @@ module Storage = Db.Storage let main ~index_docstring ~index_name ~type_search ~index ~db_filename storage = let module Storage = (val storage : Storage.S) in - let module Load_doc = Load_doc.Make (Storage) in - let module Db = Load_doc.Db in + let db = Db.make () in let h = Storage.open_out db_filename in let flush () = - (* Load_doc.clear () ; *) - Db.export h + let t = Db.export db in + Storage.save ~db:h t in let t0 = Unix.gettimeofday () in - Load_doc.run ~index_docstring ~index_name ~type_search ~index ; + Load_doc.run ~db ~index_docstring ~index_name ~type_search ~index ; let t1 = Unix.gettimeofday () in Format.printf "Indexing in %fms@." (1000.0 *. (t1 -. t0)) ; flush () ; diff --git a/index/load_doc.ml b/index/load_doc.ml index abec0de146..baf61063f5 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -1,40 +1,37 @@ module Elt = Db.Elt module Db_common = Db +module Types = Db.Types +module ModuleName = Odoc_model.Names.ModuleName -module Make (Storage : Db.Storage.S) = struct - module Types = Db.Types - module Db = Db.Make (Storage) - module ModuleName = Odoc_model.Names.ModuleName +let generic_cost ~ignore_no_doc name has_doc = + String.length name + (* + (5 * List.length path) TODO : restore depth based ordering *) + + (if ignore_no_doc || has_doc then 0 else 100) + + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 - let generic_cost ~ignore_no_doc name has_doc = - String.length name - (* + (5 * List.length path) TODO : restore depth based ordering *) - + (if ignore_no_doc || has_doc then 0 else 100) - + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 +let type_cost paths = + paths |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 - let type_cost paths = - paths |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 +let kind_cost (kind : Elt.Kind.t) = + match kind with + | Constructor type_path | Field type_path | Val type_path -> + type_cost type_path + | Doc -> 400 + | TypeDecl | Module -> 0 + | Exception | Class_type | Method | Class | TypeExtension -> 1000 + | ExtensionConstructor _ | ModuleType -> 10 - let kind_cost (kind : Elt.Kind.t) = +let cost ~name ~kind ~doc_html = + let ignore_no_doc = match kind with - | Constructor type_path | Field type_path | Val type_path -> - type_cost type_path - | Doc -> 400 - | TypeDecl | Module -> 0 - | Exception | Class_type | Method | Class | TypeExtension -> 1000 - | ExtensionConstructor _ | ModuleType -> 10 + | Elt.Kind.Module | ModuleType -> true + | _ -> false + in + let has_doc = doc_html <> "" in + (* TODO : use entry cost *) + generic_cost ~ignore_no_doc name has_doc + kind_cost kind - let cost ~name ~kind ~doc_html = - let ignore_no_doc = - match kind with - | Elt.Kind.Module | ModuleType -> true - | _ -> false - in - let has_doc = doc_html <> "" in - (* TODO : use entry cost *) - generic_cost ~ignore_no_doc name has_doc + kind_cost kind - - (* +(* todo : check usefulness let rec type_size = function @@ -50,257 +47,256 @@ module Make (Storage : Db.Storage.S) = struct | _ -> 100 *) - let rev_concat lst = - List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst +let rev_concat lst = + List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst - let rec tails = function - | [] -> [] - | _ :: xs as lst -> lst :: tails xs +let rec tails = function + | [] -> [] + | _ :: xs as lst -> lst :: tails xs - let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) - let fullname t = Format.asprintf "%a" Pretty.show_type_name_verbose t +let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) +let fullname t = Format.asprintf "%a" Pretty.show_type_name_verbose t - let all_type_names t = - let fullname = fullname t in - tails (String.split_on_char '.' fullname) +let all_type_names t = + let fullname = fullname t in + tails (String.split_on_char '.' fullname) - (** for scoring *) - let rec paths ~prefix ~sgn t = - match t with - | Odoc_model.Lang.TypeExpr.Var _ -> - let poly = "POLY" in - [ poly :: Types.string_of_sgn sgn :: prefix ] - | Any -> - let poly = "POLY" in - [ poly :: Types.string_of_sgn sgn :: prefix ] - | Arrow (_, a, b) -> - let prefix_left = "->0" :: prefix in - let prefix_right = "->1" :: prefix in - List.rev_append - (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) - (paths ~prefix:prefix_right ~sgn b) - | Constr (name, args) -> - let name = fullname name in - let prefix = name :: Types.string_of_sgn sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - paths ~prefix ~sgn arg) - args - end - | Tuple args -> - rev_concat - @@ List.mapi (fun i arg -> - let prefix = (string_of_int i ^ "*") :: prefix in - paths ~prefix ~sgn arg) - @@ args - | _ -> [] +(** for scoring *) +let rec paths ~prefix ~sgn t = + match t with + | Odoc_model.Lang.TypeExpr.Var _ -> + let poly = "POLY" in + [ poly :: Types.string_of_sgn sgn :: prefix ] + | Any -> + let poly = "POLY" in + [ poly :: Types.string_of_sgn sgn :: prefix ] + | Arrow (_, a, b) -> + let prefix_left = "->0" :: prefix in + let prefix_right = "->1" :: prefix in + List.rev_append + (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) + (paths ~prefix:prefix_right ~sgn b) + | Constr (name, args) -> + let name = fullname name in + let prefix = name :: Types.string_of_sgn sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + paths ~prefix ~sgn arg) + args + end + | Tuple args -> + rev_concat + @@ List.mapi (fun i arg -> + let prefix = (string_of_int i ^ "*") :: prefix in + paths ~prefix ~sgn arg) + @@ args + | _ -> [] - let hcons_tbl = Hashtbl.create 16 - let uid_generator = ref 0 +let hcons_tbl = Hashtbl.create 16 +let uid_generator = ref 0 - let rec hcons = function - | [] -> -1, [] - | x :: xs -> ( - let uid_xs, xs = hcons xs in - match Hashtbl.find hcons_tbl (uid_xs, x) with - | xxs -> xxs - | exception Not_found -> - let uid = !uid_generator in - uid_generator := uid + 1 ; - let result = uid, x :: xs in - Hashtbl.add hcons_tbl (uid_xs, x) result ; - result) +let rec hcons = function + | [] -> -1, [] + | x :: xs -> ( + let uid_xs, xs = hcons xs in + match Hashtbl.find hcons_tbl (uid_xs, x) with + | xxs -> xxs + | exception Not_found -> + let uid = !uid_generator in + uid_generator := uid + 1 ; + let result = uid, x :: xs in + Hashtbl.add hcons_tbl (uid_xs, x) result ; + result) - let paths typ = - List.map - (fun xs -> - let _, xs = hcons xs in - xs) - (paths ~prefix:[] ~sgn:Pos typ) +let paths typ = + List.map + (fun xs -> + let _, xs = hcons xs in + xs) + (paths ~prefix:[] ~sgn:Pos typ) - (** for indexing *) - let rec type_paths ~prefix ~sgn = function - | Odoc_model.Lang.TypeExpr.Var _ -> - [ "POLY" :: Types.string_of_sgn sgn :: prefix ] - | Any -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] - | Arrow (_lbl, a, b) -> - List.rev_append - (type_paths ~prefix ~sgn:(Types.sgn_not sgn) a) - (type_paths ~prefix ~sgn b) - | Constr (name, args) -> - rev_concat - @@ List.map (fun name -> - let name = String.concat "." name in - let prefix = name :: Types.string_of_sgn sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - type_paths ~prefix ~sgn arg) - args - end) - @@ all_type_names name - | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args - | _ -> [] +(** for indexing *) +let rec type_paths ~prefix ~sgn = function + | Odoc_model.Lang.TypeExpr.Var _ -> + [ "POLY" :: Types.string_of_sgn sgn :: prefix ] + | Any -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] + | Arrow (_lbl, a, b) -> + List.rev_append + (type_paths ~prefix ~sgn:(Types.sgn_not sgn) a) + (type_paths ~prefix ~sgn b) + | Constr (name, args) -> + rev_concat + @@ List.map (fun name -> + let name = String.concat "." name in + let prefix = name :: Types.string_of_sgn sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + type_paths ~prefix ~sgn arg) + args + end) + @@ all_type_names name + | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args + | _ -> [] - let type_paths ~prefix ~sgn t = type_paths ~prefix ~sgn t +let type_paths ~prefix ~sgn t = type_paths ~prefix ~sgn t - let with_tokenizer str fn = - let str = String.lowercase_ascii str in - let buf = Buffer.create 16 in - let flush () = - let word = Buffer.contents buf in - if word <> "" then fn word ; - Buffer.clear buf - in - let rec go i = - if i >= String.length str - then flush () - else - let chr = str.[i] in - if (chr >= 'a' && chr <= 'z') - || (chr >= '0' && chr <= '9') - || chr = '_' || chr = '@' - then Buffer.add_char buf chr - else flush () ; - go (i + 1) - in - go 0 +let with_tokenizer str fn = + let str = String.lowercase_ascii str in + let buf = Buffer.create 16 in + let flush () = + let word = Buffer.contents buf in + if word <> "" then fn word ; + Buffer.clear buf + in + let rec go i = + if i >= String.length str + then flush () + else + let chr = str.[i] in + if (chr >= 'a' && chr <= 'z') + || (chr >= '0' && chr <= '9') + || chr = '_' || chr = '@' + then Buffer.add_char buf chr + else flush () ; + go (i + 1) + in + go 0 - let register_doc elt doc_txt = - with_tokenizer doc_txt @@ fun word -> Db.store_word word elt +let register_doc ~db elt doc_txt = + with_tokenizer doc_txt @@ fun word -> Db.store_word db word elt - let register_full_name name elt = - let name = String.lowercase_ascii name in - Db.store_word name elt +let register_full_name ~db name elt = + let name = String.lowercase_ascii name in + Db.store_word db name elt - let searchable_type_of_constructor args res = - let open Odoc_model.Lang in - match args with - | TypeDecl.Constructor.Tuple args -> ( - match args with - | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) - | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) - | _ -> res) - | TypeDecl.Constructor.Record fields -> - List.fold_left - (fun res field -> - let open TypeDecl.Field in - let field_name = Odoc_model.Paths.Identifier.name field.id in - TypeExpr.Arrow (Some (Label field_name), field.type_, res)) - res fields +let searchable_type_of_constructor args res = + let open Odoc_model.Lang in + match args with + | TypeDecl.Constructor.Tuple args -> ( + match args with + | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) + | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) + | _ -> res) + | TypeDecl.Constructor.Record fields -> + List.fold_left + (fun res field -> + let open TypeDecl.Field in + let field_name = Odoc_model.Paths.Identifier.name field.id in + TypeExpr.Arrow (Some (Label field_name), field.type_, res)) + res fields - let searchable_type_of_record parent_type type_ = - let open Odoc_model.Lang in - TypeExpr.Arrow (None, parent_type, type_) +let searchable_type_of_record parent_type type_ = + let open Odoc_model.Lang in + TypeExpr.Arrow (None, parent_type, type_) - let convert_kind (kind : Odoc_search.Entry.extra) = - let open Odoc_search.Entry in - match kind with - | TypeDecl _ -> Elt.Kind.TypeDecl - | Module -> Elt.Kind.Module - | Value { value = _; type_ } -> - let paths = paths type_ in - Elt.Kind.val_ paths - | Constructor { args; res } -> - let searchable_type = searchable_type_of_constructor args res in - let paths = paths searchable_type in - Elt.Kind.constructor paths - | Field { mutable_ = _; parent_type; type_ } -> - let paths = type_ |> searchable_type_of_record parent_type |> paths in - Elt.Kind.field paths - | Doc _ -> Doc - | Exception _ -> Exception - | Class_type _ -> Class_type - | Method _ -> Method - | Class _ -> Class - | TypeExtension _ -> TypeExtension - | ExtensionConstructor { args; res } -> - let searchable_type = searchable_type_of_constructor args res in - let paths = paths searchable_type in - Elt.Kind.extension_constructor paths - | ModuleType -> ModuleType +let convert_kind (kind : Odoc_search.Entry.extra) = + let open Odoc_search.Entry in + match kind with + | TypeDecl _ -> Elt.Kind.TypeDecl + | Module -> Elt.Kind.Module + | Value { value = _; type_ } -> + let paths = paths type_ in + Elt.Kind.val_ paths + | Constructor { args; res } -> + let searchable_type = searchable_type_of_constructor args res in + let paths = paths searchable_type in + Elt.Kind.constructor paths + | Field { mutable_ = _; parent_type; type_ } -> + let paths = type_ |> searchable_type_of_record parent_type |> paths in + Elt.Kind.field paths + | Doc _ -> Doc + | Exception _ -> Exception + | Class_type _ -> Class_type + | Method _ -> Method + | Class _ -> Class + | TypeExtension _ -> TypeExtension + | ExtensionConstructor { args; res } -> + let searchable_type = searchable_type_of_constructor args res in + let paths = paths searchable_type in + Elt.Kind.extension_constructor paths + | ModuleType -> ModuleType - let register_type_expr elt type_ = - let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in - Db.store_type_paths elt type_paths +let register_type_expr ~db elt type_ = + let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in + Db.store_type_paths db elt type_paths - let register_kind ~type_search elt (kind : Odoc_search.Entry.extra) = - let open Odoc_search.Entry in - let open Odoc_model.Lang in - if type_search - then - match kind with - | TypeDecl _ -> () - | Module -> () - | Value { value = _; type_ } -> register_type_expr elt type_ - | Doc _ -> () - | Exception _ -> () - | Class_type _ -> () - | Method _ -> () - | Class _ -> () - | TypeExtension _ -> () - | ModuleType -> () - | ExtensionConstructor { args; res } | Constructor { args; res } -> - let type_ = searchable_type_of_constructor args res in - register_type_expr elt type_ - | Field { mutable_ = _; parent_type; type_ } -> - let type_ = TypeExpr.Arrow (None, parent_type, type_) in - register_type_expr elt type_ +let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.extra) = + let open Odoc_search.Entry in + let open Odoc_model.Lang in + if type_search + then + match kind with + | TypeDecl _ -> () + | Module -> () + | Value { value = _; type_ } -> register_type_expr ~db elt type_ + | Doc _ -> () + | Exception _ -> () + | Class_type _ -> () + | Method _ -> () + | Class _ -> () + | TypeExtension _ -> () + | ModuleType -> () + | ExtensionConstructor { args; res } | Constructor { args; res } -> + let type_ = searchable_type_of_constructor args res in + register_type_expr ~db elt type_ + | Field { mutable_ = _; parent_type; type_ } -> + let type_ = TypeExpr.Arrow (None, parent_type, type_) in + register_type_expr ~db elt type_ - let register_entry ~index_name ~type_search ~index_docstring - Odoc_search.Entry. - { id : Odoc_model.Paths.Identifier.Any.t - ; doc : Odoc_model.Comment.docs - ; extra : extra - } = - let open Odoc_search in - let open Odoc_search.Entry in - let is_type_extension = +let register_entry ~db ~index_name ~type_search ~index_docstring + Odoc_search.Entry. + { id : Odoc_model.Paths.Identifier.Any.t + ; doc : Odoc_model.Comment.docs + ; extra : extra + } = + let open Odoc_search in + let open Odoc_search.Entry in + let is_type_extension = + match extra with + | TypeExtension _ -> true + | _ -> false + in + if Odoc_model.Paths.Identifier.is_internal id || is_type_extension + then () + else + let full_name = id |> Pretty.fullname |> String.concat "." in + let doc_txt = Render.text_of_doc doc in + let doc_html = + match doc_txt with + | "" -> "" + | _ -> doc |> Render.html_of_doc |> string_of_html + in + let kind' = convert_kind extra in + let name = match extra with - | TypeExtension _ -> true - | _ -> false + | Doc _ -> Pretty.prefixname id + | _ -> full_name in - if Odoc_model.Paths.Identifier.is_internal id || is_type_extension - then () - else - let full_name = id |> Pretty.fullname |> String.concat "." in - let doc_txt = Render.text_of_doc doc in - let doc_html = - match doc_txt with - | "" -> "" - | _ -> doc |> Render.html_of_doc |> string_of_html - in - let kind' = convert_kind extra in - let name = - match extra with - | Doc _ -> Pretty.prefixname id - | _ -> full_name - in - let score = cost ~name ~kind:kind' ~doc_html in - let rhs = Json_display.rhs_of_kind extra in - let url = Render.url id in - let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in - if index_docstring then register_doc elt doc_txt ; - (if index_name - then - match extra with - | Doc _ -> () - | _ -> register_full_name full_name elt) ; - register_kind ~type_search elt extra + let score = cost ~name ~kind:kind' ~doc_html in + let rhs = Json_display.rhs_of_kind extra in + let url = Render.url id in + let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in + if index_docstring then register_doc ~db elt doc_txt ; + (if index_name + then + match extra with + | Doc _ -> () + | _ -> register_full_name ~db full_name elt) ; + register_kind ~db ~type_search elt extra - module Resolver = Odoc_odoc.Resolver +module Resolver = Odoc_odoc.Resolver - let run ~index_docstring ~index_name ~type_search ~index = - List.iter (register_entry ~index_docstring ~index_name ~type_search) index -end +let run ~db ~index_docstring ~index_name ~type_search ~index = + List.iter (register_entry ~db ~index_docstring ~index_name ~type_search) index diff --git a/index/load_doc.mli b/index/load_doc.mli index 41da2655f2..d5bef99cb3 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -1,11 +1,7 @@ -module Make (Storage : Db.Storage.S) : sig - module Db : Db.S with type writer = Storage.writer - - - val run : - index_docstring:bool - -> index_name:bool - -> type_search:bool - -> index:Odoc_search.Entry.t list - -> unit -end +val run : + db:Db.writer + -> index_docstring:bool + -> index_name:bool + -> type_search:bool + -> index:Odoc_search.Entry.t list + -> unit From 0e5533633f9f93ad7a3a07d6e932f93339ec0b2f Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 25 Jun 2023 20:32:27 +0200 Subject: [PATCH 104/285] remove index_lib --- db/db.ml | 1 - index/index.ml | 53 ++++++++++++++++++++++++++++----------------- index/index_lib.ml | 16 -------------- index/index_lib.mli | 8 ------- index/load_doc.ml | 5 ----- index/load_doc.mli | 6 ++--- 6 files changed, 36 insertions(+), 53 deletions(-) delete mode 100644 index/index_lib.ml delete mode 100644 index/index_lib.mli diff --git a/db/db.ml b/db/db.ml index 2ef928563f..3bc6572240 100644 --- a/db/db.ml +++ b/db/db.ml @@ -1,6 +1,5 @@ module Elt = Elt module Types = Types -module Storage_toplevel = Storage module Suffix_tree = Suffix_tree module Occ = Occ module Storage = Storage diff --git a/index/index.ml b/index/index.ml index caa3650b5d..98bff5e656 100644 --- a/index/index.ml +++ b/index/index.ml @@ -1,25 +1,38 @@ +let index_file register filename = + match Fpath.of_string filename with + | Error (`Msg msg) -> Format.printf "FILE ERROR %s: %s@." filename msg + | Ok file -> ( + match + Odoc_odoc.Indexing.handle_file + ~page:(Odoc_model.Fold.page ~f:register ()) + ~unit:(Odoc_model.Fold.unit ~f:register ()) + file + with + | Ok (Some result) -> result + | Ok None -> () + | Error (`Msg msg) -> Format.printf "ODOC ERROR %s: %s@." filename msg) + +let storage_module = function + | `ancient -> (module Storage_ancient : Db.Storage.S) + | `marshal -> (module Storage_marshal : Db.Storage.S) + | `js -> (module Storage_js : Db.Storage.S) + let main files index_docstring index_name type_search db_filename db_format = - let index = files |> List.map Fpath.of_string |> List.map Result.get_ok in - let storage = - match db_format with - | `ancient -> (module Storage_ancient : Db.Storage.S) - | `marshal -> (module Storage_marshal : Db.Storage.S) - | `js -> (module Storage_js : Db.Storage.S) - in - let add_entries li e = Odoc_search.Entry.entries_of_item e @ li in - let index = - index - |> List.fold_left - (fun li file -> - file - |> Odoc_odoc.Indexing.handle_file - ~page:(Odoc_model.Fold.page ~f:add_entries li) - ~unit:(Odoc_model.Fold.unit ~f:add_entries li) - |> Result.get_ok |> Option.value ~default:[]) - [] + let module Storage = (val storage_module db_format) in + let db = Db.make () in + let register () item = + List.iter + (Load_doc.register_entry ~db ~index_docstring ~index_name ~type_search) + (Odoc_search.Entry.entries_of_item item) in - Index_lib.main ~index_docstring ~index_name ~type_search ~index ~db_filename - storage + let h = Storage.open_out db_filename in + let t0 = Unix.gettimeofday () in + List.iter (index_file register) files ; + let t1 = Unix.gettimeofday () in + Format.printf "Indexing in %fms@." (1000.0 *. (t1 -. t0)) ; + let t = Db.export db in + Storage.save ~db:h t ; + Storage.close_out h open Cmdliner diff --git a/index/index_lib.ml b/index/index_lib.ml deleted file mode 100644 index 0fad45e81d..0000000000 --- a/index/index_lib.ml +++ /dev/null @@ -1,16 +0,0 @@ -module Storage = Db.Storage - -let main ~index_docstring ~index_name ~type_search ~index ~db_filename storage = - let module Storage = (val storage : Storage.S) in - let db = Db.make () in - let h = Storage.open_out db_filename in - let flush () = - let t = Db.export db in - Storage.save ~db:h t - in - let t0 = Unix.gettimeofday () in - Load_doc.run ~db ~index_docstring ~index_name ~type_search ~index ; - let t1 = Unix.gettimeofday () in - Format.printf "Indexing in %fms@." (1000.0 *. (t1 -. t0)) ; - flush () ; - Storage.close_out h diff --git a/index/index_lib.mli b/index/index_lib.mli deleted file mode 100644 index 6aa4d2d560..0000000000 --- a/index/index_lib.mli +++ /dev/null @@ -1,8 +0,0 @@ -val main : - index_docstring:bool - -> index_name:bool - -> type_search:bool - -> index:Odoc_search.Entry.t list - -> db_filename:string - -> (module Db.Storage.S) - -> unit diff --git a/index/load_doc.ml b/index/load_doc.ml index baf61063f5..daa3301405 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -295,8 +295,3 @@ let register_entry ~db ~index_name ~type_search ~index_docstring | Doc _ -> () | _ -> register_full_name ~db full_name elt) ; register_kind ~db ~type_search elt extra - -module Resolver = Odoc_odoc.Resolver - -let run ~db ~index_docstring ~index_name ~type_search ~index = - List.iter (register_entry ~db ~index_docstring ~index_name ~type_search) index diff --git a/index/load_doc.mli b/index/load_doc.mli index d5bef99cb3..168ccc5edf 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -1,7 +1,7 @@ -val run : +val register_entry : db:Db.writer - -> index_docstring:bool -> index_name:bool -> type_search:bool - -> index:Odoc_search.Entry.t list + -> index_docstring:bool + -> Odoc_search.Entry.t -> unit From 56355c0458e34436b37ffd6349b5a85574d32104 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 25 Jun 2023 23:12:56 +0200 Subject: [PATCH 105/285] fix suffix_tree elt equality --- db/elt.ml | 8 +++++++- db/occ.ml | 11 +++++++++++ db/suffix_tree.ml | 5 +++-- db/suffix_tree.mli | 1 + 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/db/elt.ml b/db/elt.ml index cda0ceecb2..95414a5743 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -101,7 +101,11 @@ module T = struct match String.compare a.name b.name with | 0 -> begin match Option.compare compare_pkg a.pkg b.pkg with - | 0 -> Stdlib.compare a.kind b.kind + | 0 -> begin + match Stdlib.compare a.kind b.kind with + | 0 -> Stdlib.compare a.url b.url + | c -> c + end | c -> c end | c -> c @@ -132,6 +136,8 @@ module Array = struct let arr = Array.of_list arr in Array.sort compare arr ; arr + + let equal_elt = equal end let pkg_link { pkg; _ } = diff --git a/db/occ.ml b/db/occ.ml index 512a37aabe..cf5258bf8d 100644 --- a/db/occ.ml +++ b/db/occ.ml @@ -4,6 +4,17 @@ type t = Elt.Array.t Int_map.t type elt = int * Elt.t let is_empty = Int_map.is_empty +let equal_elt (a_count, a) (b_count, b) = a_count = b_count && Elt.equal a b + +(* +let of_list li = + List.fold_left + (fun acc (count, elt) -> + let elts = try Int_map.find count acc with Not_found -> [] in + Int_map.add count (elt :: elts) acc) + Int_map.empty li + |> Int_map.map Elt.Array.of_list +*) let of_list li = List.fold_left diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index c6d222e630..610d5fb2ad 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -4,6 +4,7 @@ module type SET = sig val of_list : elt list -> t val is_empty : t -> bool + val equal_elt : elt -> elt -> bool end module Doc = struct @@ -75,10 +76,10 @@ module Make (S : SET) = struct | _ -> x :: xs let hash = Hashtbl.hash - let equal = List.equal ( == ) + let equal = List.equal S.equal_elt let mem (x : S.elt) = function - | y :: _ -> x == y + | y :: _ -> S.equal_elt x y | _ -> false module Hashtbl = Hashtbl.Make (struct diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index b01a07d3d6..4cb5b5915f 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -4,6 +4,7 @@ module type SET = sig val of_list : elt list -> t val is_empty : t -> bool + val equal_elt : elt -> elt -> bool end module Make (S : SET) : sig From 528fea6c133ac5e6b35527681c31d80516aa62bf Mon Sep 17 00:00:00 2001 From: ArthurW Date: Mon, 26 Jun 2023 01:19:42 +0200 Subject: [PATCH 106/285] add weird sorting test --- cli/main.ml | 2 +- db/elt.ml | 2 +- test/cram/base.t/run.t | 103 ++++++++++++++++++++++++++---------- test/cram/cli.t/run.t | 11 +--- test/cram/cli_poly.t/run.t | 4 +- test/cram/cli_small.t/run.t | 4 +- test/cram/simple.t/run.t | 8 +-- 7 files changed, 88 insertions(+), 46 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index ddd4491bbf..44b532bd4d 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -12,7 +12,7 @@ let print_result ~print_cost Format.printf "%s%s %s%a\n" score kind name pp_rhs rhs let search ~print_cost ~db query = - match Query.(api ~shards:db { query; packages = []; limit = 50 }) with + match Query.(api ~shards:db { query; packages = []; limit = 10 }) with | _, [] -> print_endline "[No results]" | _, (_ :: _ as results) -> List.iter (print_result ~print_cost) results ; diff --git a/db/elt.ml b/db/elt.ml index 95414a5743..4d689a06e8 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -121,7 +121,7 @@ end include T -let equal a b = structural_compare a b = 0 +let equal a b = compare a b = 0 module Set = Set.Make (T) diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index de417f8d9b..6253e6f5bf 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -2,8 +2,28 @@ $ du -sh megaodocl 5.1M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: {For_generated_code}1.t + Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar + Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Int63_emul.t Warning, resolved hidden path: Base__.Int63_emul.t Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t @@ -29,31 +49,10 @@ Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Int63_emul.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar - Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar - Warning, resolved hidden path: {For_generated_code}1.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Indexing in 658.329010ms - Export in 614.521980ms - 1.60user 0.05system 0:01.65elapsed 100%CPU (0avgtext+0avgdata 190028maxresident)k - 0inputs+6408outputs (0major+52927minor)pagefaults 0swaps -$ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null + Indexing in 648.846149ms + Export in 515.198946ms + 1.45user 0.04system 0:01.49elapsed 100%CPU (0avgtext+0avgdata 187536maxresident)k + 0inputs+5560outputs (0major+52582minor)pagefaults 0swaps $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -65,8 +64,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 3200 db.js - 2412 db.js.gz + 2776 db.js + 2092 db.js.gz 1628 megaodocl.gz @@ -91,3 +90,53 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr odoc_search.js $ cp -r html /tmp $ firefox /tmp/html/base/index.html + $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null + Indexing in 758.491039ms + Export in 544.108868ms + $ sherlodoc --db=db_marshal.bin "group b" + val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t + val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t + val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t + val Base.List.groupi : 'a t -> break:(int -> 'a -> 'a -> bool) -> 'a t t + val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.List.sort_and_group : 'a t -> compare:('a -> 'a -> int) -> 'a t t + val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t + val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list + val Base.String.split_on_chars : t -> on:char list -> t list + val Base.String.Escaping.split_on_chars : string -> on:char list -> escape_char:char -> string list + $ sherlodoc --db=db_marshal.bin "group by" + val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list + val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list + val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list + val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Hashtbl.group : ?growth_allowed:bool -> + ?size:int -> + 'a Key.t -> + get_key:('r -> 'a) -> + get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t + val Base.Hashtbl.Creators.group : ?growth_allowed:bool -> + ?size:int -> + 'a Key.t -> + get_key:('r -> 'a) -> + get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t + val Base.String.split_on_chars : t -> on:char list -> t list + val Base.String.Escaping.split_on_chars : string -> on:char list -> escape_char:char -> string list + $ sherlodoc --db=db_marshal.bin "map2" + mod Base.Applicative.Make_using_map2 + sig Base.Applicative.Basic_using_map2 + mod Base.Applicative.Make2_using_map2 + mod Base.Applicative.Make3_using_map2 + sig Base.Applicative.Basic2_using_map2 + sig Base.Applicative.Basic3_using_map2 + mod Base.Applicative.Make_using_map2_local + sig Base.Applicative.Basic_using_map2_local + mod Base.Applicative.Make2_using_map2_local + mod Base.Applicative.Make3_using_map2_local diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index ccc6d0c1ff..7838a51187 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 1.405954ms - Export in 0.463009ms + Indexing in 1.257896ms + Export in 0.494003ms $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" val Main.unique_name : foo @@ -58,17 +58,10 @@ 216 mod Main.S_to_S1 316 type Main.list 318 type Main.List.t = 'a list - 319 val Main.consume : moo -> unit - 320 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 321 val Main.consume_2 : moo -> moo -> unit 323 val Main.Map.to_list : foo - 327 val Main.consume_2_other : moo -> t -> unit 327 type Main.extensible_type = .. - 328 val Main.nesting_priority : foo - 333 val Main.Nest.nesting_priority : foo 373 cons Main.MyExtension : moo -> extensible_type 1108 val Main.foo : foo - 1154 doc page $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" [No results] TODO : get a result for the query bellow diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index d97d83a3cb..7a8baa5831 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.602961ms - Export in 0.049114ms + Indexing in 0.576973ms + Export in 0.041008ms $ export SHERLODOC_DB=db.bin TODO : get a result for the query bellow $ sherlodoc ":'a" diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 7f8aed977d..e6ea223816 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,8 +5,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.160933ms - Export in 0.089884ms + Indexing in 0.257015ms + Export in 0.078201ms $ export SHERLODOC_DB=db.bin $ sherlodoc --print-cost "list" 109 mod Main.List diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 398676b253..fee41121ca 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -7,11 +7,11 @@ $ du -sh megaodocl 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - Indexing in 0.874996ms - Export in 0.494003ms + Indexing in 1.915932ms + Export in 0.855923ms $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 0.792980ms - Export in 0.483990ms + Indexing in 1.312017ms + Export in 0.560045ms $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null From 1adf0500263a9280464a94cb0512d0c6e2f73c98 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 26 Jun 2023 18:11:45 +0200 Subject: [PATCH 107/285] Does not stackoverflow on the browser --- query/list.ml | 9 ++ query/query.ml | 5 +- query/succ.ml | 171 +++++++++++++++++++----------------- test/cram/base.t/run.t | 27 ++++-- test/cram/cli.t/run.t | 4 +- test/cram/cli_poly.t/run.t | 4 +- test/cram/cli_small.t/run.t | 4 +- test/cram/simple.t/run.t | 8 +- 8 files changed, 128 insertions(+), 104 deletions(-) create mode 100644 query/list.ml diff --git a/query/list.ml b/query/list.ml new file mode 100644 index 0000000000..547ee1e780 --- /dev/null +++ b/query/list.ml @@ -0,0 +1,9 @@ +include Stdlib.List + +(* Same as Stdlib, except for the tmc annotation that does not make it slower + but prevents stack overflows, notably on the browser. *) +let[@tail_mod_cons] rec map f = function + | [] -> [] + | a :: l -> + let r = f a in + r :: map f l \ No newline at end of file diff --git a/query/query.ml b/query/query.ml index e2e426309e..403e0f2ef7 100644 --- a/query/query.ml +++ b/query/query.ml @@ -21,10 +21,7 @@ let collapse_trie_occ ~count t = Succ.empty let collapse_trie t = - t |> Tree.to_sets - |> List.fold_left - (fun succ arr -> Succ.union succ (Succ.of_array arr)) - Succ.empty + t |> Tree.to_sets |> List.map Succ.of_array |> Succ.union_of_list let find_types ~shards names = List.fold_left diff --git a/query/succ.ml b/query/succ.ml index c0101c0a39..dfdbf8cca8 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -25,6 +25,7 @@ let inter a b = | Empty, _ | _, Empty -> empty | _, All -> a | All, _ -> b + | x, y when x == y -> a | x, y -> let x, y = if a.cardinal < b.cardinal then x, y else y, x in { cardinal = min a.cardinal b.cardinal; s = Inter (x, y) } @@ -34,102 +35,110 @@ let union a b = | Empty, _ -> b | _, Empty -> a | All, _ | _, All -> all + | x, y when x == y -> a | x, y -> let x, y = if a.cardinal < b.cardinal then x, y else y, x in { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } -let array_first arr = arr.(0) - -exception Gt of Elt.t - -let rec succ_ge elt = function - | All -> elt - | Empty -> raise Not_found - | Array s -> - let out = Array_succ.succ_ge_exn ~compare:Elt.compare elt s in - begin - match Elt.compare elt out with - | 0 -> elt - | _ -> raise (Gt out) - end - | Inter (a, b) -> - let _ = succ_ge elt a in - let y = succ_ge elt b in - y - | Union (a, b) -> begin - match succ_ge elt a with - | exception Not_found -> succ_ge elt b - | exception Gt x -> begin - match succ_ge elt b with - | exception Not_found -> raise (Gt x) - | exception Gt y -> - raise - (Gt - (match Elt.compare x y with - | c when c <= 0 -> x - | _ -> y)) - | v -> v - end - | v -> v - end +let union_of_array arr = + let rec loop lo hi = + match hi - lo with + | 0 -> empty + | 1 -> arr.(lo) + | dist -> + let mid = lo + (dist / 2) in + let left = loop lo mid in + let right = loop mid hi in + union left right + in + loop 0 (Array.length arr) -let rec succ_gt elt = function - | All -> invalid_arg "Succ.succ_gt All" - | Empty -> raise Not_found - | Array s -> Array_succ.succ_gt_exn ~compare:Elt.compare elt s - | Inter (a, _b) -> succ_gt elt a - | Union (a, b) -> begin - match succ_gt_opt elt a, succ_gt_opt elt b with - | None, None -> raise Not_found - | None, Some z | Some z, None -> z - | Some x, Some y -> begin - match Elt.compare x y with - | c when c <= 0 -> x - | _ -> y - end - end +let union_of_list li = li |> Array.of_list |> union_of_array + +let best x y = + match Elt.compare x y with + | 0 -> x + | c when c < 0 -> x + | _ -> y + +let update_candidate old_cand new_cand = + Some + (match old_cand with + | Some old_cand -> best old_cand new_cand + | None -> new_cand) -and succ_gt_opt elt t = try Some (succ_gt elt t) with Not_found -> None +let best_opt old_cand new_cand = + match old_cand, new_cand with + | None, None -> None + | None, Some z | Some z, None -> Some z + | Some x, Some y -> Some (best x y) -let rec first = function +let ( let* ) = Option.bind + +type strictness = + | Gt + | Ge + +let array_succ ~strictness = + match strictness with + | Ge -> Array_succ.succ_ge + | Gt -> Array_succ.succ_gt + +let rec succ ~strictness t elt = + (* Printf.printf "depth : %i\n" depth ; *) + match t with + | All -> invalid_arg "Succ.succ_rec All" + | Empty -> None + | Array arr -> array_succ ~strictness ~compare:Elt.compare elt arr + | Union (l, r) -> + let elt_r = succ ~strictness r elt in + let elt_l = succ ~strictness l elt in + best_opt elt_l elt_r + | Inter (l, r) -> + let rec loop elt_r = + let* elt_l = succ ~strictness l elt_r in + let* elt_r = succ ~strictness:Ge r elt_l in + if Elt.equal elt_l elt_r then Some elt_l else loop elt_r + in + loop elt + +let succ_ge = succ ~strictness:Ge +let succ_gt = succ ~strictness:Gt + +let rec first candidate t = + match t with | All -> invalid_arg "Succ.first All" - | Empty -> raise Not_found - | Array s -> array_first s - | Inter (a, _b) -> first a + | Empty -> None + | Array s -> ( try update_candidate candidate s.(0) with e -> raise e) + | Inter (a, _) -> + let* elt = first candidate a in + succ_ge t elt | Union (a, b) -> begin - match first_opt a, first_opt b with - | None, None -> raise Not_found - | None, Some z | Some z, None -> z - | Some x, Some y -> begin - match Elt.compare x y with - | 0 -> x - | c when c < 0 -> x - | _ -> y - end + let a = first candidate a in + let candidate = best_opt candidate a in + first candidate b end -and first_opt t = try Some (first t) with Not_found -> None +let first = first None + +let first_exn t = + match first t with + | Some v -> v + | None -> raise Not_found let to_seq t = + (* PPrint.ToChannel.pretty 0.8 80 stdout (pprint t) ; *) let state = ref None in - let rec go elt = - match succ_ge elt t with - | elt' -> - assert (Elt.compare elt elt' = 0) ; - state := Some elt ; - Some elt - | exception Gt elt -> go elt - | exception Not_found -> None - in - let go_gt () = - match !state with - | None -> go (first t) - | Some previous_elt -> ( - match succ_gt previous_elt t with - | elt -> go elt - | exception Not_found -> None) + let loop () = + let elt = + match !state with + | None -> first t + | Some previous_elt -> succ_gt t previous_elt + in + state := elt ; + elt in - let next () = try go_gt () with _ -> None in + let next () = try Printexc.print loop () with _ -> None in Seq.of_dispenser next let to_seq t = to_seq t.s diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 6253e6f5bf..7bd42a89bf 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -49,10 +49,12 @@ Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Either0.t - Indexing in 648.846149ms - Export in 515.198946ms - 1.45user 0.04system 0:01.49elapsed 100%CPU (0avgtext+0avgdata 187536maxresident)k - 0inputs+5560outputs (0major+52582minor)pagefaults 0swaps + Indexing in 701.358080ms + Export in 685.815096ms + + real 0m1.786s + user 0m1.747s + sys 0m0.033s $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -64,8 +66,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2776 db.js - 2092 db.js.gz + 2736 db.js + 2060 db.js.gz 1628 megaodocl.gz @@ -91,8 +93,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cp -r html /tmp $ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 758.491039ms - Export in 544.108868ms + Indexing in 708.482981ms + Export in 549.648046ms $ sherlodoc --db=db_marshal.bin "group b" val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t @@ -127,8 +129,15 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr combine:('b -> 'b -> 'b) -> 'r list -> ('a, 'b) t + val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> + ?size:int -> + 'a Key.t -> + get_key:('r -> 'a) -> + get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t val Base.String.split_on_chars : t -> on:char list -> t list - val Base.String.Escaping.split_on_chars : string -> on:char list -> escape_char:char -> string list $ sherlodoc --db=db_marshal.bin "map2" mod Base.Applicative.Make_using_map2 sig Base.Applicative.Basic_using_map2 diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 7838a51187..5e551df0a7 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 1.257896ms - Export in 0.494003ms + Indexing in 1.361132ms + Export in 0.602961ms $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" val Main.unique_name : foo diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index 7a8baa5831..b6f2afbbd3 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.576973ms - Export in 0.041008ms + Indexing in 0.655890ms + Export in 0.038862ms $ export SHERLODOC_DB=db.bin TODO : get a result for the query bellow $ sherlodoc ":'a" diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index e6ea223816..7f39067bd6 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,8 +5,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.257015ms - Export in 0.078201ms + Indexing in 0.247002ms + Export in 0.077963ms $ export SHERLODOC_DB=db.bin $ sherlodoc --print-cost "list" 109 mod Main.List diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index fee41121ca..1f8cb4d6cf 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -7,11 +7,11 @@ $ du -sh megaodocl 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.915932ms - Export in 0.855923ms + Indexing in 1.532078ms + Export in 0.615835ms $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.312017ms - Export in 0.560045ms + Indexing in 1.391172ms + Export in 0.612020ms $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null From c3367e53c27893d5af30edecbc47c06c9c338649 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 27 Jun 2023 10:36:12 +0200 Subject: [PATCH 108/285] Add deleted tests back --- query/query.ml | 4 +++ query/query.mli | 7 ++++- query/test/dune | 3 +++ query/test/test.ml | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 query/test/dune create mode 100644 query/test/test.ml diff --git a/query/query.ml b/query/query.ml index 403e0f2ef7..19029cd57e 100644 --- a/query/query.ml +++ b/query/query.ml @@ -7,6 +7,10 @@ module Tree_occ = Db.Suffix_tree.With_occ open Db.Types module Occ = Db.Occ.Int_map +module Private = struct + module Array_succ = Array_succ +end + let inter_list xs = List.fold_left Succ.inter Succ.all xs let collapse_occ ~count occs = diff --git a/query/query.mli b/query/query.mli index 47beb2f342..795d98c49b 100644 --- a/query/query.mli +++ b/query/query.mli @@ -8,4 +8,9 @@ type t = ; limit : int } -val api : shards: Db.t list -> t -> string * Db.Elt.t list +val api : shards:Db.t list -> t -> string * Db.Elt.t list + +(** For testing *) +module Private : sig + module Array_succ = Array_succ +end diff --git a/query/test/dune b/query/test/dune new file mode 100644 index 0000000000..46d89d810c --- /dev/null +++ b/query/test/dune @@ -0,0 +1,3 @@ +(test + (name test) + (libraries alcotest query)) diff --git a/query/test/test.ml b/query/test/test.ml new file mode 100644 index 0000000000..14a4e3e787 --- /dev/null +++ b/query/test/test.ml @@ -0,0 +1,67 @@ +open Query.Private + +let rec succ_ge_reference i ~compare elt arr = + Printf.printf "ref_succ_ge %i\n%!" i ; + if i = Array.length arr + then None + else if compare arr.(i) elt >= 0 + then Some arr.(i) + else succ_ge_reference (i + 1) ~compare elt arr + +let rec succ_gt_reference i ~compare elt arr = + if i = Array.length arr + then None + else if compare arr.(i) elt > 0 + then Some arr.(i) + else succ_gt_reference (i + 1) ~compare elt arr + +let succ_ge_reference ~compare elt arr = succ_ge_reference 0 ~compare elt arr +let succ_gt_reference ~compare elt arr = succ_gt_reference 0 ~compare elt arr + +let test_succ_ge elt arr () = + Alcotest.(check (option int)) + "same int option" + (succ_ge_reference ~compare:Int.compare elt arr) + (Array_succ.succ_ge ~compare:Int.compare elt arr) + +let test_succ_gt elt arr () = + Alcotest.(check (option int)) + "same int option" + (succ_gt_reference ~compare:Int.compare elt arr) + (Array_succ.succ_gt ~compare:Int.compare elt arr) + +let () = Random.init 123 + +(* The tests *) + +let random_array size = + let r = + List.init size (fun _ -> Random.full_int (size * 2)) + |> List.sort_uniq Int.compare |> Array.of_list + in + + r + +let tests_arr name test = + List.init 50 (fun i -> + let elt = Random.full_int ((i * 2) + 1) in + let arr = random_array i in + let arr_string = + if i <= 5 + then + "[|" + ^ (arr |> Array.to_list |> List.map string_of_int + |> String.concat "; ") + ^ "|]" + else "[|...|]" + in + Alcotest.test_case + (Printf.sprintf "%s %i %s " name elt arr_string) + `Quick (test elt arr)) + +let tests_succ_ge = tests_arr "succ_ge" test_succ_ge +let tests_succ_gt = tests_arr "succ_gt" test_succ_gt + +let () = + let open Alcotest in + run "Query" [ "Array_succ", tests_succ_ge @ tests_succ_gt ] From 9eadd69180ebf1ab6d7cb1d8557f23ffc6f4cb5b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 27 Jun 2023 17:11:17 +0200 Subject: [PATCH 109/285] Use rev_map instead of trmc --- query/list.ml | 9 --------- query/query.ml | 5 ++++- 2 files changed, 4 insertions(+), 10 deletions(-) delete mode 100644 query/list.ml diff --git a/query/list.ml b/query/list.ml deleted file mode 100644 index 547ee1e780..0000000000 --- a/query/list.ml +++ /dev/null @@ -1,9 +0,0 @@ -include Stdlib.List - -(* Same as Stdlib, except for the tmc annotation that does not make it slower - but prevents stack overflows, notably on the browser. *) -let[@tail_mod_cons] rec map f = function - | [] -> [] - | a :: l -> - let r = f a in - r :: map f l \ No newline at end of file diff --git a/query/query.ml b/query/query.ml index 19029cd57e..ef3b569209 100644 --- a/query/query.ml +++ b/query/query.ml @@ -25,7 +25,10 @@ let collapse_trie_occ ~count t = Succ.empty let collapse_trie t = - t |> Tree.to_sets |> List.map Succ.of_array |> Succ.union_of_list + (* here we use rev_map, because the order is not important, and the list is + too long : map would stack overflow. + TODO : get a tree instead of a map. *) + t |> Tree.to_sets |> List.rev_map Succ.of_array |> Succ.union_of_list let find_types ~shards names = List.fold_left From 5efb48df8ad51926c549bc3c537a75497ead5416 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 27 Jun 2023 17:12:03 +0200 Subject: [PATCH 110/285] Occ is abstract --- db/occ.ml | 2 ++ db/occ.mli | 7 +++++++ query/query.ml | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 db/occ.mli diff --git a/db/occ.ml b/db/occ.ml index cf5258bf8d..60875261b1 100644 --- a/db/occ.ml +++ b/db/occ.ml @@ -3,6 +3,8 @@ module Int_map = Map.Make (Int) type t = Elt.Array.t Int_map.t type elt = int * Elt.t +let find = Int_map.find_opt +let fold = Int_map.fold let is_empty = Int_map.is_empty let equal_elt (a_count, a) (b_count, b) = a_count = b_count && Elt.equal a b diff --git a/db/occ.mli b/db/occ.mli new file mode 100644 index 0000000000..b3ede13520 --- /dev/null +++ b/db/occ.mli @@ -0,0 +1,7 @@ +type t +type elt = int * Elt.t +val find : int -> t -> Elt.t array option +val fold : (int -> Elt.t array -> 'a -> 'a) -> t -> 'a -> 'a +val is_empty : t -> bool +val equal_elt : elt -> elt -> bool +val of_list : elt list -> t diff --git a/query/query.ml b/query/query.ml index ef3b569209..1d06c40854 100644 --- a/query/query.ml +++ b/query/query.ml @@ -5,7 +5,7 @@ module Storage = Db.Storage module Tree = Db.Suffix_tree.With_elts module Tree_occ = Db.Suffix_tree.With_occ open Db.Types -module Occ = Db.Occ.Int_map +module Occ = Db.Occ module Private = struct module Array_succ = Array_succ From 2d8546c33e2af7ee92aef026d1e1681a09552789 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 27 Jun 2023 17:12:27 +0200 Subject: [PATCH 111/285] format --- query/sort.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/query/sort.ml b/query/sort.ml index 555f7ada01..8ae0a3bd1c 100644 --- a/query/sort.ml +++ b/query/sort.ml @@ -1,4 +1,3 @@ - module Elt = Db.Elt module Type_distance = struct From 58c09c1af47bb293468e241863ff972058b7cc95 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 27 Jun 2023 17:13:26 +0200 Subject: [PATCH 112/285] format --- store/storage_ancient.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/store/storage_ancient.ml b/store/storage_ancient.ml index a23498df53..dce23b623e 100644 --- a/store/storage_ancient.ml +++ b/store/storage_ancient.ml @@ -1,4 +1,3 @@ - let base_addr = 0x100000000000n type writer = @@ -11,7 +10,7 @@ let open_out filename = let ancient = Ancient.attach handle base_addr in { write_shard = 0; ancient } -let save ~db (t : Db.t) = +let save ~db (t : Db.t) = ignore (Ancient.share db.ancient db.write_shard t) ; db.write_shard <- db.write_shard + 1 From a9465dcb288974cb3ab072473a592c0dd8137332 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 28 Jun 2023 16:56:47 +0200 Subject: [PATCH 113/285] Bugfix in Succ and make it polymorphic --- query/succ.ml | 100 +++++++++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/query/succ.ml b/query/succ.ml index dfdbf8cca8..e52b558e75 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,17 +1,40 @@ -open Db - -type s = +type 'a s = | All | Empty - | Array of Elt.t array - | Inter of s * s - | Union of s * s + | Array of 'a array + | Inter of 'a s * 'a s + | Union of 'a s * 'a s -type t = +type 'a t = { cardinal : int - ; s : s + ; s : 'a s } +let rec print_s a ~depth s = + print_string (String.make (depth * 4) ' ') ; + let depth = depth + 1 in + match s with + | All -> print_endline "All" + | Empty -> print_endline "Empty" + | Inter (l, r) -> + print_endline "Inter" ; + print_s a ~depth l ; + print_s a ~depth r + | Union (l, r) -> + print_endline "Union" ; + print_s a ~depth l ; + print_s a ~depth r + | Array arr -> + print_string "{ " ; + Array.iter + (fun elt -> + a elt ; + print_string " ") + arr ; + print_endline "}" + +let print_s a s = print_s a ~depth:0 s +let print a t = print_s a t.s let all = { cardinal = -1; s = All } let empty = { cardinal = 0; s = Empty } @@ -55,25 +78,20 @@ let union_of_array arr = let union_of_list li = li |> Array.of_list |> union_of_array -let best x y = - match Elt.compare x y with +let best ~compare x y = + match compare x y with | 0 -> x | c when c < 0 -> x | _ -> y -let update_candidate old_cand new_cand = - Some - (match old_cand with - | Some old_cand -> best old_cand new_cand - | None -> new_cand) - -let best_opt old_cand new_cand = +let best_opt ~compare old_cand new_cand = match old_cand, new_cand with | None, None -> None | None, Some z | Some z, None -> Some z - | Some x, Some y -> Some (best x y) + | Some x, Some y -> Some (best ~compare x y) let ( let* ) = Option.bind +let ( let+ ) x f = Option.map f x type strictness = | Gt @@ -84,56 +102,54 @@ let array_succ ~strictness = | Ge -> Array_succ.succ_ge | Gt -> Array_succ.succ_gt -let rec succ ~strictness t elt = +let rec succ ~compare ~strictness t elt = (* Printf.printf "depth : %i\n" depth ; *) match t with | All -> invalid_arg "Succ.succ_rec All" | Empty -> None - | Array arr -> array_succ ~strictness ~compare:Elt.compare elt arr + | Array arr -> array_succ ~strictness ~compare elt arr | Union (l, r) -> - let elt_r = succ ~strictness r elt in - let elt_l = succ ~strictness l elt in - best_opt elt_l elt_r + let elt_r = succ ~compare ~strictness r elt in + let elt_l = succ ~compare ~strictness l elt in + best_opt ~compare elt_l elt_r | Inter (l, r) -> let rec loop elt_r = - let* elt_l = succ ~strictness l elt_r in - let* elt_r = succ ~strictness:Ge r elt_l in - if Elt.equal elt_l elt_r then Some elt_l else loop elt_r + let* elt_l = succ ~compare ~strictness l elt_r in + let* elt_r = succ ~compare ~strictness:Ge r elt_l in + if compare elt_l elt_r = 0 then Some elt_l else loop elt_r in loop elt -let succ_ge = succ ~strictness:Ge -let succ_gt = succ ~strictness:Gt +let succ_ge ~compare t elt = succ ~compare ~strictness:Ge t elt +let succ_gt ~compare t elt = succ ~compare ~strictness:Gt t elt -let rec first candidate t = +let rec first ~compare candidate t = match t with | All -> invalid_arg "Succ.first All" | Empty -> None - | Array s -> ( try update_candidate candidate s.(0) with e -> raise e) + | Array s -> best_opt ~compare candidate (Some s.(0)) | Inter (a, _) -> - let* elt = first candidate a in - succ_ge t elt + let* elt = first ~compare candidate a in + succ_ge ~compare t elt | Union (a, b) -> begin - let a = first candidate a in - let candidate = best_opt candidate a in - first candidate b + let candidate = first ~compare candidate a in + first ~compare candidate b end -let first = first None +let first ~compare t = first ~compare None t -let first_exn t = - match first t with +let first_exn ~compare t = + match first ~compare t with | Some v -> v | None -> raise Not_found -let to_seq t = - (* PPrint.ToChannel.pretty 0.8 80 stdout (pprint t) ; *) +let to_seq ~compare t = let state = ref None in let loop () = let elt = match !state with - | None -> first t - | Some previous_elt -> succ_gt t previous_elt + | None -> first ~compare t + | Some previous_elt -> succ_gt ~compare t previous_elt in state := elt ; elt From 8728bd4c12373b39725d7ed95e07471b62800e72 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 28 Jun 2023 16:57:12 +0200 Subject: [PATCH 114/285] Adds new test : cli and Succ --- query/query.ml | 2 +- query/test/test.ml | 238 +++++++++++++++++++++++++++++---------- test/cram/base.t/run.t | 38 ++++--- test/cram/cli.t/main.mli | 10 +- test/cram/cli.t/run.t | 20 +++- 5 files changed, 219 insertions(+), 89 deletions(-) diff --git a/query/query.ml b/query/query.ml index 1d06c40854..4d9fda78c9 100644 --- a/query/query.ml +++ b/query/query.ml @@ -96,7 +96,7 @@ let api ~(shards : Db.t list) params = Parser.of_string params.query in let results = search ~shards query_name query_typ in - let results = Succ.to_seq results in + let results = Succ.to_seq ~compare:Db.Elt.compare results in let results = match_packages ~packages:params.packages results in let results = List.of_seq @@ Seq.take params.limit results in let results = Sort.list query_name query_typ_arrow results in diff --git a/query/test/test.ml b/query/test/test.ml index 14a4e3e787..ee1fbb6055 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -1,67 +1,181 @@ open Query.Private -let rec succ_ge_reference i ~compare elt arr = - Printf.printf "ref_succ_ge %i\n%!" i ; - if i = Array.length arr - then None - else if compare arr.(i) elt >= 0 - then Some arr.(i) - else succ_ge_reference (i + 1) ~compare elt arr - -let rec succ_gt_reference i ~compare elt arr = - if i = Array.length arr - then None - else if compare arr.(i) elt > 0 - then Some arr.(i) - else succ_gt_reference (i + 1) ~compare elt arr - -let succ_ge_reference ~compare elt arr = succ_ge_reference 0 ~compare elt arr -let succ_gt_reference ~compare elt arr = succ_gt_reference 0 ~compare elt arr - -let test_succ_ge elt arr () = - Alcotest.(check (option int)) - "same int option" - (succ_ge_reference ~compare:Int.compare elt arr) - (Array_succ.succ_ge ~compare:Int.compare elt arr) - -let test_succ_gt elt arr () = - Alcotest.(check (option int)) - "same int option" - (succ_gt_reference ~compare:Int.compare elt arr) - (Array_succ.succ_gt ~compare:Int.compare elt arr) - -let () = Random.init 123 - -(* The tests *) - -let random_array size = - let r = - List.init size (fun _ -> Random.full_int (size * 2)) - |> List.sort_uniq Int.compare |> Array.of_list - in - - r - -let tests_arr name test = - List.init 50 (fun i -> - let elt = Random.full_int ((i * 2) + 1) in - let arr = random_array i in - let arr_string = - if i <= 5 - then - "[|" - ^ (arr |> Array.to_list |> List.map string_of_int - |> String.concat "; ") - ^ "|]" - else "[|...|]" - in - Alcotest.test_case - (Printf.sprintf "%s %i %s " name elt arr_string) - `Quick (test elt arr)) - -let tests_succ_ge = tests_arr "succ_ge" test_succ_ge -let tests_succ_gt = tests_arr "succ_gt" test_succ_gt +let print_int ~ch i = output_string ch (string_of_int i) + +module Test_array = struct + let rec succ_ge_reference i ~compare elt arr = + Printf.printf "ref_succ_ge %i\n%!" i ; + if i = Array.length arr + then None + else if compare arr.(i) elt >= 0 + then Some arr.(i) + else succ_ge_reference (i + 1) ~compare elt arr + + let rec succ_gt_reference i ~compare elt arr = + if i = Array.length arr + then None + else if compare arr.(i) elt > 0 + then Some arr.(i) + else succ_gt_reference (i + 1) ~compare elt arr + + let succ_ge_reference ~compare elt arr = succ_ge_reference 0 ~compare elt arr + let succ_gt_reference ~compare elt arr = succ_gt_reference 0 ~compare elt arr + + let test_succ_ge elt arr () = + Alcotest.(check (option int)) + "same int option" + (succ_ge_reference ~compare:Int.compare elt arr) + (Array_succ.succ_ge ~compare:Int.compare elt arr) + + let test_succ_gt elt arr () = + Alcotest.(check (option int)) + "same int option" + (succ_gt_reference ~compare:Int.compare elt arr) + (Array_succ.succ_gt ~compare:Int.compare elt arr) + + let () = Random.init 123 + + (* The tests *) + + let random_array size = + let r = + List.init size (fun _ -> Random.full_int (size * 2)) + |> List.sort_uniq Int.compare |> Array.of_list + in + + r + + let tests_arr name test = + List.init 50 (fun i -> + let elt = Random.full_int ((i * 2) + 1) in + let arr = random_array i in + let arr_string = + if i <= 5 + then + "[|" + ^ (arr |> Array.to_list |> List.map string_of_int + |> String.concat "; ") + ^ "|]" + else "[|...|]" + in + Alcotest.test_case + (Printf.sprintf "%s %i %s " name elt arr_string) + `Quick (test elt arr)) + + let tests_succ_ge = tests_arr "succ_ge" test_succ_ge + let tests_succ_gt = tests_arr "succ_gt" test_succ_gt +end + +open Query + +module Test_succ = struct + let rec mem ~compare t elt = + let open Succ in + match t with + | All -> invalid_arg "Succ.succ_rec All" + | Empty -> false + | Array arr -> Array.exists (fun elt' -> compare elt elt' = 0) arr + | Union (l, r) -> mem ~compare l elt || mem ~compare r elt + | Inter (l, r) -> mem ~compare l elt && mem ~compare r elt + + let ( let* ) = Option.bind + let ( let+ ) x f = Option.map f x + + let array_succ_reference ~strictness = + let open Succ in + match strictness with + | Ge -> Test_array.succ_ge_reference + | Gt -> Test_array.succ_gt_reference + + let rec succ_reference ~compare ~strictness t elt = + (* Printf.printf "depth : %i\n" depth ; *) + match t with + | Succ.All -> invalid_arg "Succ.succ_rec All" + | Empty -> None + | Array arr -> array_succ_reference ~strictness ~compare elt arr + | Union (l, r) -> + let elt_r = succ_reference ~compare ~strictness r elt in + let elt_l = succ_reference ~compare ~strictness l elt in + Succ.best_opt ~compare elt_l elt_r + | Inter (l, r) -> + let rec loop elt = + if mem ~compare r elt + then Some elt + else + let* elt = succ_reference ~compare ~strictness:Gt l elt in + loop elt + in + let* elt = succ_reference ~compare ~strictness l elt in + loop elt + + let rec first_reference ~compare t = + match t with + | Succ.All -> invalid_arg "Succ.first All" + | Empty -> None + | Array s -> Some s.(0) + | Inter (l, r) -> + let rec loop elt = + let* elt = elt in + if mem ~compare r elt + then Some elt + else + let elt = succ_reference ~strictness:Gt ~compare l elt in + loop elt + in + loop (first_reference ~compare l) + | Union (l, r) -> + Succ.best_opt ~compare + (first_reference ~compare l) + (first_reference ~compare r) + + let _ = first_reference + + let rec random_succ size = + if size = 0 + then Succ.empty + else + match Random.int 3 with + | 0 -> + let arr = Test_array.random_array size in + Array.sort Int.compare arr ; + Succ.of_array arr + | 1 -> Succ.inter (random_succ (size / 2)) (random_succ (size / 2)) + | 2 -> Succ.union (random_succ (size / 2)) (random_succ (size / 2)) + | _ -> assert false + + let random_succ size = + let t = random_succ size in + t.s + + let tests_succ name test = + List.init 20 (fun i -> + let i = i * 5 in + let elt = Random.full_int ((i * 2) + 1) in + let succ = random_succ i in + Alcotest.test_case + (Printf.sprintf "%s size %i elt %i" name i elt) + `Quick (test elt succ)) + + let tests_succ_gt elt tree () = + let strictness = Succ.Gt in + Alcotest.(check (option int)) + "same int option" + (succ_reference ~strictness ~compare:Int.compare tree elt) + (Succ.succ ~strictness ~compare:Int.compare tree elt) + + let tests_succ_ge elt tree () = + let strictness = Succ.Ge in + let ref = succ_reference ~strictness ~compare:Int.compare tree elt in + let real = Succ.succ ~strictness ~compare:Int.compare tree elt in + Alcotest.(check (option int)) "same int option" ref real + + let tests_succ_ge = tests_succ "succ_ge" tests_succ_ge + let tests_succ_gt = tests_succ "succ_gt" tests_succ_gt +end let () = let open Alcotest in - run "Query" [ "Array_succ", tests_succ_ge @ tests_succ_gt ] + run "Query" + [ "Array_succ", Test_array.tests_succ_ge @ Test_array.tests_succ_gt + ; "Succ", Test_succ.tests_succ_ge @ Test_succ.tests_succ_gt + ] diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 7bd42a89bf..f47e574be6 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -49,12 +49,12 @@ Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Either0.t - Indexing in 701.358080ms - Export in 685.815096ms + Indexing in 680.731058ms + Export in 603.530169ms - real 0m1.786s - user 0m1.747s - sys 0m0.033s + real 0m1.615s + user 0m1.546s + sys 0m0.064s $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -66,8 +66,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2736 db.js - 2060 db.js.gz + 2824 db.js + 2132 db.js.gz 1628 megaodocl.gz @@ -91,10 +91,10 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr odoc.css odoc_search.js $ cp -r html /tmp - $ firefox /tmp/html/base/index.html +$ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 708.482981ms - Export in 549.648046ms + Indexing in 722.393036ms + Export in 560.818911ms $ sherlodoc --db=db_marshal.bin "group b" val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t @@ -129,15 +129,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr combine:('b -> 'b -> 'b) -> 'r list -> ('a, 'b) t - val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> - ?size:int -> - 'a Key.t -> - get_key:('r -> 'a) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t val Base.String.split_on_chars : t -> on:char list -> t list + val Base.String.Escaping.split_on_chars : string -> on:char list -> escape_char:char -> string list $ sherlodoc --db=db_marshal.bin "map2" mod Base.Applicative.Make_using_map2 sig Base.Applicative.Basic_using_map2 @@ -149,3 +142,12 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr sig Base.Applicative.Basic_using_map2_local mod Base.Applicative.Make2_using_map2_local mod Base.Applicative.Make3_using_map2_local + $ sherlodoc --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" + val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> + ?size:int -> + 'a Key.t -> + get_key:('r -> 'a) -> + get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t diff --git a/test/cram/cli.t/main.mli b/test/cram/cli.t/main.mli index 941aec38dc..338adb4026 100644 --- a/test/cram/cli.t/main.mli +++ b/test/cram/cli.t/main.mli @@ -25,6 +25,8 @@ module List : sig type 'a t = 'a list val map : ('a -> 'b) -> 'a t -> 'b t + val map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t end val foo : foo @@ -37,11 +39,9 @@ val value : moo val consume : moo -> unit val consume_2 : moo -> moo -> unit val consume_2_other : moo -> t -> unit - val produce : unit -> moo val produce_2' : unit -> unit -> moo - module type Modtype = sig val v_modtype : foo end @@ -51,11 +51,12 @@ module type S = sig end module S_to_S1 : sig end (**/**) + val hidden : foo + (**/**) val poly_1 : 'a -> 'b -> 'c - val poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c type 'a boo @@ -63,5 +64,4 @@ type 'a boo val poly_param : 'a boo type extensible_type = .. - -type extensible_type += MyExtension of moo \ No newline at end of file +type extensible_type += MyExtension of moo diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 5e551df0a7..2e2b2b84b8 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 1.361132ms - Export in 0.602961ms + Indexing in 2.419949ms + Export in 0.387192ms $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" val Main.unique_name : foo @@ -27,18 +27,27 @@ 209 type Main.list 315 type Main.List.t = 'a list 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 318 val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list 319 val Main.Map.to_list : foo + 326 val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 1108 val Main.foo : foo 1154 doc page $ sherlodoc --print-cost "map" 108 mod Main.Map 213 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 318 val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list 320 val Main.Map.to_list : foo + 327 val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 1108 val Main.foo : foo $ sherlodoc --print-cost "list map" 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 422 val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list 423 val Main.Map.to_list : foo + 431 val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 2108 val Main.foo : foo + $ sherlodoc --print-cost "map2" + 214 val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 327 val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc --print-cost ":moo" 210 val Main.value : moo 213 val Main.produce : unit -> moo @@ -58,8 +67,8 @@ 216 mod Main.S_to_S1 316 type Main.list 318 type Main.List.t = 'a list + 319 val Main.consume : moo -> unit 323 val Main.Map.to_list : foo - 327 type Main.extensible_type = .. 373 cons Main.MyExtension : moo -> extensible_type 1108 val Main.foo : foo $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" @@ -74,11 +83,16 @@ TODO : get a result for the query bellow val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.poly_param : 'a boo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc ": 'a -> 'b -> 'c " val Main.poly_1 : 'a -> 'b -> 'c val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc ": ('a -> 'b) -> 'a t -> 'b t" val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t TODO : get a result for the query bellow $ sherlodoc ": 'a bo" [No results] From f9370af0945a3f145ae5664bad3db54ab320dd3c Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 28 Jun 2023 17:00:11 +0200 Subject: [PATCH 115/285] Make length more important for static cost --- index/load_doc.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index/load_doc.ml b/index/load_doc.ml index daa3301405..18f418b9ad 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -4,7 +4,10 @@ module Types = Db.Types module ModuleName = Odoc_model.Names.ModuleName let generic_cost ~ignore_no_doc name has_doc = - String.length name + (* name length is important not because short identifier are better in the + abstract, but because the shortest result will be close to the query, as + the suffix tree does not return shorter than the query*) + String.length name * 4 (* + (5 * List.length path) TODO : restore depth based ordering *) + (if ignore_no_doc || has_doc then 0 else 100) + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 From e7ceb43d6ca3452ae7f18a84e911fb417e720c9c Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 28 Jun 2023 17:00:33 +0200 Subject: [PATCH 116/285] Typo in comment --- index/load_doc.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index/load_doc.ml b/index/load_doc.ml index 18f418b9ad..213b4b3785 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -6,7 +6,7 @@ module ModuleName = Odoc_model.Names.ModuleName let generic_cost ~ignore_no_doc name has_doc = (* name length is important not because short identifier are better in the abstract, but because the shortest result will be close to the query, as - the suffix tree does not return shorter than the query*) + the suffix tree does not return results shorter than the query*) String.length name * 4 (* + (5 * List.length path) TODO : restore depth based ordering *) + (if ignore_no_doc || has_doc then 0 else 100) From 45c97c82bb98058bac6a46c77d6004c62de7c73b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 28 Jun 2023 17:12:30 +0200 Subject: [PATCH 117/285] Add options for testing the static order --- cli/main.ml | 27 ++++++++++++++++++--------- query/{sort.ml => dynamic_cost.ml} | 7 ++----- query/query.ml | 15 ++++++++++++--- query/query.mli | 4 ++-- www/www.ml | 1 - 5 files changed, 34 insertions(+), 20 deletions(-) rename query/{sort.ml => dynamic_cost.ml} (98%) diff --git a/cli/main.ml b/cli/main.ml index 44b532bd4d..b20beff31e 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -11,21 +11,23 @@ let print_result ~print_cost in Format.printf "%s%s %s%a\n" score kind name pp_rhs rhs -let search ~print_cost ~db query = - match Query.(api ~shards:db { query; packages = []; limit = 10 }) with +let search ~print_cost ~dynamic_sort ~db query = + match + Query.(api ~shards:db ~dynamic_sort { query; packages = []; limit = 10 }) + with | _, [] -> print_endline "[No results]" | _, (_ :: _ as results) -> List.iter (print_result ~print_cost) results ; flush stdout -let rec search_loop ~print_cost ~db = +let rec search_loop ~print_cost ~dynamic_sort ~db = match In_channel.input_line stdin with | Some query -> - search ~print_cost ~db query ; - search_loop ~print_cost ~db + search ~print_cost ~dynamic_sort ~db query ; + search_loop ~print_cost ~dynamic_sort ~db | None -> print_endline "[Search session ended]" -let main db query print_cost = +let main db query print_cost dynamic_sort = match db with | None -> output_string stderr @@ -35,8 +37,8 @@ let main db query print_cost = | Some db -> ( let db = Storage_marshal.load db in match query with - | None -> search_loop ~print_cost ~db - | Some query -> search ~print_cost ~db query) + | None -> search_loop ~print_cost ~dynamic_sort ~db + | Some query -> search ~print_cost ~dynamic_sort ~db query) open Cmdliner @@ -59,7 +61,14 @@ let print_cost = let doc = "Prints cost of each result" in Arg.(value & flag & info [ "print-cost" ] ~doc) -let main = Term.(const main $ db_filename $ query $ print_cost) +let dynamic_sort = + let doc = + "Sort the results by looking at the query.\n\ + Disabling it allows to look at the static costs of elements." + in + Arg.(value & flag & info [ "dynamic-sort" ] ~doc) + +let main = Term.(const main $ db_filename $ query $ print_cost $ dynamic_sort) let cmd = let doc = "CLI interface to query sherlodoc" in diff --git a/query/sort.ml b/query/dynamic_cost.ml similarity index 98% rename from query/sort.ml rename to query/dynamic_cost.ml index 8ae0a3bd1c..d87435fe75 100644 --- a/query/sort.ml +++ b/query/dynamic_cost.ml @@ -330,8 +330,5 @@ module Reasoning = struct let score ~query_name ~query_type elt = score (v query_name query_type elt) end -let list query_name query_type results = - results - |> List.map (fun elt -> - Elt.{ elt with score = Reasoning.score ~query_name ~query_type elt }) - |> List.sort Elt.compare +let elt ~query_name ~query_type elt = + Elt.{ elt with score = Reasoning.score ~query_name ~query_type elt } diff --git a/query/query.ml b/query/query.ml index 4d9fda78c9..ba761d4e4a 100644 --- a/query/query.ml +++ b/query/query.ml @@ -1,6 +1,6 @@ module Parser = Query_parser module Succ = Succ -module Sort = Sort +module Dynamic_cost = Dynamic_cost module Storage = Db.Storage module Tree = Db.Suffix_tree.With_elts module Tree_occ = Db.Suffix_tree.With_occ @@ -91,7 +91,7 @@ let match_packages ~packages results = | [] -> results | _ -> Seq.filter (match_packages ~packages) results -let api ~(shards : Db.t list) params = +let api ~(shards : Db.t list) ?(dynamic_sort = true) params = let query_name, query_typ, query_typ_arrow, pretty = Parser.of_string params.query in @@ -99,5 +99,14 @@ let api ~(shards : Db.t list) params = let results = Succ.to_seq ~compare:Db.Elt.compare results in let results = match_packages ~packages:params.packages results in let results = List.of_seq @@ Seq.take params.limit results in - let results = Sort.list query_name query_typ_arrow results in + let results = + if dynamic_sort + then + List.map + (Dynamic_cost.elt ~query_name ~query_type:query_typ_arrow) + results + else results + in + let results = List.sort Db.Elt.compare results in + pretty, results diff --git a/query/query.mli b/query/query.mli index 795d98c49b..6681744bf8 100644 --- a/query/query.mli +++ b/query/query.mli @@ -1,6 +1,6 @@ module Parser = Query_parser module Succ = Succ -module Sort = Sort +module Dynamic_cost = Dynamic_cost type t = { query : string @@ -8,7 +8,7 @@ type t = ; limit : int } -val api : shards:Db.t list -> t -> string * Db.Elt.t list +val api : shards:Db.t list -> ?dynamic_sort:bool -> t -> string * Db.Elt.t list (** For testing *) module Private : sig diff --git a/www/www.ml b/www/www.ml index dbb267ad91..5a2890377a 100644 --- a/www/www.ml +++ b/www/www.ml @@ -1,6 +1,5 @@ module Storage = Db.Storage module Succ = Query.Succ -module Sort = Query.Sort module H = Tyxml.Html let api ~shards params = From 4487ea373c2d744410971a2509521790e7a5a45d Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 28 Jun 2023 17:12:48 +0200 Subject: [PATCH 118/285] Format --- db/occ.mli | 3 ++- index/load_doc.ml | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/db/occ.mli b/db/occ.mli index b3ede13520..924a8ba482 100644 --- a/db/occ.mli +++ b/db/occ.mli @@ -1,5 +1,6 @@ -type t +type t type elt = int * Elt.t + val find : int -> t -> Elt.t array option val fold : (int -> Elt.t array -> 'a -> 'a) -> t -> 'a -> 'a val is_empty : t -> bool diff --git a/index/load_doc.ml b/index/load_doc.ml index 213b4b3785..a9b53f9969 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -4,10 +4,10 @@ module Types = Db.Types module ModuleName = Odoc_model.Names.ModuleName let generic_cost ~ignore_no_doc name has_doc = - (* name length is important not because short identifier are better in the - abstract, but because the shortest result will be close to the query, as + (* name length is important not because short identifier are better in the + abstract, but because the shortest result will be close to the query, as the suffix tree does not return results shorter than the query*) - String.length name * 4 + (String.length name * 4) (* + (5 * List.length path) TODO : restore depth based ordering *) + (if ignore_no_doc || has_doc then 0 else 100) + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 From 6d3608a8a90594f78671ea955afecf68cebcfad1 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 28 Jun 2023 17:25:59 +0200 Subject: [PATCH 119/285] temp commit --- test/cram/base.t/run.t | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index f47e574be6..fc9867d720 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -49,12 +49,12 @@ Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Either0.t - Indexing in 680.731058ms - Export in 603.530169ms + Indexing in 780.164003ms + Export in 694.236994ms - real 0m1.615s - user 0m1.546s - sys 0m0.064s + real 0m1.876s + user 0m1.820s + sys 0m0.047s $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -93,26 +93,25 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cp -r html /tmp $ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 722.393036ms - Export in 560.818911ms - $ sherlodoc --db=db_marshal.bin "group b" - val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t - val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t + Indexing in 853.119850ms + Export in 640.402079ms + $ sherlodoc --db=db_marshal.bin "group b" | sort val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t + val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t + val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t val Base.List.groupi : 'a t -> break:(int -> 'a -> 'a -> bool) -> 'a t t - val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list val Base.List.sort_and_group : 'a t -> compare:('a -> 'a -> int) -> 'a t t - val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t + val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.String.split_on_chars : t -> on:char list -> t list + val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list val Base.String.Escaping.split_on_chars : string -> on:char list -> escape_char:char -> string list + val Base.String.split_on_chars : t -> on:char list -> t list $ sherlodoc --db=db_marshal.bin "group by" + val Base.String.split_on_chars : t -> on:char list -> t list val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list + val Base.String.Escaping.split_on_chars : string -> on:char list -> escape_char:char -> string list val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list - val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list val Base.Hashtbl.group : ?growth_allowed:bool -> ?size:int -> 'a Key.t -> @@ -129,19 +128,20 @@ $ firefox /tmp/html/base/index.html combine:('b -> 'b -> 'b) -> 'r list -> ('a, 'b) t - val Base.String.split_on_chars : t -> on:char list -> t list - val Base.String.Escaping.split_on_chars : string -> on:char list -> escape_char:char -> string list + val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list + val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list $ sherlodoc --db=db_marshal.bin "map2" mod Base.Applicative.Make_using_map2 - sig Base.Applicative.Basic_using_map2 mod Base.Applicative.Make2_using_map2 mod Base.Applicative.Make3_using_map2 + sig Base.Applicative.Basic_using_map2 sig Base.Applicative.Basic2_using_map2 sig Base.Applicative.Basic3_using_map2 mod Base.Applicative.Make_using_map2_local - sig Base.Applicative.Basic_using_map2_local mod Base.Applicative.Make2_using_map2_local mod Base.Applicative.Make3_using_map2_local + sig Base.Applicative.Basic_using_map2_local $ sherlodoc --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> ?size:int -> From 1dfb39fbac8229e3bd77200accacc92051ba660f Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 5 Jul 2023 14:22:17 +0200 Subject: [PATCH 120/285] Fix prefixname --- index/pretty.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index/pretty.ml b/index/pretty.ml index 8ddc4100f4..1eb4d73424 100644 --- a/index/pretty.ml +++ b/index/pretty.ml @@ -108,7 +108,7 @@ let prefixname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string = fun n -> match full_name_aux (n :> Paths.Identifier.t) with | [] -> "" - | _ :: q -> String.concat "." q + | _ :: q -> q |> List.rev |> String.concat "." let show_type_name_verbose h : Paths.Path.Type.t -> _ = function | `Resolved t -> From 5321a8e0453fdd281b125f87c312ec68b0856d7f Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 5 Jul 2023 16:00:35 +0200 Subject: [PATCH 121/285] Type search of exceptions --- db/elt.ml | 6 +- index/load_doc.ml | 13 ++-- query/dynamic_cost.ml | 2 +- test/cram/base.t/run.t | 54 ++++++----------- test/cram/cli.t/main.mli | 7 +++ test/cram/cli.t/run.t | 118 +++++++++++++++++++----------------- test/cram/cli_poly.t/run.t | 4 +- test/cram/cli_small.t/run.t | 12 ++-- test/cram/simple.t/run.t | 8 +-- 9 files changed, 114 insertions(+), 110 deletions(-) diff --git a/db/elt.ml b/db/elt.ml index 4d689a06e8..6903e77cab 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -22,7 +22,7 @@ module Kind = struct | Doc | TypeDecl | Module - | Exception + | Exception of 'a | Class_type | Method | Class @@ -39,7 +39,7 @@ module Kind = struct let doc = Doc let type_decl = TypeDecl let module_ = Module - let exception_ = Exception + let exception_ type_path = Exception type_path let class_type = Class_type let method_ = Method let class_ = Class @@ -54,7 +54,7 @@ module Kind = struct | Doc -> "doc" | TypeDecl -> "type" | Module -> "mod" - | Exception -> "exn" + | Exception _ -> "exn" | Class_type -> "class" | Method -> "meth" | Class -> "class" diff --git a/index/load_doc.ml b/index/load_doc.ml index a9b53f9969..d98390b37b 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -21,7 +21,8 @@ let kind_cost (kind : Elt.Kind.t) = type_cost type_path | Doc -> 400 | TypeDecl | Module -> 0 - | Exception | Class_type | Method | Class | TypeExtension -> 1000 + | Exception _ | Class_type | Method | Class -> 10 + | TypeExtension -> 1000 | ExtensionConstructor _ | ModuleType -> 10 let cost ~name ~kind ~doc_html = @@ -220,7 +221,10 @@ let convert_kind (kind : Odoc_search.Entry.extra) = let paths = type_ |> searchable_type_of_record parent_type |> paths in Elt.Kind.field paths | Doc _ -> Doc - | Exception _ -> Exception + | Exception { args; res } -> + let searchable_type = searchable_type_of_constructor args res in + let paths = paths searchable_type in + Elt.Kind.exception_ paths | Class_type _ -> Class_type | Method _ -> Method | Class _ -> Class @@ -245,13 +249,14 @@ let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.extra) = | Module -> () | Value { value = _; type_ } -> register_type_expr ~db elt type_ | Doc _ -> () - | Exception _ -> () | Class_type _ -> () | Method _ -> () | Class _ -> () | TypeExtension _ -> () | ModuleType -> () - | ExtensionConstructor { args; res } | Constructor { args; res } -> + | ExtensionConstructor { args; res } + | Constructor { args; res } + | Exception { args; res } -> let type_ = searchable_type_of_constructor args res in register_type_expr ~db elt type_ | Field { mutable_ = _; parent_type; type_ } -> diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index d87435fe75..cc46476708 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -225,7 +225,7 @@ module Reasoning = struct | Elt.Kind.Doc -> Doc | Elt.Kind.TypeDecl -> TypeDecl | Elt.Kind.Module -> Module - | Elt.Kind.Exception -> Exception + | Elt.Kind.Exception _ -> Exception | Elt.Kind.Class_type -> Class_type | Elt.Kind.Method -> Method | Elt.Kind.Class -> Class diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index fc9867d720..110394e946 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -18,8 +18,6 @@ Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Int63_emul.t - Warning, resolved hidden path: Base__.Int63_emul.t Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t @@ -49,12 +47,12 @@ Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Either0.t - Indexing in 780.164003ms - Export in 694.236994ms + Indexing in 802.123070ms + Export in 625.782967ms - real 0m1.876s - user 0m1.820s - sys 0m0.047s + real 0m1.817s + user 0m1.735s + sys 0m0.063s $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -66,8 +64,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2824 db.js - 2132 db.js.gz + 2732 db.js + 2060 db.js.gz 1628 megaodocl.gz @@ -92,45 +90,31 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr odoc_search.js $ cp -r html /tmp $ firefox /tmp/html/base/index.html - $ sherlodoc_index --format=marshal --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 853.119850ms - Export in 640.402079ms + $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null + Indexing in 1257.050037ms + Export in 1118.567944ms $ sherlodoc --db=db_marshal.bin "group b" | sort + 'a Key.t -> + 'r list -> + ('a, 'b) t + ?size:int -> + combine:('b -> 'b -> 'b) -> + get_data:('r -> 'b) -> + get_key:('r -> 'a) -> + val Base.Hashtbl.group : ?growth_allowed:bool -> val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t val Base.List.groupi : 'a t -> break:(int -> 'a -> 'a -> bool) -> 'a t t val Base.List.sort_and_group : 'a t -> compare:('a -> 'a -> int) -> 'a t t val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t + val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.String.Escaping.split_on_chars : string -> on:char list -> escape_char:char -> string list - val Base.String.split_on_chars : t -> on:char list -> t list $ sherlodoc --db=db_marshal.bin "group by" - val Base.String.split_on_chars : t -> on:char list -> t list val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.String.Escaping.split_on_chars : string -> on:char list -> escape_char:char -> string list - val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Hashtbl.group : ?growth_allowed:bool -> - ?size:int -> - 'a Key.t -> - get_key:('r -> 'a) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t - val Base.Hashtbl.Creators.group : ?growth_allowed:bool -> - ?size:int -> - 'a Key.t -> - get_key:('r -> 'a) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t - val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list - val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list $ sherlodoc --db=db_marshal.bin "map2" mod Base.Applicative.Make_using_map2 mod Base.Applicative.Make2_using_map2 diff --git a/test/cram/cli.t/main.mli b/test/cram/cli.t/main.mli index 338adb4026..069546a5fb 100644 --- a/test/cram/cli.t/main.mli +++ b/test/cram/cli.t/main.mli @@ -65,3 +65,10 @@ val poly_param : 'a boo type extensible_type = .. type extensible_type += MyExtension of moo + +type exn_payload + +exception Implicit_exn of exn_payload +exception Explicit_exn : exn_payload -> exn +type exn += Very_explicit_exn : exn_payload -> exn + diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 2e2b2b84b8..29c612dfc2 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 2.419949ms - Export in 0.387192ms + Indexing in 2.393007ms + Export in 0.482798ms $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" val Main.unique_name : foo @@ -22,67 +22,67 @@ $ sherlodoc "nesting_priority" val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo - $ sherlodoc --print-cost "list" - 109 mod Main.List - 209 type Main.list - 315 type Main.List.t = 'a list - 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 318 val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 319 val Main.Map.to_list : foo - 326 val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 1108 val Main.foo : foo - 1154 doc page - $ sherlodoc --print-cost "map" - 108 mod Main.Map - 213 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 318 val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 320 val Main.Map.to_list : foo - 327 val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 1108 val Main.foo : foo - $ sherlodoc --print-cost "list map" - 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 422 val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 423 val Main.Map.to_list : foo - 431 val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 2108 val Main.foo : foo - $ sherlodoc --print-cost "map2" - 214 val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 327 val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - $ sherlodoc --print-cost ":moo" - 210 val Main.value : moo - 213 val Main.produce : unit -> moo - 217 val Main.produce_2' : unit -> unit -> moo - $ sherlodoc --print-cost ":moo -> _" - 212 val Main.consume : moo -> unit - 215 val Main.consume_2 : moo -> moo -> unit - 221 val Main.consume_2_other : moo -> t -> unit - 266 cons Main.MyExtension : moo -> extensible_type - $ sherlodoc --print-cost "modtype" - 112 sig Main.Modtype - 325 val Main.Modtype.v_modtype : foo - $ sherlodoc --print-cost "S" - 106 sig Main.S - 216 mod Main.List - 216 mod Main.Nest - 216 mod Main.S_to_S1 - 316 type Main.list - 318 type Main.List.t = 'a list - 319 val Main.consume : moo -> unit - 323 val Main.Map.to_list : foo - 373 cons Main.MyExtension : moo -> extensible_type - 1108 val Main.foo : foo - $ sherlodoc --print-cost "qwertyuiopasdfghjklzxcvbnm" + $ sherlodoc "list" + mod Main.List + val Main.foo : foo + type Main.list + type Main.List.t = 'a list + val Main.Map.to_list : foo + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + doc page + $ sherlodoc "map" + mod Main.Map + val Main.foo : foo + val Main.Map.to_list : foo + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + $ sherlodoc "list map" + val Main.foo : foo + val Main.Map.to_list : foo + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + $ sherlodoc "map2" + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + $ sherlodoc ":moo" + val Main.value : moo + val Main.produce : unit -> moo + val Main.produce_2' : unit -> unit -> moo + $ sherlodoc ":moo -> _" + cons Main.MyExtension : moo -> extensible_type + val Main.consume : moo -> unit + val Main.consume_2 : moo -> moo -> unit + val Main.consume_2_other : moo -> t -> unit + $ sherlodoc "modtype" + sig Main.Modtype + val Main.Modtype.v_modtype : foo + $ sherlodoc "S" + sig Main.S + mod Main.List + mod Main.Nest + val Main.foo : foo + mod Main.S_to_S1 + type Main.list + type Main.List.t = 'a list + val Main.Map.to_list : foo + cons Main.MyExtension : moo -> extensible_type + val Main.consume : moo -> unit + $ sherlodoc "qwertyuiopasdfghjklzxcvbnm" [No results] TODO : get a result for the query bellow - $ sherlodoc --print-cost "hidden" + $ sherlodoc "hidden" [No results] - $ sherlodoc --print-cost ":mo" + $ sherlodoc ":mo" [No results] $ sherlodoc ":'a" val Main.poly_1 : 'a -> 'b -> 'c - val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.poly_param : 'a boo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc ": 'a -> 'b -> 'c " @@ -98,3 +98,11 @@ TODO : get a result for the query bellow [No results] $ sherlodoc ":extensible_type" cons Main.MyExtension : moo -> extensible_type + $ sherlodoc ":exn" + exn Main.Explicit_exn : exn_payload -> exn + exn Main.Implicit_exn : exn_payload -> exn + cons Main.Very_explicit_exn : exn_payload -> exn + $ sherlodoc ": exn_payload -> _" + exn Main.Explicit_exn : exn_payload -> exn + exn Main.Implicit_exn : exn_payload -> exn + cons Main.Very_explicit_exn : exn_payload -> exn diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index b6f2afbbd3..b1e9d70f2d 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.655890ms - Export in 0.038862ms + Indexing in 0.592947ms + Export in 0.042915ms $ export SHERLODOC_DB=db.bin TODO : get a result for the query bellow $ sherlodoc ":'a" diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 7f39067bd6..5a2a365232 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,11 +5,11 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.247002ms - Export in 0.077963ms + Indexing in 0.222206ms + Export in 0.052929ms $ export SHERLODOC_DB=db.bin $ sherlodoc --print-cost "list" - 109 mod Main.List - 209 type Main.list - 315 type Main.List.t = 'a list - 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 36 mod Main.List + 136 type Main.list + 144 type Main.List.t = 'a list + 222 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 1f8cb4d6cf..a1ba015aa2 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -7,11 +7,11 @@ $ du -sh megaodocl 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.532078ms - Export in 0.615835ms + Indexing in 1.632929ms + Export in 0.807047ms $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.391172ms - Export in 0.612020ms + Indexing in 1.590014ms + Export in 0.725985ms $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null From b74c748064f2b1c128335c170afbc26d3b9737cf Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 5 Jul 2023 18:49:29 +0200 Subject: [PATCH 122/285] Succ bugfix and better testing --- query/succ.ml | 32 +++++++++++------- query/test/test.ml | 74 ++++++++++++++++++++++++------------------ test/cram/base.t/run.t | 18 ++++++---- 3 files changed, 74 insertions(+), 50 deletions(-) diff --git a/query/succ.ml b/query/succ.ml index e52b558e75..877abd6b3b 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -103,7 +103,6 @@ let array_succ ~strictness = | Gt -> Array_succ.succ_gt let rec succ ~compare ~strictness t elt = - (* Printf.printf "depth : %i\n" depth ; *) match t with | All -> invalid_arg "Succ.succ_rec All" | Empty -> None @@ -114,30 +113,30 @@ let rec succ ~compare ~strictness t elt = best_opt ~compare elt_l elt_r | Inter (l, r) -> let rec loop elt_r = - let* elt_l = succ ~compare ~strictness l elt_r in + let* elt_l = succ ~compare ~strictness:Ge l elt_r in let* elt_r = succ ~compare ~strictness:Ge r elt_l in if compare elt_l elt_r = 0 then Some elt_l else loop elt_r in - loop elt + let* elt_l = succ ~compare ~strictness l elt in + loop elt_l let succ_ge ~compare t elt = succ ~compare ~strictness:Ge t elt let succ_gt ~compare t elt = succ ~compare ~strictness:Gt t elt -let rec first ~compare candidate t = +let rec first ~compare t = match t with | All -> invalid_arg "Succ.first All" | Empty -> None - | Array s -> best_opt ~compare candidate (Some s.(0)) - | Inter (a, _) -> - let* elt = first ~compare candidate a in + | Array s -> Some s.(0) + | Inter (l, _) -> + let* elt = first ~compare l in succ_ge ~compare t elt - | Union (a, b) -> begin - let candidate = first ~compare candidate a in - first ~compare candidate b + | Union (l, r) -> begin + let elt_l = first ~compare l in + let elt_r = first ~compare r in + best_opt ~compare elt_l elt_r end -let first ~compare t = first ~compare None t - let first_exn ~compare t = match first ~compare t with | Some v -> v @@ -154,6 +153,15 @@ let to_seq ~compare t = state := elt ; elt in + (* Here, as stackoverflow could be thrown. In that case, we do not want to + crash, as a more complex search will probably not trigger the stackoverflow, + and we want the webworker or server to be running when such a request is + inputed. + The Printexc is very important as we nee dto be able to tell if the + situation described above happens. + With the current algorithm, such a stackoverflow is never triggered even + on big libraries like Base, but it is not tail-rec, so a big enough search + db could trigger it. *) let next () = try Printexc.print loop () with _ -> None in Seq.of_dispenser next diff --git a/query/test/test.ml b/query/test/test.ml index ee1fbb6055..8b211cf532 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -1,7 +1,5 @@ open Query.Private -let print_int ~ch i = output_string ch (string_of_int i) - module Test_array = struct let rec succ_ge_reference i ~compare elt arr = Printf.printf "ref_succ_ge %i\n%!" i ; @@ -130,6 +128,34 @@ module Test_succ = struct let _ = first_reference + let extra_succ = + Succ.( + union + (inter (of_array [| 0; 1|]) (of_array [| 0; 1;|])) + (inter + (of_array [| 0; 2; 3 |]) + (of_array [| 1; 3; 5; 7 |]))) + + let to_seq_reference ~compare t = + let state = ref None in + let loop () = + let elt = + match !state with + | None -> + print_endline "None" ; + first_reference ~compare t + | Some previous_elt -> + Printf.printf "Some %i\n%!" previous_elt ; + succ_reference ~strictness:Gt ~compare t previous_elt + in + state := elt ; + elt + in + let next () = try Printexc.print loop () with _ -> None in + Seq.of_dispenser next + + let to_seq_reference t = to_seq_reference t.Succ.s + let rec random_succ size = if size = 0 then Succ.empty @@ -143,39 +169,25 @@ module Test_succ = struct | 2 -> Succ.union (random_succ (size / 2)) (random_succ (size / 2)) | _ -> assert false - let random_succ size = - let t = random_succ size in - t.s - - let tests_succ name test = - List.init 20 (fun i -> - let i = i * 5 in - let elt = Random.full_int ((i * 2) + 1) in - let succ = random_succ i in - Alcotest.test_case - (Printf.sprintf "%s size %i elt %i" name i elt) - `Quick (test elt succ)) - - let tests_succ_gt elt tree () = - let strictness = Succ.Gt in - Alcotest.(check (option int)) - "same int option" - (succ_reference ~strictness ~compare:Int.compare tree elt) - (Succ.succ ~strictness ~compare:Int.compare tree elt) - - let tests_succ_ge elt tree () = - let strictness = Succ.Ge in - let ref = succ_reference ~strictness ~compare:Int.compare tree elt in - let real = Succ.succ ~strictness ~compare:Int.compare tree elt in - Alcotest.(check (option int)) "same int option" ref real - - let tests_succ_ge = tests_succ "succ_ge" tests_succ_ge - let tests_succ_gt = tests_succ "succ_gt" tests_succ_gt + let test_to_seq tree () = + let ref = tree |> to_seq_reference ~compare:Int.compare |> List.of_seq in + let real = tree |> Succ.to_seq ~compare:Int.compare |> List.of_seq in + Alcotest.(check (list int)) "same int list" ref real + + let tests_to_seq = + [ Alcotest.test_case "Succ.to_seq extra" `Quick (test_to_seq extra_succ) ] + @ List.init 50 (fun i -> + let i = i * 7 in + let succ = random_succ i in + if i = 75 then Succ.print print_int succ ; + Alcotest.test_case + (Printf.sprintf "Succ.to_seq size %i" i) + `Quick (test_to_seq succ)) end let () = let open Alcotest in run "Query" [ "Array_succ", Test_array.tests_succ_ge @ Test_array.tests_succ_gt - ; "Succ", Test_succ.tests_succ_ge @ Test_succ.tests_succ_gt + ; "Succ", Test_succ.tests_to_seq ] diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 110394e946..1d46486d49 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -47,12 +47,12 @@ Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Either0.t - Indexing in 802.123070ms - Export in 625.782967ms + Indexing in 2168.125868ms + Export in 1096.270084ms - real 0m1.817s - user 0m1.735s - sys 0m0.063s + real 0m4.273s + user 0m4.055s + sys 0m0.170s $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -91,8 +91,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cp -r html /tmp $ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 1257.050037ms - Export in 1118.567944ms + Indexing in 1701.007128ms + Export in 951.998949ms $ sherlodoc --db=db_marshal.bin "group b" | sort 'a Key.t -> 'r list -> @@ -113,8 +113,12 @@ $ firefox /tmp/html/base/index.html val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list $ sherlodoc --db=db_marshal.bin "group by" val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list + val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list + val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.Creators_and_accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list $ sherlodoc --db=db_marshal.bin "map2" mod Base.Applicative.Make_using_map2 mod Base.Applicative.Make2_using_map2 From 571a01f7b68cc7f923fa31d2a78a1c1934179d3b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 5 Jul 2023 18:54:05 +0200 Subject: [PATCH 123/285] format --- query/test/test.ml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/query/test/test.ml b/query/test/test.ml index 8b211cf532..3e234261db 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -131,10 +131,8 @@ module Test_succ = struct let extra_succ = Succ.( union - (inter (of_array [| 0; 1|]) (of_array [| 0; 1;|])) - (inter - (of_array [| 0; 2; 3 |]) - (of_array [| 1; 3; 5; 7 |]))) + (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) + (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |]))) let to_seq_reference ~compare t = let state = ref None in From e83d176ca94a285cd8446f67260381c06c717963 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 6 Jul 2023 15:14:19 +0200 Subject: [PATCH 124/285] Succ cleanup --- query/query.ml | 1 + query/succ.ml | 130 +++++++++++++++++++++----------------------- query/succ.mli | 24 +++++++++ query/test/test.ml | 131 +++++++++++++-------------------------------- 4 files changed, 123 insertions(+), 163 deletions(-) create mode 100644 query/succ.mli diff --git a/query/query.ml b/query/query.ml index ba761d4e4a..0590eb36a6 100644 --- a/query/query.ml +++ b/query/query.ml @@ -96,6 +96,7 @@ let api ~(shards : Db.t list) ?(dynamic_sort = true) params = Parser.of_string params.query in let results = search ~shards query_name query_typ in + let results = Succ.finish results in let results = Succ.to_seq ~compare:Db.Elt.compare results in let results = match_packages ~packages:params.packages results in let results = List.of_seq @@ Seq.take params.limit results in diff --git a/query/succ.ml b/query/succ.ml index 877abd6b3b..43e3b2af3b 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,16 +1,11 @@ -type 'a s = +type 'a t = | All | Empty | Array of 'a array - | Inter of 'a s * 'a s - | Union of 'a s * 'a s - -type 'a t = - { cardinal : int - ; s : 'a s - } + | Inter of 'a t * 'a t + | Union of 'a t * 'a t -let rec print_s a ~depth s = +let rec print a ~depth s = print_string (String.make (depth * 4) ' ') ; let depth = depth + 1 in match s with @@ -18,12 +13,12 @@ let rec print_s a ~depth s = | Empty -> print_endline "Empty" | Inter (l, r) -> print_endline "Inter" ; - print_s a ~depth l ; - print_s a ~depth r + print a ~depth l ; + print a ~depth r | Union (l, r) -> print_endline "Union" ; - print_s a ~depth l ; - print_s a ~depth r + print a ~depth l ; + print a ~depth r | Array arr -> print_string "{ " ; Array.iter @@ -33,50 +28,7 @@ let rec print_s a ~depth s = arr ; print_endline "}" -let print_s a s = print_s a ~depth:0 s -let print a t = print_s a t.s -let all = { cardinal = -1; s = All } -let empty = { cardinal = 0; s = Empty } - -let of_array arr = - if Array.length arr = 0 - then empty - else { cardinal = Array.length arr; s = Array arr } - -let inter a b = - match a.s, b.s with - | Empty, _ | _, Empty -> empty - | _, All -> a - | All, _ -> b - | x, y when x == y -> a - | x, y -> - let x, y = if a.cardinal < b.cardinal then x, y else y, x in - { cardinal = min a.cardinal b.cardinal; s = Inter (x, y) } - -let union a b = - match a.s, b.s with - | Empty, _ -> b - | _, Empty -> a - | All, _ | _, All -> all - | x, y when x == y -> a - | x, y -> - let x, y = if a.cardinal < b.cardinal then x, y else y, x in - { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } - -let union_of_array arr = - let rec loop lo hi = - match hi - lo with - | 0 -> empty - | 1 -> arr.(lo) - | dist -> - let mid = lo + (dist / 2) in - let left = loop lo mid in - let right = loop mid hi in - union left right - in - loop 0 (Array.length arr) - -let union_of_list li = li |> Array.of_list |> union_of_array +let print a s = print a ~depth:0 s let best ~compare x y = match compare x y with @@ -91,7 +43,6 @@ let best_opt ~compare old_cand new_cand = | Some x, Some y -> Some (best ~compare x y) let ( let* ) = Option.bind -let ( let+ ) x f = Option.map f x type strictness = | Gt @@ -120,9 +71,6 @@ let rec succ ~compare ~strictness t elt = let* elt_l = succ ~compare ~strictness l elt in loop elt_l -let succ_ge ~compare t elt = succ ~compare ~strictness:Ge t elt -let succ_gt ~compare t elt = succ ~compare ~strictness:Gt t elt - let rec first ~compare t = match t with | All -> invalid_arg "Succ.first All" @@ -130,25 +78,20 @@ let rec first ~compare t = | Array s -> Some s.(0) | Inter (l, _) -> let* elt = first ~compare l in - succ_ge ~compare t elt + succ ~strictness:Ge ~compare t elt | Union (l, r) -> begin let elt_l = first ~compare l in let elt_r = first ~compare r in best_opt ~compare elt_l elt_r end -let first_exn ~compare t = - match first ~compare t with - | Some v -> v - | None -> raise Not_found - let to_seq ~compare t = let state = ref None in let loop () = let elt = match !state with | None -> first ~compare t - | Some previous_elt -> succ_gt ~compare t previous_elt + | Some previous_elt -> succ ~strictness:Gt ~compare t previous_elt in state := elt ; elt @@ -165,4 +108,53 @@ let to_seq ~compare t = let next () = try Printexc.print loop () with _ -> None in Seq.of_dispenser next -let to_seq t = to_seq t.s +(** Functions to build a succ tree *) + +type 'a builder = + { cardinal : int + ; s : 'a t + } + +let finish a = a.s +let all = { cardinal = -1; s = All } +let empty = { cardinal = 0; s = Empty } + +let of_array arr = + if Array.length arr = 0 + then empty + else { cardinal = Array.length arr; s = Array arr } + +let inter a b = + match a.s, b.s with + | Empty, _ | _, Empty -> empty + | _, All -> a + | All, _ -> b + | x, y when x == y -> a + | x, y -> + let x, y = if a.cardinal < b.cardinal then x, y else y, x in + { cardinal = min a.cardinal b.cardinal; s = Inter (x, y) } + +let union a b = + match a.s, b.s with + | Empty, _ -> b + | _, Empty -> a + | All, _ | _, All -> all + | x, y when x == y -> a + | x, y -> + let x, y = if a.cardinal < b.cardinal then x, y else y, x in + { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } + +let union_of_array arr = + let rec loop lo hi = + match hi - lo with + | 0 -> empty + | 1 -> arr.(lo) + | dist -> + let mid = lo + (dist / 2) in + let left = loop lo mid in + let right = loop mid hi in + union left right + in + loop 0 (Array.length arr) + +let union_of_list li = li |> Array.of_list |> union_of_array diff --git a/query/succ.mli b/query/succ.mli new file mode 100644 index 0000000000..8a8e01a056 --- /dev/null +++ b/query/succ.mli @@ -0,0 +1,24 @@ +(** This module provides a way to get the first n elements of a very large set + without computing the other elements. *) + +type 'a t + +val print : ('a -> unit) -> 'a t -> unit +val to_seq : compare:('a -> 'a -> int) -> 'a t -> 'a Seq.t + +(** Functions to build a succ tree *) + +type 'a builder + +val finish : 'a builder -> 'a t +val all : 'a builder +val empty : 'a builder + +val of_array : 'a array -> 'a builder +(** Warning : only provide a sorted array, this is not checked ! + It also has to be sorted according to the [compare] function that you will + eventually pass to [to_seq] *) + +val inter : 'a builder -> 'a builder -> 'a builder +val union : 'a builder -> 'a builder -> 'a builder +val union_of_list : 'a builder list -> 'a builder diff --git a/query/test/test.ml b/query/test/test.ml index 3e234261db..2ab4cd91da 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -67,117 +67,60 @@ end open Query module Test_succ = struct - let rec mem ~compare t elt = - let open Succ in - match t with - | All -> invalid_arg "Succ.succ_rec All" - | Empty -> false - | Array arr -> Array.exists (fun elt' -> compare elt elt' = 0) arr - | Union (l, r) -> mem ~compare l elt || mem ~compare r elt - | Inter (l, r) -> mem ~compare l elt && mem ~compare r elt - - let ( let* ) = Option.bind - let ( let+ ) x f = Option.map f x - - let array_succ_reference ~strictness = - let open Succ in - match strictness with - | Ge -> Test_array.succ_ge_reference - | Gt -> Test_array.succ_gt_reference - - let rec succ_reference ~compare ~strictness t elt = - (* Printf.printf "depth : %i\n" depth ; *) - match t with - | Succ.All -> invalid_arg "Succ.succ_rec All" - | Empty -> None - | Array arr -> array_succ_reference ~strictness ~compare elt arr - | Union (l, r) -> - let elt_r = succ_reference ~compare ~strictness r elt in - let elt_l = succ_reference ~compare ~strictness l elt in - Succ.best_opt ~compare elt_l elt_r - | Inter (l, r) -> - let rec loop elt = - if mem ~compare r elt - then Some elt - else - let* elt = succ_reference ~compare ~strictness:Gt l elt in - loop elt - in - let* elt = succ_reference ~compare ~strictness l elt in - loop elt - - let rec first_reference ~compare t = - match t with - | Succ.All -> invalid_arg "Succ.first All" - | Empty -> None - | Array s -> Some s.(0) - | Inter (l, r) -> - let rec loop elt = - let* elt = elt in - if mem ~compare r elt - then Some elt - else - let elt = succ_reference ~strictness:Gt ~compare l elt in - loop elt - in - loop (first_reference ~compare l) - | Union (l, r) -> - Succ.best_opt ~compare - (first_reference ~compare l) - (first_reference ~compare r) - - let _ = first_reference + (** This module does the same thing as Succ, but its correctness is obvious + and its performance terrible. *) + module Reference = struct + include Set.Make (Int) + + let of_array arr = arr |> Array.to_seq |> of_seq + let to_seq ~compare:_ = to_seq + end + + (** This module is used to construct a pair of a "set array" using [Reference] + and a Succ that are exactly the same. *) + module Both = struct + let empty = Reference.empty, Succ.empty + let union (l, l') (r, r') = Reference.union l r, Succ.union l' r' + let inter (l, l') (r, r') = Reference.inter l r, Succ.inter l' r' + let of_array arr = Reference.of_array arr, Succ.of_array arr + let finish (arr, succ) = arr, Succ.finish succ + end let extra_succ = - Succ.( - union - (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) - (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |]))) - - let to_seq_reference ~compare t = - let state = ref None in - let loop () = - let elt = - match !state with - | None -> - print_endline "None" ; - first_reference ~compare t - | Some previous_elt -> - Printf.printf "Some %i\n%!" previous_elt ; - succ_reference ~strictness:Gt ~compare t previous_elt - in - state := elt ; - elt - in - let next () = try Printexc.print loop () with _ -> None in - Seq.of_dispenser next - - let to_seq_reference t = to_seq_reference t.Succ.s - - let rec random_succ size = + Both.( + finish + @@ union + (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) + (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |]))) + + let rec random_set ~empty ~union ~inter ~of_array size = + let random_set = random_set ~empty ~union ~inter ~of_array in if size = 0 - then Succ.empty + then empty else match Random.int 3 with | 0 -> let arr = Test_array.random_array size in Array.sort Int.compare arr ; - Succ.of_array arr - | 1 -> Succ.inter (random_succ (size / 2)) (random_succ (size / 2)) - | 2 -> Succ.union (random_succ (size / 2)) (random_succ (size / 2)) + of_array arr + | 1 -> inter (random_set (size / 2)) (random_set (size / 2)) + | 2 -> union (random_set (size / 2)) (random_set (size / 2)) | _ -> assert false let test_to_seq tree () = - let ref = tree |> to_seq_reference ~compare:Int.compare |> List.of_seq in - let real = tree |> Succ.to_seq ~compare:Int.compare |> List.of_seq in + let ref = + fst tree |> Reference.to_seq ~compare:Int.compare |> List.of_seq + in + let real = snd tree |> Succ.to_seq ~compare:Int.compare |> List.of_seq in Alcotest.(check (list int)) "same int list" ref real let tests_to_seq = [ Alcotest.test_case "Succ.to_seq extra" `Quick (test_to_seq extra_succ) ] @ List.init 50 (fun i -> let i = i * 7 in - let succ = random_succ i in - if i = 75 then Succ.print print_int succ ; + let succ = + i |> Both.(random_set ~empty ~union ~inter ~of_array) |> Both.finish + in Alcotest.test_case (Printf.sprintf "Succ.to_seq size %i" i) `Quick (test_to_seq succ)) From 1a31504ba27b299245a88566e4e702c6f1dc05ae Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 7 Jul 2023 14:53:38 +0200 Subject: [PATCH 125/285] Cleanup query api --- query/query.ml | 2 +- query/query.mli | 5 +---- query/test/test.ml | 2 -- www/www.ml | 1 - 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/query/query.ml b/query/query.ml index 0590eb36a6..91b1830758 100644 --- a/query/query.ml +++ b/query/query.ml @@ -1,5 +1,4 @@ module Parser = Query_parser -module Succ = Succ module Dynamic_cost = Dynamic_cost module Storage = Db.Storage module Tree = Db.Suffix_tree.With_elts @@ -9,6 +8,7 @@ module Occ = Db.Occ module Private = struct module Array_succ = Array_succ + module Succ = Succ end let inter_list xs = List.fold_left Succ.inter Succ.all xs diff --git a/query/query.mli b/query/query.mli index 6681744bf8..ff2acddf2d 100644 --- a/query/query.mli +++ b/query/query.mli @@ -1,7 +1,3 @@ -module Parser = Query_parser -module Succ = Succ -module Dynamic_cost = Dynamic_cost - type t = { query : string ; packages : string list @@ -13,4 +9,5 @@ val api : shards:Db.t list -> ?dynamic_sort:bool -> t -> string * Db.Elt.t list (** For testing *) module Private : sig module Array_succ = Array_succ + module Succ = Succ end diff --git a/query/test/test.ml b/query/test/test.ml index 2ab4cd91da..8fb20c5a3b 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -64,8 +64,6 @@ module Test_array = struct let tests_succ_gt = tests_arr "succ_gt" test_succ_gt end -open Query - module Test_succ = struct (** This module does the same thing as Succ, but its correctness is obvious and its performance terrible. *) diff --git a/www/www.ml b/www/www.ml index 5a2890377a..5e70bfc574 100644 --- a/www/www.ml +++ b/www/www.ml @@ -1,5 +1,4 @@ module Storage = Db.Storage -module Succ = Query.Succ module H = Tyxml.Html let api ~shards params = From 9fe953d570985ccec92f68af4727c8910452f19b Mon Sep 17 00:00:00 2001 From: Thomas Refis Date: Thu, 13 Jul 2023 16:13:57 +0200 Subject: [PATCH 126/285] Pass id to entries_of_item --- index/index.ml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/index/index.ml b/index/index.ml index 98bff5e656..4151d2c088 100644 --- a/index/index.ml +++ b/index/index.ml @@ -2,12 +2,16 @@ let index_file register filename = match Fpath.of_string filename with | Error (`Msg msg) -> Format.printf "FILE ERROR %s: %s@." filename msg | Ok file -> ( - match - Odoc_odoc.Indexing.handle_file - ~page:(Odoc_model.Fold.page ~f:register ()) - ~unit:(Odoc_model.Fold.unit ~f:register ()) - file - with + 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 | Ok (Some result) -> result | Ok None -> () | Error (`Msg msg) -> Format.printf "ODOC ERROR %s: %s@." filename msg) @@ -20,10 +24,10 @@ let storage_module = function let main files index_docstring index_name type_search db_filename db_format = let module Storage = (val storage_module db_format) in let db = Db.make () in - let register () item = + let register id () item = List.iter (Load_doc.register_entry ~db ~index_docstring ~index_name ~type_search) - (Odoc_search.Entry.entries_of_item item) + (Odoc_search.Entry.entries_of_item id item) in let h = Storage.open_out db_filename in let t0 = Unix.gettimeofday () in From 3fb1411d9a024b661bc222a4cd700374140133cf Mon Sep 17 00:00:00 2001 From: Thomas Refis Date: Thu, 13 Jul 2023 16:39:52 +0200 Subject: [PATCH 127/285] pretty: fix build, does this module make sense? --- index/pretty.ml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/index/pretty.ml b/index/pretty.ml index 1eb4d73424..f52efc0a24 100644 --- a/index/pretty.ml +++ b/index/pretty.ml @@ -18,7 +18,10 @@ and show_ident_short h (r : Paths.Identifier.t_pv Paths.Identifier.id) = | `CoreType n -> Format.fprintf h "%s" (Names.TypeName.to_string n) | _ -> Format.fprintf h "%S" (Paths.Identifier.name r) -and show_module_t h = function +and show_module_t h p = + Format.fprintf h "%s" (Odoc_document.Url.render_path (p : Paths.Path.Module.t :> Paths.Path.t)) + (* + function | `Resolved t -> let open Paths.Path in Format.fprintf h "%a" show_ident_long @@ -30,6 +33,7 @@ and show_module_t h = function | `Forward str -> Format.fprintf h "%s" str | `Result _ -> () | `Identifier _ -> () + *) and show_module_path h = function | `Identifier (`Module (_, md)) -> @@ -100,6 +104,12 @@ let rec full_name_aux : Paths.Identifier.t -> string list = InstanceVariableName.to_string name :: full_name_aux (parent :> t) | `Label (parent, name) -> LabelName.to_string name :: full_name_aux (parent :> t) + | `AssetFile (parent, name) -> name :: full_name_aux (parent :> t) + | `SourceDir (parent, name) -> name :: full_name_aux (parent :> t) + | `SourcePage (parent, name) -> name :: full_name_aux (parent :> t) + | `SourceLocation (parent, name) -> + DefName.to_string name :: full_name_aux (parent :> t) + | `SourceLocationMod id -> full_name_aux (id :> t) let fullname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string list = fun n -> List.rev @@ full_name_aux (n :> Paths.Identifier.t) From ad0424113c000b6276eb937e44d23c11e6d3cff3 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 17 Jul 2023 10:53:18 +0200 Subject: [PATCH 128/285] WIP compatibility with odoc PR --- cli/main.ml | 19 +++- db/elt.ml | 14 --- index/load_doc.ml | 28 ++--- index/pretty.ml | 2 +- jsoo/main.ml | 39 +++++-- .../cram/base.t/base_internalhash_types.odocl | Bin 3353 -> 3329 bytes test/cram/base.t/md5_lib.odocl | Bin 2391 -> 2341 bytes test/cram/base.t/page-index.odocl | Bin 39593 -> 38650 bytes test/cram/base.t/run.t | 104 ++++++++---------- test/cram/cli.t/run.t | 4 +- test/cram/cli_poly.t/run.t | 4 +- test/cram/cli_small.t/run.t | 4 +- test/cram/simple.t/run.t | 41 ++----- www/ui.ml | 19 +++- 14 files changed, 140 insertions(+), 138 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index b20beff31e..f042e39c88 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -1,9 +1,26 @@ let pp_or cond pp_true pp_false ppf = if cond then pp_true ppf else pp_false ppf +let string_of_kind = + let open Db.Elt.Kind in + function + | Doc -> "doc" + | TypeDecl -> "type" + | Module -> "mod" + | Exception _ -> "exn" + | Class_type -> "class" + | Method -> "meth" + | Class -> "class" + | TypeExtension -> "type" + | ExtensionConstructor _ -> "cons" + | ModuleType -> "sig" + | Constructor _ -> "cons" + | Field _ -> "field" + | Val _ -> "val" + let print_result ~print_cost Db.Elt.{ name; rhs; url = _; kind; score; doc_html = _; pkg = _ } = let score = if print_cost then string_of_int score ^ " " else "" in - let kind = kind |> Db.Elt.Kind.to_string |> Unescape.string in + let kind = kind |> string_of_kind |> Unescape.string in let name = Unescape.string name in let pp_rhs h = function | None -> () diff --git a/db/elt.ml b/db/elt.ml index 6903e77cab..c948898b03 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -50,20 +50,6 @@ module Kind = struct let field type_path = Field type_path let val_ type_path = Val type_path - let to_string = function - | Doc -> "doc" - | TypeDecl -> "type" - | Module -> "mod" - | Exception _ -> "exn" - | Class_type -> "class" - | Method -> "meth" - | Class -> "class" - | TypeExtension -> "type" - | ExtensionConstructor _ -> "cons" - | ModuleType -> "sig" - | Constructor _ -> "cons" - | Field _ -> "field" - | Val _ -> "val" end module Package = struct diff --git a/index/load_doc.ml b/index/load_doc.ml index d98390b37b..fcd82c94a8 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -135,8 +135,8 @@ let rec type_paths ~prefix ~sgn = function (type_paths ~prefix ~sgn:(Types.sgn_not sgn) a) (type_paths ~prefix ~sgn b) | Constr (name, args) -> - rev_concat - @@ List.map (fun name -> + name |> all_type_names + |> List.map (fun name -> let name = String.concat "." name in let prefix = name :: Types.string_of_sgn sgn :: prefix in begin @@ -150,7 +150,7 @@ let rec type_paths ~prefix ~sgn = function type_paths ~prefix ~sgn arg) args end) - @@ all_type_names name + |> rev_concat | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args | _ -> [] @@ -205,7 +205,7 @@ let searchable_type_of_record parent_type type_ = let open Odoc_model.Lang in TypeExpr.Arrow (None, parent_type, type_) -let convert_kind (kind : Odoc_search.Entry.extra) = +let convert_kind (kind : Odoc_search.Entry.kind) = let open Odoc_search.Entry in match kind with | TypeDecl _ -> Elt.Kind.TypeDecl @@ -239,7 +239,7 @@ let register_type_expr ~db elt type_ = let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in Db.store_type_paths db elt type_paths -let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.extra) = +let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.kind) = let open Odoc_search.Entry in let open Odoc_model.Lang in if type_search @@ -264,15 +264,11 @@ let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.extra) = register_type_expr ~db elt type_ let register_entry ~db ~index_name ~type_search ~index_docstring - Odoc_search.Entry. - { id : Odoc_model.Paths.Identifier.Any.t - ; doc : Odoc_model.Comment.docs - ; extra : extra - } = + Odoc_search.Entry.{ id; doc; kind } = let open Odoc_search in let open Odoc_search.Entry in let is_type_extension = - match extra with + match kind with | TypeExtension _ -> true | _ -> false in @@ -286,20 +282,20 @@ let register_entry ~db ~index_name ~type_search ~index_docstring | "" -> "" | _ -> doc |> Render.html_of_doc |> string_of_html in - let kind' = convert_kind extra in + let kind' = convert_kind kind in let name = - match extra with + match kind with | Doc _ -> Pretty.prefixname id | _ -> full_name in let score = cost ~name ~kind:kind' ~doc_html in - let rhs = Json_display.rhs_of_kind extra in + let rhs = Generator.rhs_of_kind kind in let url = Render.url id in let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in if index_docstring then register_doc ~db elt doc_txt ; (if index_name then - match extra with + match kind with | Doc _ -> () | _ -> register_full_name ~db full_name elt) ; - register_kind ~db ~type_search elt extra + register_kind ~db ~type_search elt kind diff --git a/index/pretty.ml b/index/pretty.ml index f52efc0a24..0642be14e9 100644 --- a/index/pretty.ml +++ b/index/pretty.ml @@ -25,7 +25,7 @@ and show_module_t h p = | `Resolved t -> let open Paths.Path in Format.fprintf h "%a" show_ident_long - (Resolved.Module.identifier t + (Resolved.identifier (t : Resolved.Module.t :> Resolved.t) :> Paths.Identifier.t_pv Paths.Identifier.id) | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x | `Root x -> Format.fprintf h "%s" x diff --git a/jsoo/main.ml b/jsoo/main.ml index 157537a999..171066b1d9 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -76,6 +76,24 @@ let inflate str = let db = Jv.(inflate @@ call global "sherlodoc_db" [||]) |> Fut.map Storage_js.load +let string_of_kind = + let open Db.Elt.Kind in + let open Odoc_search.Generator in + function + | Db.Elt.Kind.Doc -> kind_doc + | TypeDecl -> kind_typedecl + | Module -> kind_module + | Exception _ -> kind_exception + | Class_type -> kind_class_type + | Method -> kind_method + | Class -> kind_class + | TypeExtension -> kind_extension + | ExtensionConstructor _ -> kind_extension_constructor + | ModuleType -> kind_module_type + | Constructor _ -> kind_constructor + | Field _ -> kind_field + | Val _ -> kind_value + let search message = don't_wait_for @@ @@ -91,14 +109,21 @@ let search message = Jv.(apply (get global "postMessage")) [| Jv.of_list (fun Db.Elt.{ name; rhs; doc_html; kind; url; _ } -> - let kind = Db.Elt.Kind.to_string kind in - let json_display = - Odoc_search.Json_display.of_strings - ~id:(String.split_on_char '.' name) - ~rhs ~doc:doc_html ~kind ~url + let kind = string_of_kind kind in + let prefix_name, name = + let rev_name = name |> String.split_on_char '.' |> List.rev in + ( rev_name |> List.tl |> List.rev |> String.concat "." + , List.hd rev_name ) + in + let html = + Odoc_search.Generator.html_of_strings ~kind ~prefix_name ~name + ~typedecl_params:None (*TODO pass value*) + ~rhs ~doc:doc_html + |> List.map (Format.asprintf "%a" (Tyxml.Html.pp_elt ())) + |> String.concat "\n" in - json_display |> Odoc_html.Json.to_string |> Jstr.of_string - |> Brr.Json.decode |> Result.get_ok) + + Jv.obj [| "html", Jv.of_string html; url, Jv.of_string url |]) results |] in diff --git a/test/cram/base.t/base_internalhash_types.odocl b/test/cram/base.t/base_internalhash_types.odocl index 61d01f3f946cb0fb80b6d114c142d3aa0b10dfd1..35ce6a6d4531eacba5da2a3b8092d7f886fc4846 100644 GIT binary patch delta 48 zcmbO!)hIP#DX%{R15+0R1IIBSHrlx98Y7=lfdLcGrn}oYRdeDC3?|R#P~3c;$%_jB DQDP3B delta 72 zcmZpankhA5DQ`Lh15+0R1IHO4Hr=@C8l#$CacW{waz=bkVp3{Oydjfn_}wf{!<=|j P;mP{kikr7Hd2s;%H&hp8 diff --git a/test/cram/base.t/md5_lib.odocl b/test/cram/base.t/md5_lib.odocl index 0016dea28f2c05d3304d51e2b8c6da69bd893a91..befe8c4c98c9eab1a805d0b644ccb4de2a0a4bd9 100644 GIT binary patch delta 62 zcmcaEv{Yz93-1&L2F4Q%3~W3M46Lg+PBdrYRVpxGl5f?0YMK*YV6gce({_-MA(M&D O)kz>B!_B8zdzb+>I}Xl=&;PmS3_gR^r*PXB zanGw#C0|jgT8dPv=H>3|0iCJA3a-+}yZE}Q2CF!1j**|Jo74(sV9$%OJc1d-<(hvX z3T7dyr#GBnR>6At=C=7T1#^%(@cj?L9O6fj*E9;|!T2NZEx|nE3VjDC*arLH=VyX# zhz*7Tt%3zG&fNG-uz+|aVU=JzgdMx+C)keIl2k>KI3Vw6`x3zpdDxs0vcuHigqXEC zJwf7-Iac0nS>MZ%)$cCR5INt7{krEG_AY zj=C!PCC-%T#WKDm(=ACuTHUzR=9YXF60G$Hi>1xY^U4VZXM;ks+AXIQo>vnm2UsBOD>^x_rKv+BC^&(u z?axBNDKef|dF*g85m+l^n+7aIV68Ia=~U|!$UtuJqs)LWg%mK_9Cuj z<@}Nf(hkdk!5uP!khYUwTDdiRoE5{fJjCA>*Ve+U*p&J+%@|6xVg%^nwNz$pCE{X~Xy^0dSl1ehfL@0s^F-Z5`=y`5me!p{`^ZcLZT^)n_Pa)cu ze8;3vSUVMp?p%eUqhV-p(Yn7q*x1%|F3{R|CfFJf0LGRdB$!(RTRziNm4Q)Zo6@!w z7a=o}xr}g;T0%NzRsBXZM?*iX|RD^g}j4w>-RdKucf17p$TbJzsWNI{ z&DjAphx;JI7k!CwbI8CJZ0YK}16x87oZvdS7*4QoVF}JyJ*K@&nq1Bhz~LO7#KwBQ zdS(~iDqZ8_!vJ%A)5DsiDNYsvs`qqaS)>`HiC!fp8z&Hmd-vuW5~$!avKJ(%;oswe z{6Nwr#0zrVrM?s`Z@57hVKvy01MeyHt2R9-b&;#j0|m|1%h>kNnZrdit=Pg}=LOS= z_vKiS2cWL_)#m=~?BK4GAg*iQJhmlzsKn2DO3o_zxO`y$yL|u~bYmjarH_?dfua-Q z%~l5zM0p}+%c}S*L;;d7j0|BTHW3vS?dS>-%pY##V_{?G_3TTf4H*RTN>~>*^e zAODK#^Fnq{?-Ul~ImoNK2YfIRq}ASihz*I&pRxkCIHC`BxLV2(O|wEqW_Cr)MwSybF}i2x~ywS}18h@3XJJmG35B8cA$o?%{2+= xyNf diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 1d46486d49..34b1c977bc 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -1,7 +1,32 @@ - $ cat $(find . -name '*.odocl') > megaodocl +q $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 5.1M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + Indexing in 2934.671164ms + Export in 1175.176859ms + + real 0m5.095s + user 0m4.675s + sys 0m0.163s +$ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -name '*.odocl') 2> /dev/null +$ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null + + $ gzip -k db.js + + $ gzip -k megaodocl + + $ du -s *.js *.gz + 2708 db.js + 2044 db.js.gz + 1624 megaodocl.gz + + + $ for f in $(find . -name '*.odocl'); do + > odoc html-generate --search-file=db.js --search-file=sherlodoc.js --output-dir html $f + > done Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t @@ -9,7 +34,6 @@ Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: {For_generated_code}1.t Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar Warning, resolved hidden path: Base__.Either0.t @@ -47,78 +71,45 @@ Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Set_intf.Named.t Warning, resolved hidden path: Base__.Either0.t - Indexing in 2168.125868ms - Export in 1096.270084ms - - real 0m4.273s - user 0m4.055s - sys 0m0.170s -$ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null - - $ gzip -k db.js - - $ gzip -k megaodocl - - $ du -s *.js *.gz - 2732 db.js - 2060 db.js.gz - 1628 megaodocl.gz - - - $ for f in $(find . -name '*.odocl'); do - > odoc html-generate --with-search --output-dir html $f 2> /dev/null - > done $ odoc support-files -o html - $ cat db.js ../../../jsoo/main.bc.js > html/index.js - $ cp sherlodoc_db.bin html - cp: cannot stat 'sherlodoc_db.bin': No such file or directory - [1] - $ du -sh html/index.js - 15M html/index.js + $ cp db.js html/ + $ cp ../../../jsoo/main.bc.js html/sherlodoc.js + $ du -sh html/sherlodoc.js + 13M html/sherlodoc.js $ ls html base + db.js fonts highlight.pack.js - index.js katex.min.css katex.min.js odoc.css odoc_search.js + sherlodoc.js $ cp -r html /tmp $ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 1701.007128ms - Export in 951.998949ms + Indexing in 1396.560907ms + Export in 961.407900ms $ sherlodoc --db=db_marshal.bin "group b" | sort - 'a Key.t -> - 'r list -> - ('a, 'b) t - ?size:int -> - combine:('b -> 'b -> 'b) -> - get_data:('r -> 'b) -> - get_key:('r -> 'a) -> - val Base.Hashtbl.group : ?growth_allowed:bool -> - val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t - val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t + val Base.Hashtbl.group : ?growth_allowed:bool -> ?size:int -> 'a t -> get_key:('r -> 'a) -> get_data:('r -> 'b) -> combine:('b -> 'b -> 'b) -> 'r list -> [('a, 'b) t] + val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> [('a, 'b list) t] + val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> [('a, 'b list) t] val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t val Base.List.groupi : 'a t -> break:(int -> 'a -> 'a -> bool) -> 'a t t val Base.List.sort_and_group : 'a t -> compare:('a -> 'a -> int) -> 'a t t val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.group_by : [('a, 'cmp) t] -> equiv:('a -> 'a -> bool) -> [('a, 'cmp) t] list $ sherlodoc --db=db_marshal.bin "group by" - val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.group_by : [('a, 'cmp) t] -> equiv:('a -> 'a -> bool) -> [('a, 'cmp) t] list val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list - val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.Set.Creators_and_accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list + val Base.Set.Using_comparator.group_by : [('a, 'cmp) t] -> equiv:('a -> 'a -> bool) -> [('a, 'cmp) t] list + val Base.Set.Accessors_generic.group_by : [('a, 'cmp) t] -> equiv:('a elt -> 'a elt -> bool) -> [('a, 'cmp) t] list + val Base.Set.Using_comparator.Tree.group_by : [('a, 'cmp) t] -> equiv:('a -> 'a -> bool) -> [('a, 'cmp) t] list + val Base.Set.Creators_and_accessors_generic.group_by : [('a, 'cmp) t] -> equiv:('a elt -> 'a elt -> bool) -> [('a, 'cmp) t] list $ sherlodoc --db=db_marshal.bin "map2" mod Base.Applicative.Make_using_map2 mod Base.Applicative.Make2_using_map2 @@ -131,11 +122,4 @@ $ firefox /tmp/html/base/index.html mod Base.Applicative.Make3_using_map2_local sig Base.Applicative.Basic_using_map2_local $ sherlodoc --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" - val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> - ?size:int -> - 'a Key.t -> - get_key:('r -> 'a) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t + val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> ?size:int -> 'a t -> get_key:('r -> 'a) -> get_data:('r -> 'b) -> combine:('b -> 'b -> 'b) -> 'r list -> [('a, 'b) t] diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 29c612dfc2..ba346ca1bb 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 2.393007ms - Export in 0.482798ms + Indexing in 8.804083ms + Export in 3.623009ms $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" val Main.unique_name : foo diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index b1e9d70f2d..0e26e6e527 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.592947ms - Export in 0.042915ms + Indexing in 2.681971ms + Export in 2.697945ms $ export SHERLODOC_DB=db.bin TODO : get a result for the query bellow $ sherlodoc ":'a" diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 5a2a365232..c642f6d5a8 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,8 +5,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.222206ms - Export in 0.052929ms + Indexing in 1.044035ms + Export in 0.388861ms $ export SHERLODOC_DB=db.bin $ sherlodoc --print-cost "list" 36 mod Main.List diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index a1ba015aa2..5a482cc94c 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -1,52 +1,29 @@ $ ocamlc -c main.ml -bin-annot -I . - $ odoc compile -I . main.cmt - $ odoc compile -I . page.mld + $ odoc compile --child asset-db.js --child asset-sherlodoc.js --child module-main --search-asset=db.js --search-asset=sherlodoc.js -I . page.mld + $ odoc compile --parent page --search-asset=db.js --search-asset=sherlodoc.js -I . main.cmt $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.632929ms - Export in 0.807047ms - $ sherlodoc_index --format=marshal --db=sherlodoc_db.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.590014ms - Export in 0.725985ms -$ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null - - $ gzip -k db.js - - $ gzip -k megaodocl - - $ du -s *.js *.gz - 8 db.js - 8 db.js.gz - 8 megaodocl.gz - + Indexing in 1.182795ms + Export in 0.593901ms +Here cat is used to remove weird permissions on executable built by dune + $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ for f in $(find . -name '*.odocl'); do - > odoc html-generate --with-search --output-dir html $f 2> /dev/null + > odoc html-generate --asset db.js --asset sherlodoc.js --output-dir html $f 2> /dev/null > done $ odoc support-files -o html - $ cat db.js ../../../jsoo/main.bc.js > html/index.js - $ cp sherlodoc_db.bin html - $ du -sh html/index.js - 12M html/index.js $ ls html - Main fonts highlight.pack.js - index.js katex.min.css katex.min.js odoc.css odoc_search.js - page.html - sherlodoc_db.bin + page $ cp -r html /tmp -$ firefox /tmp/html/Main/index.html + $ firefox /tmp/html/Main/index.html diff --git a/www/ui.ml b/www/ui.ml index 8b12b0830b..3b8675d8b9 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -10,6 +10,23 @@ let render_link elt = | Some link -> [ a_href link ] | None -> [] +let string_of_kind = + let open Db.Elt.Kind in + function + | Doc -> "doc" + | TypeDecl -> "type" + | Module -> "mod" + | Exception _ -> "exn" + | Class_type -> "class" + | Method -> "meth" + | Class -> "class" + | TypeExtension -> "type" + | ExtensionConstructor _ -> "cons" + | ModuleType -> "sig" + | Constructor _ -> "cons" + | Field _ -> "field" + | Val _ -> "val" + let render_elt elt = let open Db.Elt in let link = render_link elt in @@ -19,7 +36,7 @@ let render_elt elt = | Some rhs -> [ html_txt rhs ] | None -> [] in - let kind = Db.Elt.Kind.to_string elt.kind ^ " " in + let kind = string_of_kind elt.kind ^ " " in [ txt kind; a ~a:link [ em [ txt elt.name ] ] ] @ rhs let render_pkg elt = From 1e1d1d0ec895dd61fbe0b9a9631405c7e0e9a1f6 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 25 Aug 2023 14:56:11 +0200 Subject: [PATCH 129/285] no titles for doc comments --- jsoo/main.ml | 15 ++++++++++---- test/cram/simple.t/page.mld | 2 ++ test/cram/simple.t/run.t | 41 ++++++++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/jsoo/main.ml b/jsoo/main.ml index 171066b1d9..95f8dbc7b8 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -109,12 +109,19 @@ let search message = Jv.(apply (get global "postMessage")) [| Jv.of_list (fun Db.Elt.{ name; rhs; doc_html; kind; url; _ } -> - let kind = string_of_kind kind in let prefix_name, name = - let rev_name = name |> String.split_on_char '.' |> List.rev in - ( rev_name |> List.tl |> List.rev |> String.concat "." - , List.hd rev_name ) + match kind with + | Db.Elt.Kind.Doc -> None, None + | _ -> + let rev_name = + name |> String.split_on_char '.' |> List.rev + in + ( rev_name |> List.tl |> List.rev |> String.concat "." + |> Option.some + , rev_name |> List.hd |> Option.some ) in + let kind = string_of_kind kind in + let html = Odoc_search.Generator.html_of_strings ~kind ~prefix_name ~name ~typedecl_params:None (*TODO pass value*) diff --git a/test/cram/simple.t/page.mld b/test/cram/simple.t/page.mld index 37fe4527d8..a2a2439df7 100644 --- a/test/cram/simple.t/page.mld +++ b/test/cram/simple.t/page.mld @@ -8,3 +8,5 @@ A paragraph - a list {e of} things - bliblib + +{!Main} \ No newline at end of file diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 5a482cc94c..cab1a2d11a 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -7,15 +7,32 @@ $ du -sh megaodocl 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.182795ms - Export in 0.593901ms + Indexing in 1.058102ms + Export in 0.505924ms Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js + $ odoc support-files -o html $ for f in $(find . -name '*.odocl'); do - > odoc html-generate --asset db.js --asset sherlodoc.js --output-dir html $f 2> /dev/null + > echo $f ; + > odoc html-generate --asset db.js --asset sherlodoc.js --output-dir html $f > done - $ odoc support-files -o html + ./page-page.odocl + ./main.odocl + $ ls + db.js + html + main.cmi + main.cmo + main.cmt + main.ml + main.odoc + main.odocl + megaodocl + page-page.odoc + page-page.odocl + page.mld + sherlodoc.js $ ls html fonts highlight.pack.js @@ -24,6 +41,20 @@ Here cat is used to remove weird permissions on executable built by dune odoc.css odoc_search.js page + $ ls html/page + Main + db.js + index.html + sherlodoc.js + $ find .html -type f | sort + find: '.html': No such file or directory $ cp -r html /tmp - $ firefox /tmp/html/Main/index.html + $ cp sherlodoc.js /tmp/html + $ cp db.js /tmp/html + $ firefox /tmp/html/page/index.html + $ grep -E -o "'[\./]*db\.js" html/page/index.html + 'db.js + $ grep -E -o "'[\./]*db\.js" html/page/Main/index.html + '../db.js + From 0377e152e422958b73d1bb066dc6b72a207941c8 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 28 Aug 2023 16:21:35 +0200 Subject: [PATCH 130/285] Fixes the name of the generated js object of an entry --- jsoo/main.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jsoo/main.ml b/jsoo/main.ml index 95f8dbc7b8..49d005b3e6 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -129,8 +129,7 @@ let search message = |> List.map (Format.asprintf "%a" (Tyxml.Html.pp_elt ())) |> String.concat "\n" in - - Jv.obj [| "html", Jv.of_string html; url, Jv.of_string url |]) + Jv.obj [| "html", Jv.of_string html; "url", Jv.of_string url |]) results |] in From d9cfda1d288c39463e6627774615da9e29db8a8a Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 28 Aug 2023 16:22:08 +0200 Subject: [PATCH 131/285] New odocls for the base test --- .../cram/base.t/base_internalhash_types.odocl | Bin 3329 -> 3271 bytes test/cram/base.t/caml.odocl | Bin 32790 -> 32791 bytes test/cram/base.t/md5_lib.odocl | Bin 2341 -> 2258 bytes test/cram/base.t/page-index.odocl | Bin 38650 -> 36967 bytes test/cram/base.t/run.t | 94 +++++++----------- test/cram/base.t/shadow_stdlib.odocl | Bin 81028 -> 81029 bytes test/cram/simple.t/run.t | 6 +- 7 files changed, 41 insertions(+), 59 deletions(-) diff --git a/test/cram/base.t/base_internalhash_types.odocl b/test/cram/base.t/base_internalhash_types.odocl index 35ce6a6d4531eacba5da2a3b8092d7f886fc4846..e102815121b1e59aa05c3ed01da02db8c6b34438 100644 GIT binary patch delta 1429 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 OT>pcTsvfF*s`?kOT7^*n diff --git a/test/cram/base.t/page-index.odocl b/test/cram/base.t/page-index.odocl index cec6dbe57cf9058a5935e49ad5a40b9a77494e34..ed6cc46627f3c78be806683c382d65c82f1ec9fb 100644 GIT binary patch literal 36967 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�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 U^P>NYGva>Y$^ZQ`#FM@M2Y1q4rvLx| literal 38650 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 diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 34b1c977bc..01bdeba9f5 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -1,13 +1,13 @@ -q $ cat $(find . -name '*.odocl') > megaodocl + $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl - 5.1M megaodocl + 4.9M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - Indexing in 2934.671164ms - Export in 1175.176859ms + Indexing in 501.541853ms + Export in 528.162003ms - real 0m5.095s - user 0m4.675s - sys 0m0.163s + real 0m1.372s + user 0m1.320s + sys 0m0.047s $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -19,65 +19,45 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2708 db.js - 2044 db.js.gz - 1624 megaodocl.gz + 2672 db.js + 2016 db.js.gz + 1552 megaodocl.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --search-file=db.js --search-file=sherlodoc.js --output-dir html $f > done - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar - Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Either0.t + odoc: unknown option '--search-file'. + unknown option '--search-file'. + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + odoc: unknown option '--search-file'. + unknown option '--search-file'. + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + odoc: unknown option '--search-file'. + unknown option '--search-file'. + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + odoc: unknown option '--search-file'. + unknown option '--search-file'. + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + odoc: unknown option '--search-file'. + unknown option '--search-file'. + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + odoc: unknown option '--search-file'. + unknown option '--search-file'. + Usage: odoc html-generate [OPTION]… FILE.odocl + Try 'odoc html-generate --help' or 'odoc --help' for more information. + [2] $ odoc support-files -o html $ cp db.js html/ $ cp ../../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js 13M html/sherlodoc.js $ ls html - base db.js fonts highlight.pack.js @@ -89,8 +69,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cp -r html /tmp $ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 1396.560907ms - Export in 961.407900ms + Indexing in 498.206854ms + Export in 444.612980ms $ sherlodoc --db=db_marshal.bin "group b" | sort val Base.Hashtbl.group : ?growth_allowed:bool -> ?size:int -> 'a t -> get_key:('r -> 'a) -> get_data:('r -> 'b) -> combine:('b -> 'b -> 'b) -> 'r list -> [('a, 'b) t] val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> [('a, 'b list) t] diff --git a/test/cram/base.t/shadow_stdlib.odocl b/test/cram/base.t/shadow_stdlib.odocl index fa74a5d40a602ab91a9216cfb697400abc651157..869648b23bca481f8646c99dade957b08b439770 100644 GIT binary patch delta 42 zcmV+_0M-A5`2>ae1dxyv=l}p6`TzioLI418!Jv|$2mk;yfuyyh0n9nKZ#n@L0$^+p AKmY&$ delta 42 zcmV+_0M-A6`2>Xd1dxyv=Kug5`TzioK>z@7z@U<#2mk;ufuyyh0n9nKaXJAM0$=bC AIsgCw diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index cab1a2d11a..4aeeeaaf04 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -7,11 +7,13 @@ $ du -sh megaodocl 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.058102ms - Export in 0.505924ms + Indexing in 1.797915ms + Export in 0.930071ms Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js + $ du -sh sherlodoc.js + 1.2M sherlodoc.js $ odoc support-files -o html $ for f in $(find . -name '*.odocl'); do > echo $f ; From 4fea97b3fdf010466dbefcd0eb393b814a58e1a9 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 31 Aug 2023 17:22:54 +0200 Subject: [PATCH 132/285] Compatibility with odoc cleanup --- index/load_doc.ml | 6 +++--- jsoo/main.ml | 4 ++-- test/cram/simple.t/main.ml | 36 ++++++++++++++++++++---------------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/index/load_doc.ml b/index/load_doc.ml index fcd82c94a8..4b3f95dd3a 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -280,7 +280,7 @@ let register_entry ~db ~index_name ~type_search ~index_docstring let doc_html = match doc_txt with | "" -> "" - | _ -> doc |> Render.html_of_doc |> string_of_html + | _ -> doc |> Html.of_doc |> string_of_html in let kind' = convert_kind kind in let name = @@ -289,8 +289,8 @@ let register_entry ~db ~index_name ~type_search ~index_docstring | _ -> full_name in let score = cost ~name ~kind:kind' ~doc_html in - let rhs = Generator.rhs_of_kind kind in - let url = Render.url id in + let rhs = Html.rhs_of_kind kind in + let url = Html.url id in let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in if index_docstring then register_doc ~db elt doc_txt ; (if index_name diff --git a/jsoo/main.ml b/jsoo/main.ml index 49d005b3e6..cb268cb9dd 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -78,7 +78,7 @@ let db = let string_of_kind = let open Db.Elt.Kind in - let open Odoc_search.Generator in + let open Odoc_search.Html in function | Db.Elt.Kind.Doc -> kind_doc | TypeDecl -> kind_typedecl @@ -123,7 +123,7 @@ let search message = let kind = string_of_kind kind in let html = - Odoc_search.Generator.html_of_strings ~kind ~prefix_name ~name + Odoc_search.Html.of_strings ~kind ~prefix_name ~name ~typedecl_params:None (*TODO pass value*) ~rhs ~doc:doc_html |> List.map (Format.asprintf "%a" (Tyxml.Html.pp_elt ())) diff --git a/test/cram/simple.t/main.ml b/test/cram/simple.t/main.ml index 7c6fbd1fb5..f5eb8813f0 100644 --- a/test/cram/simple.t/main.ml +++ b/test/cram/simple.t/main.ml @@ -9,19 +9,19 @@ type t = int module type Signature = sig end -class istack = object - val mutable v = [0; 2] - - method pop = - match v with - | hd :: tl -> - v <- tl; - Some hd - | [] -> None - - method push hd = - v <- hd :: v -end +class istack = + object + val mutable v = [ 0; 2 ] + + method pop = + match v with + | hd :: tl -> + v <- tl ; + Some hd + | [] -> None + + method push hd = v <- hd :: v + end class type my_class_type = object end @@ -53,6 +53,12 @@ let lorem3 _ = 'e' (** lorem 4 *) +module Trucmuche = struct + let bidule = 4 +end + +include Trucmuche + let lorem4 = 1 type my_type = int * char @@ -74,7 +80,6 @@ type 'a list = | Cons of 'a * 'a list | Nil - (** Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo @@ -84,5 +89,4 @@ type 'a list = let long = 3 type ext_t = .. - -type ext_t += Ext_const of int \ No newline at end of file +type ext_t += Ext_const of int From 8b720de0f48509dcfd6bb332b306adbbc8441f4a Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 31 Aug 2023 17:30:25 +0200 Subject: [PATCH 133/285] typedecl params are now printed in search results --- cli/main.ml | 2 +- db/elt.ml | 5 ++--- index/load_doc.ml | 11 ++++++----- index/pretty.ml | 5 +++-- jsoo/main.ml | 10 +++++++--- query/dynamic_cost.ml | 2 +- www/ui.ml | 2 +- 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index f042e39c88..174835905a 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -4,7 +4,7 @@ let string_of_kind = let open Db.Elt.Kind in function | Doc -> "doc" - | TypeDecl -> "type" + | TypeDecl _ -> "type" | Module -> "mod" | Exception _ -> "exn" | Class_type -> "class" diff --git a/db/elt.ml b/db/elt.ml index c948898b03..e5684e2d5d 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -20,7 +20,7 @@ type type_path = string list list module Kind = struct type 'a abstract = | Doc - | TypeDecl + | TypeDecl of string option | Module | Exception of 'a | Class_type @@ -37,7 +37,7 @@ module Kind = struct let equal = ( = ) let doc = Doc - let type_decl = TypeDecl + let type_decl args = TypeDecl args let module_ = Module let exception_ type_path = Exception type_path let class_type = Class_type @@ -49,7 +49,6 @@ module Kind = struct let constructor type_path = Constructor type_path let field type_path = Field type_path let val_ type_path = Val type_path - end module Package = struct diff --git a/index/load_doc.ml b/index/load_doc.ml index 4b3f95dd3a..3ae40abdfa 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -20,7 +20,7 @@ let kind_cost (kind : Elt.Kind.t) = | Constructor type_path | Field type_path | Val type_path -> type_cost type_path | Doc -> 400 - | TypeDecl | Module -> 0 + | TypeDecl _ | Module -> 0 | Exception _ | Class_type | Method | Class -> 10 | TypeExtension -> 1000 | ExtensionConstructor _ | ModuleType -> 10 @@ -205,10 +205,11 @@ let searchable_type_of_record parent_type type_ = let open Odoc_model.Lang in TypeExpr.Arrow (None, parent_type, type_) -let convert_kind (kind : Odoc_search.Entry.kind) = +let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = let open Odoc_search.Entry in match kind with - | TypeDecl _ -> Elt.Kind.TypeDecl + | TypeDecl _ -> + Elt.Kind.TypeDecl (Odoc_search.Html.typedecl_params_of_entry entry) | Module -> Elt.Kind.Module | Value { value = _; type_ } -> let paths = paths type_ in @@ -264,7 +265,7 @@ let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.kind) = register_type_expr ~db elt type_ let register_entry ~db ~index_name ~type_search ~index_docstring - Odoc_search.Entry.{ id; doc; kind } = + (Odoc_search.Entry.{ id; doc; kind } as entry) = let open Odoc_search in let open Odoc_search.Entry in let is_type_extension = @@ -282,7 +283,7 @@ let register_entry ~db ~index_name ~type_search ~index_docstring | "" -> "" | _ -> doc |> Html.of_doc |> string_of_html in - let kind' = convert_kind kind in + let kind' = convert_kind entry in let name = match kind with | Doc _ -> Pretty.prefixname id diff --git a/index/pretty.ml b/index/pretty.ml index 0642be14e9..428c2c6033 100644 --- a/index/pretty.ml +++ b/index/pretty.ml @@ -19,8 +19,9 @@ and show_ident_short h (r : Paths.Identifier.t_pv Paths.Identifier.id) = | _ -> Format.fprintf h "%S" (Paths.Identifier.name r) and show_module_t h p = - Format.fprintf h "%s" (Odoc_document.Url.render_path (p : Paths.Path.Module.t :> Paths.Path.t)) - (* + Format.fprintf h "%s" + (Odoc_document.Url.render_path (p : Paths.Path.Module.t :> Paths.Path.t)) +(* function | `Resolved t -> let open Paths.Path in diff --git a/jsoo/main.ml b/jsoo/main.ml index cb268cb9dd..37a7ba8fe4 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -81,7 +81,7 @@ let string_of_kind = let open Odoc_search.Html in function | Db.Elt.Kind.Doc -> kind_doc - | TypeDecl -> kind_typedecl + | TypeDecl _ -> kind_typedecl | Module -> kind_module | Exception _ -> kind_exception | Class_type -> kind_class_type @@ -109,6 +109,11 @@ let search message = Jv.(apply (get global "postMessage")) [| Jv.of_list (fun Db.Elt.{ name; rhs; doc_html; kind; url; _ } -> + let typedecl_params = + match kind with + | Db.Elt.Kind.TypeDecl args -> args + | _ -> None + in let prefix_name, name = match kind with | Db.Elt.Kind.Doc -> None, None @@ -124,8 +129,7 @@ let search message = let html = Odoc_search.Html.of_strings ~kind ~prefix_name ~name - ~typedecl_params:None (*TODO pass value*) - ~rhs ~doc:doc_html + ~typedecl_params ~rhs ~doc:doc_html |> List.map (Format.asprintf "%a" (Tyxml.Html.pp_elt ())) |> String.concat "\n" in diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index cc46476708..8f6265ff9b 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -223,7 +223,7 @@ module Reasoning = struct let kind elt = match elt.Elt.kind with | Elt.Kind.Doc -> Doc - | Elt.Kind.TypeDecl -> TypeDecl + | Elt.Kind.TypeDecl _ -> TypeDecl | Elt.Kind.Module -> Module | Elt.Kind.Exception _ -> Exception | Elt.Kind.Class_type -> Class_type diff --git a/www/ui.ml b/www/ui.ml index 3b8675d8b9..a90c3a749a 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -14,7 +14,7 @@ let string_of_kind = let open Db.Elt.Kind in function | Doc -> "doc" - | TypeDecl -> "type" + | TypeDecl _ -> "type" | Module -> "mod" | Exception _ -> "exn" | Class_type -> "class" From 953cd1f67c67ae9a182145b0ef32ff507df19c6a Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 7 Sep 2023 14:13:59 +0200 Subject: [PATCH 134/285] compatibility with last odoc renaming --- index/load_doc.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index/load_doc.ml b/index/load_doc.ml index 3ae40abdfa..5a07d6ee58 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -277,7 +277,7 @@ let register_entry ~db ~index_name ~type_search ~index_docstring then () else let full_name = id |> Pretty.fullname |> String.concat "." in - let doc_txt = Render.text_of_doc doc in + let doc_txt = Text.of_doc doc in let doc_html = match doc_txt with | "" -> "" @@ -291,7 +291,7 @@ let register_entry ~db ~index_name ~type_search ~index_docstring in let score = cost ~name ~kind:kind' ~doc_html in let rhs = Html.rhs_of_kind kind in - let url = Html.url id in + let url = Html.url id in let url = Result.get_ok url in let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in if index_docstring then register_doc ~db elt doc_txt ; (if index_name From 6871b217a9d1604e4e6ecb40f6c4c13b02c0df8b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 7 Sep 2023 16:07:40 +0200 Subject: [PATCH 135/285] compatibility with odoc refactoring --- jsoo/dune | 2 +- jsoo/main.ml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jsoo/dune b/jsoo/dune index 37511c5483..72a5a27861 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -1,4 +1,4 @@ (executable (name main) (modes js) - (libraries tyxml query storage_js brr checkseum.ocaml odoc.search)) + (libraries tyxml query storage_js brr odoc.search_html_frontend)) diff --git a/jsoo/main.ml b/jsoo/main.ml index 37a7ba8fe4..3ee78fe8e2 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -78,7 +78,7 @@ let db = let string_of_kind = let open Db.Elt.Kind in - let open Odoc_search.Html in + let open Html_frontend in function | Db.Elt.Kind.Doc -> kind_doc | TypeDecl _ -> kind_typedecl @@ -128,7 +128,7 @@ let search message = let kind = string_of_kind kind in let html = - Odoc_search.Html.of_strings ~kind ~prefix_name ~name + Html_frontend.of_strings ~kind ~prefix_name ~name ~typedecl_params ~rhs ~doc:doc_html |> List.map (Format.asprintf "%a" (Tyxml.Html.pp_elt ())) |> String.concat "\n" From 8affd982f295dfa69f660d7f6959cfa94660764b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 16 Oct 2023 15:18:11 +0200 Subject: [PATCH 136/285] newlines in cli output --- test/cram/base.t/run.t | 100 ++++++++++++++++++++++++++++-------- test/cram/cli.t/run.t | 6 +-- test/cram/cli_poly.t/run.t | 4 +- test/cram/cli_small.t/run.t | 4 +- test/cram/simple.t/run.t | 6 +-- 5 files changed, 90 insertions(+), 30 deletions(-) diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 01bdeba9f5..24b780c1ba 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -2,12 +2,58 @@ $ du -sh megaodocl 4.9M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - Indexing in 501.541853ms - Export in 528.162003ms + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: {For_generated_code}1.t + Warning, resolved hidden path: {For_generated_code}1.t + Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar + Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Either0.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Set_intf.Named.t + Warning, resolved hidden path: Base__.Either0.t + Indexing in 1491.415977ms + Export in 645.585060ms - real 0m1.372s - user 0m1.320s - sys 0m0.047s + real 0m2.677s + user 0m2.586s + sys 0m0.083s $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -19,8 +65,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2672 db.js - 2016 db.js.gz + 2700 db.js + 2036 db.js.gz 1552 megaodocl.gz @@ -56,7 +102,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cp db.js html/ $ cp ../../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 13M html/sherlodoc.js + 5.0M html/sherlodoc.js $ ls html db.js fonts @@ -69,27 +115,34 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cp -r html /tmp $ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 498.206854ms - Export in 444.612980ms + Indexing in 939.327955ms + Export in 508.702993ms $ sherlodoc --db=db_marshal.bin "group b" | sort - val Base.Hashtbl.group : ?growth_allowed:bool -> ?size:int -> 'a t -> get_key:('r -> 'a) -> get_data:('r -> 'b) -> combine:('b -> 'b -> 'b) -> 'r list -> [('a, 'b) t] - val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> [('a, 'b list) t] - val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> [('a, 'b list) t] + 'a Key.t -> + 'r list -> + ('a, 'b) t + ?size:int -> + combine:('b -> 'b -> 'b) -> + get_data:('r -> 'b) -> + get_key:('r -> 'a) -> + val Base.Hashtbl.group : ?growth_allowed:bool -> + val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t + val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t val Base.List.groupi : 'a t -> break:(int -> 'a -> 'a -> bool) -> 'a t t val Base.List.sort_and_group : 'a t -> compare:('a -> 'a -> int) -> 'a t t val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.group_by : [('a, 'cmp) t] -> equiv:('a -> 'a -> bool) -> [('a, 'cmp) t] list + val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list $ sherlodoc --db=db_marshal.bin "group by" - val Base.Set.group_by : [('a, 'cmp) t] -> equiv:('a -> 'a -> bool) -> [('a, 'cmp) t] list + val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.Using_comparator.group_by : [('a, 'cmp) t] -> equiv:('a -> 'a -> bool) -> [('a, 'cmp) t] list - val Base.Set.Accessors_generic.group_by : [('a, 'cmp) t] -> equiv:('a elt -> 'a elt -> bool) -> [('a, 'cmp) t] list - val Base.Set.Using_comparator.Tree.group_by : [('a, 'cmp) t] -> equiv:('a -> 'a -> bool) -> [('a, 'cmp) t] list - val Base.Set.Creators_and_accessors_generic.group_by : [('a, 'cmp) t] -> equiv:('a elt -> 'a elt -> bool) -> [('a, 'cmp) t] list + val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list + val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.Creators_and_accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list $ sherlodoc --db=db_marshal.bin "map2" mod Base.Applicative.Make_using_map2 mod Base.Applicative.Make2_using_map2 @@ -102,4 +155,11 @@ $ firefox /tmp/html/base/index.html mod Base.Applicative.Make3_using_map2_local sig Base.Applicative.Basic_using_map2_local $ sherlodoc --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" - val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> ?size:int -> 'a t -> get_key:('r -> 'a) -> get_data:('r -> 'b) -> combine:('b -> 'b -> 'b) -> 'r list -> [('a, 'b) t] + val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> + ?size:int -> + 'a Key.t -> + get_key:('r -> 'a) -> + get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index ba346ca1bb..3f3a8a2660 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 8.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 8.804083ms - Export in 3.623009ms + Indexing in 2.303839ms + Export in 0.540018ms $ export SHERLODOC_DB=db.bin $ sherlodoc "unique_name" val Main.unique_name : foo @@ -31,7 +31,7 @@ val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - doc page + doc $ sherlodoc "map" mod Main.Map val Main.foo : foo diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index 0e26e6e527..3576fb4a20 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -7,8 +7,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 2.681971ms - Export in 2.697945ms + Indexing in 0.751019ms + Export in 0.050068ms $ export SHERLODOC_DB=db.bin TODO : get a result for the query bellow $ sherlodoc ":'a" diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index c642f6d5a8..d415a3dee5 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,8 +5,8 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 1.044035ms - Export in 0.388861ms + Indexing in 0.252008ms + Export in 0.079870ms $ export SHERLODOC_DB=db.bin $ sherlodoc --print-cost "list" 36 mod Main.List diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 4aeeeaaf04..e02300d93c 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -7,13 +7,13 @@ $ du -sh megaodocl 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.797915ms - Export in 0.930071ms + Indexing in 1.780987ms + Export in 0.813007ms Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 1.2M sherlodoc.js + 5.0M sherlodoc.js $ odoc support-files -o html $ for f in $(find . -name '*.odocl'); do > echo $f ; From 45ef0de87f07382f8de112e26f7c2d9a1ce814d8 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 17 Oct 2023 14:56:29 +0200 Subject: [PATCH 137/285] comments and format --- cli/main.ml | 3 ++ cli/unescape.mll | 7 +++- db/occ.mli | 7 ++++ db/suffix_tree.mli | 3 ++ index/load_doc.ml | 3 +- index/pretty.ml | 5 +++ jsoo/main.ml | 89 +++++++++++++++++++++++---------------------- query/array_succ.ml | 4 ++ query/succ.ml | 10 +++-- query/succ.mli | 8 ++-- query/test/test.ml | 2 + store/dune | 2 + 12 files changed, 89 insertions(+), 54 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index 174835905a..9ed27bce7e 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -1,3 +1,6 @@ +(** This executable allows to search in a sherlodoc database on the commandline. + It is mainly used for testing, but should work as is as a commandline tool. *) + let pp_or cond pp_true pp_false ppf = if cond then pp_true ppf else pp_false ppf let string_of_kind = diff --git a/cli/unescape.mll b/cli/unescape.mll index 5ca36fa2d4..9affdeee74 100644 --- a/cli/unescape.mll +++ b/cli/unescape.mll @@ -1,4 +1,7 @@ - +(* The goal of this lexer is to remove html encoding from strings, so that + they display nicely on the command-line. The only encodings included are the + one actually used. Because this executable is mainly used for testing, this + is fine. *) rule buffer b = parse | "&" { Buffer.add_char b '&'; buffer b lexbuf } | "<" { Buffer.add_char b '<'; buffer b lexbuf } @@ -18,4 +21,4 @@ let string str = let b = Buffer.create (String.length str) in buffer b lexbuf ; Buffer.contents b -} \ No newline at end of file +}C \ No newline at end of file diff --git a/db/occ.mli b/db/occ.mli index 924a8ba482..8b432cd7df 100644 --- a/db/occ.mli +++ b/db/occ.mli @@ -1,3 +1,10 @@ +(** [Occ] stands for occurences. It associate sets of elements to the number + of time members of the set occurs. + The list [[a, a, b, b, c]] would correspond to [[(2, [a; b]); (1, [c]) ]]. + It is used or type search : you want to be able to return every function + that takes two ints as an argument. Without this datastrucure, we would only + to search for functions that take ints, without specifying the amount. *) + type t type elt = int * Elt.t diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index 4cb5b5915f..491d5f9313 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -1,3 +1,6 @@ +(** The suffix tree datastructure. You need to provide a datastructure for the + sets of elements at the leafs of the tree. *) + module type SET = sig type t type elt diff --git a/index/load_doc.ml b/index/load_doc.ml index 5a07d6ee58..f9d2cd6341 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -291,7 +291,8 @@ let register_entry ~db ~index_name ~type_search ~index_docstring in let score = cost ~name ~kind:kind' ~doc_html in let rhs = Html.rhs_of_kind kind in - let url = Html.url id in let url = Result.get_ok url in + let url = Html.url id in + let url = Result.get_ok url in let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in if index_docstring then register_doc ~db elt doc_txt ; (if index_name diff --git a/index/pretty.ml b/index/pretty.ml index 428c2c6033..4e6f8b59d1 100644 --- a/index/pretty.ml +++ b/index/pretty.ml @@ -1,3 +1,8 @@ +(** This file contains useful printer, that are however of dubious + maintainability. Their result is used to be parsed afteward, it is not + printed but consumed as the basis for type-search. Because of this it is + sensitive code. *) + open Odoc_model module ModuleName = Odoc_model.Names.ModuleName module H = Tyxml.Html diff --git a/jsoo/main.ml b/jsoo/main.ml index 3ee78fe8e2..7516e9dc45 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -27,54 +27,55 @@ let stream_of_string str = let don't_wait_for fut = Fut.await fut Fun.id -let string_of_stream stream = - print_endline "string_of_stream" ; - let buffer = Buffer.create 128 in - let append str = - Buffer.add_string buffer (str |> Brr.Tarray.of_jv |> Brr.Tarray.to_string) - in - let open Jv in - let reader = call stream "getReader" [||] in +module Decompress_browser = struct + (** This module contains binding to the browser string compression api. It is + much faster than using an OCaml library, and does not require sending code + over the network. *) - let open Fut.Syntax in - let rec read_step obj = - let done_ = get obj "done" |> to_bool in - let str = get obj "value" in - if not done_ - then ( - append str ; - read ()) - else Fut.return () - and read () : unit Fut.t = - let read = call reader "read" [||] in - let promise = Fut.of_promise ~ok:Fun.id read in - Fut.bind promise (function - | Ok v -> - (* print_endline "Ok v" ; *) - read_step v - | Error e -> - print_endline "error in string_of_stream" ; - print_error e ; - Fut.return ()) - in - let+ () = read () in - let r = Buffer.contents buffer in - (* Printf.printf "Inflated to size %i\n%!" (String.length r) ; *) - r + let string_of_stream stream = + let buffer = Buffer.create 128 in + let append str = + Buffer.add_string buffer (str |> Brr.Tarray.of_jv |> Brr.Tarray.to_string) + in + let open Jv in + let reader = call stream "getReader" [||] in -let inflate str = - (* print_endline "inflating" ; *) - let dekompressor = - Jv.(new_ "DecompressionStream" [| of_string "deflate" |]) - in - let str = Jv.(call global "atob" [| str |]) |> Jv.to_jstr in - (* Printf.printf "String has size %i\n%!" (str |> Jstr.length) ; *) - let stream = stream_of_string str in - let decompressed_stream = Jv.call stream "pipeThrough" [| dekompressor |] in - string_of_stream decompressed_stream + let open Fut.Syntax in + let rec read_step obj = + let done_ = get obj "done" |> to_bool in + let str = get obj "value" in + if not done_ + then ( + append str ; + read ()) + else Fut.return () + and read () : unit Fut.t = + let read = call reader "read" [||] in + let promise = Fut.of_promise ~ok:Fun.id read in + Fut.bind promise (function + | Ok v -> read_step v + | Error e -> + print_endline "error in string_of_stream" ; + print_error e ; + Fut.return ()) + in + let+ () = read () in + let r = Buffer.contents buffer in + r + + let inflate str = + let dekompressor = + Jv.(new_ "DecompressionStream" [| of_string "deflate" |]) + in + let str = Jv.(call global "atob" [| str |]) |> Jv.to_jstr in + let stream = stream_of_string str in + let decompressed_stream = Jv.call stream "pipeThrough" [| dekompressor |] in + string_of_stream decompressed_stream +end let db = - Jv.(inflate @@ call global "sherlodoc_db" [||]) |> Fut.map Storage_js.load + Jv.(Decompress_browser.inflate @@ call global "sherlodoc_db" [||]) + |> Fut.map Storage_js.load let string_of_kind = let open Db.Elt.Kind in diff --git a/query/array_succ.ml b/query/array_succ.ml index fc2ca98d6f..8f2cab26b8 100644 --- a/query/array_succ.ml +++ b/query/array_succ.ml @@ -1,3 +1,7 @@ +(** This module allows searching for the successor of a value in a sorted array. + The array are assumed to be sorted : this is not checked. As this is tricky + code, it is unit-tested. *) + let get = Array.get let rec succ_ge ~compare elt arr lo hi = diff --git a/query/succ.ml b/query/succ.ml index 43e3b2af3b..4e9f32c2b9 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -97,10 +97,10 @@ let to_seq ~compare t = elt in (* Here, as stackoverflow could be thrown. In that case, we do not want to - crash, as a more complex search will probably not trigger the stackoverflow, - and we want the webworker or server to be running when such a request is - inputed. - The Printexc is very important as we nee dto be able to tell if the + crash, as a more complex search will have fewer results and probably not + trigger the stackoverflow, and we want the webworker or server to be + running when such a request is inputed. + The Printexc is very important as we need to be able to tell if the situation described above happens. With the current algorithm, such a stackoverflow is never triggered even on big libraries like Base, but it is not tail-rec, so a big enough search @@ -144,6 +144,8 @@ let union a b = let x, y = if a.cardinal < b.cardinal then x, y else y, x in { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } +(** This does a dychotomy to avoid building a comb, which would have poor + performance. *) let union_of_array arr = let rec loop lo hi = match hi - lo with diff --git a/query/succ.mli b/query/succ.mli index 8a8e01a056..4ef264fc9f 100644 --- a/query/succ.mli +++ b/query/succ.mli @@ -1,5 +1,5 @@ (** This module provides a way to get the first n elements of a very large set - without computing the other elements. *) + without computing the whole list of elements. *) type 'a t @@ -16,9 +16,11 @@ val empty : 'a builder val of_array : 'a array -> 'a builder (** Warning : only provide a sorted array, this is not checked ! - It also has to be sorted according to the [compare] function that you will - eventually pass to [to_seq] *) + It has to be sorted according to the [compare] function that you will + eventually pass to [to_seq]. *) val inter : 'a builder -> 'a builder -> 'a builder val union : 'a builder -> 'a builder -> 'a builder + val union_of_list : 'a builder list -> 'a builder +(** [union_of_list] has better performance than [List.fold_left union empty]. *) diff --git a/query/test/test.ml b/query/test/test.ml index 8fb20c5a3b..ba05cf12b9 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -84,6 +84,8 @@ module Test_succ = struct let finish (arr, succ) = arr, Succ.finish succ end + (** This is a problematic exemple that was found randomly. It is saved here + to check for regressions. *) let extra_succ = Both.( finish diff --git a/store/dune b/store/dune index c46f2196c5..2fe93ddc10 100644 --- a/store/dune +++ b/store/dune @@ -1,3 +1,5 @@ +; This directory contains modules for storing search databases. + (library (name storage_ancient) (modules storage_ancient) From ca3eac86a379162ed59cece7dbe0a215e54ba16b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 24 Oct 2023 14:36:20 +0200 Subject: [PATCH 138/285] odoc compatibility --- index/index.ml | 3 +-- index/pretty.ml | 2 ++ jsoo/main.ml | 4 ++-- www/ui.ml | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/index/index.ml b/index/index.ml index 4151d2c088..f3f2e86d38 100644 --- a/index/index.ml +++ b/index/index.ml @@ -12,8 +12,7 @@ let index_file register filename = Fold.unit ~f:(register (id :> Paths.Identifier.t)) () u in match Odoc_odoc.Indexing.handle_file ~page ~unit file with - | Ok (Some result) -> result - | Ok None -> () + | Ok result -> result | Error (`Msg msg) -> Format.printf "ODOC ERROR %s: %s@." filename msg) let storage_module = function diff --git a/index/pretty.ml b/index/pretty.ml index 4e6f8b59d1..6671fb7b2e 100644 --- a/index/pretty.ml +++ b/index/pretty.ml @@ -116,6 +116,8 @@ let rec full_name_aux : Paths.Identifier.t -> string list = | `SourceLocation (parent, name) -> DefName.to_string name :: full_name_aux (parent :> t) | `SourceLocationMod id -> full_name_aux (id :> t) + | `SourceLocationInternal (parent, name) -> + LocalName.to_string name :: full_name_aux (parent :> t) let fullname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string list = fun n -> List.rev @@ full_name_aux (n :> Paths.Identifier.t) diff --git a/jsoo/main.ml b/jsoo/main.ml index 7516e9dc45..4e6db8882b 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -79,7 +79,7 @@ let db = let string_of_kind = let open Db.Elt.Kind in - let open Html_frontend in + let open Odoc_html_frontend in function | Db.Elt.Kind.Doc -> kind_doc | TypeDecl _ -> kind_typedecl @@ -129,7 +129,7 @@ let search message = let kind = string_of_kind kind in let html = - Html_frontend.of_strings ~kind ~prefix_name ~name + Odoc_html_frontend.of_strings ~kind ~prefix_name ~name ~typedecl_params ~rhs ~doc:doc_html |> List.map (Format.asprintf "%a" (Tyxml.Html.pp_elt ())) |> String.concat "\n" diff --git a/www/ui.ml b/www/ui.ml index a90c3a749a..d6954e4185 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -108,7 +108,7 @@ let search_form query = ; a_value query ; a_placeholder "Search..." ; a_autofocus () - ; a_autocomplete false + ; a_autocomplete `Off ] () ; input ~a:[ a_input_type `Submit; a_value "Search!" ] () From cc414ae5674ae0f2827f3a22ad1b8704174bc78a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis=20Roch=C3=A9=20=28Ahrefs=29?= Date: Fri, 27 Oct 2023 15:06:10 +0000 Subject: [PATCH 139/285] fix compilation with tyxml.4.6.0 --- sherlodoc.opam | 2 +- www/ui.ml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sherlodoc.opam b/sherlodoc.opam index 1b9de2484b..e8c84902cc 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -14,7 +14,7 @@ depends: [ "fpath" "odoc" {= "2.1.0"} "opam-core" - "tyxml" + "tyxml" {>= "4.6.0"} ] build: [ ["dune" "subst"] {dev} diff --git a/www/ui.ml b/www/ui.ml index 4e6cbd4bdb..c864144f0c 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -71,7 +71,7 @@ let search_form query = ; a_value query ; a_placeholder "Search..." ; a_autofocus () - ; a_autocomplete false + ; a_autocomplete `Off ] () ; input ~a:[ a_input_type `Submit; a_value "Search!" ] () From 5c2c082931b3fb74830669ce2240cfb08b72ed12 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 24 Nov 2023 10:54:16 +0100 Subject: [PATCH 140/285] removes syntax error --- cli/unescape.mll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/unescape.mll b/cli/unescape.mll index 9affdeee74..bb2ca23929 100644 --- a/cli/unescape.mll +++ b/cli/unescape.mll @@ -21,4 +21,4 @@ let string str = let b = Buffer.create (String.length str) in buffer b lexbuf ; Buffer.contents b -}C \ No newline at end of file +} \ No newline at end of file From 9df6badac8c5115952caf6b0dc2441aeda33972e Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 24 Nov 2023 10:54:26 +0100 Subject: [PATCH 141/285] add limit --- cli/main.ml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index 9ed27bce7e..10973b37ce 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -31,23 +31,23 @@ let print_result ~print_cost in Format.printf "%s%s %s%a\n" score kind name pp_rhs rhs -let search ~print_cost ~dynamic_sort ~db query = +let search ~print_cost ~dynamic_sort ~limit ~db query = match - Query.(api ~shards:db ~dynamic_sort { query; packages = []; limit = 10 }) + Query.(api ~shards:db ~dynamic_sort { query; packages = []; limit }) with | _, [] -> print_endline "[No results]" | _, (_ :: _ as results) -> List.iter (print_result ~print_cost) results ; flush stdout -let rec search_loop ~print_cost ~dynamic_sort ~db = +let rec search_loop ~print_cost ~dynamic_sort ~limit ~db = match In_channel.input_line stdin with | Some query -> - search ~print_cost ~dynamic_sort ~db query ; - search_loop ~print_cost ~dynamic_sort ~db + search ~print_cost ~dynamic_sort ~limit ~db query ; + search_loop ~print_cost ~dynamic_sort ~limit ~db | None -> print_endline "[Search session ended]" -let main db query print_cost dynamic_sort = +let main db query print_cost dynamic_sort limit = match db with | None -> output_string stderr @@ -57,8 +57,8 @@ let main db query print_cost dynamic_sort = | Some db -> ( let db = Storage_marshal.load db in match query with - | None -> search_loop ~print_cost ~dynamic_sort ~db - | Some query -> search ~print_cost ~dynamic_sort ~db query) + | None -> search_loop ~print_cost ~dynamic_sort ~limit ~db + | Some query -> search ~print_cost ~dynamic_sort ~limit ~db query) open Cmdliner @@ -88,7 +88,7 @@ let dynamic_sort = in Arg.(value & flag & info [ "dynamic-sort" ] ~doc) -let main = Term.(const main $ db_filename $ query $ print_cost $ dynamic_sort) +let main = Term.(const main $ db_filename $ query $ print_cost $ dynamic_sort $ limit) let cmd = let doc = "CLI interface to query sherlodoc" in From af73e4ae5fcd3aa069e13b0d6c9e324a05f1aea9 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 24 Nov 2023 10:55:14 +0100 Subject: [PATCH 142/285] Just to compile still needs to fix --- index/pretty.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/index/pretty.ml b/index/pretty.ml index 6671fb7b2e..44ed4c5d3c 100644 --- a/index/pretty.ml +++ b/index/pretty.ml @@ -118,6 +118,7 @@ let rec full_name_aux : Paths.Identifier.t -> string list = | `SourceLocationMod id -> full_name_aux (id :> t) | `SourceLocationInternal (parent, name) -> LocalName.to_string name :: full_name_aux (parent :> t) + | `ExtensionDecl _ -> failwith "todo" let fullname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string list = fun n -> List.rev @@ full_name_aux (n :> Paths.Identifier.t) From 71429f5ec7f4887260ba089a819733648e06681f Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 24 Nov 2023 10:55:24 +0100 Subject: [PATCH 143/285] Better error message --- index/index.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index/index.ml b/index/index.ml index f3f2e86d38..6eff055d36 100644 --- a/index/index.ml +++ b/index/index.ml @@ -13,7 +13,7 @@ let index_file register filename = in match Odoc_odoc.Indexing.handle_file ~page ~unit file with | Ok result -> result - | Error (`Msg msg) -> Format.printf "ODOC ERROR %s: %s@." filename msg) + | Error (`Msg msg) -> Format.printf "Odoc warning or error %s: %s@." filename msg) let storage_module = function | `ancient -> (module Storage_ancient : Db.Storage.S) From ca33a60b6b6c5e7c066edb91c8cc4778eb37514b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 24 Nov 2023 10:56:02 +0100 Subject: [PATCH 144/285] install sherlodoc.js --- jsoo/dune | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/jsoo/dune b/jsoo/dune index 72a5a27861..7cd0b3e6b6 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -2,3 +2,13 @@ (name main) (modes js) (libraries tyxml query storage_js brr odoc.search_html_frontend)) + +(rule + (alias all) + (action + (copy main.bc.js sherlodoc.js))) + +(install + (files sherlodoc.js) + (section bin) + (package sherlodoc)) From a533e2379805063c9822f76ef5595a71535dee6a Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 24 Nov 2023 10:56:17 +0100 Subject: [PATCH 145/285] I am not sure about this one --- www/ui.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/ui.ml b/www/ui.ml index d6954e4185..02feb02384 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -108,8 +108,7 @@ let search_form query = ; a_value query ; a_placeholder "Search..." ; a_autofocus () - ; a_autocomplete `Off - ] + ; a_autocomplete false ] () ; input ~a:[ a_input_type `Submit; a_value "Search!" ] () ] From ac8556d334f110aedc495fdbb6b73050387de644 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 24 Nov 2023 10:05:25 +0100 Subject: [PATCH 146/285] wip fix opam dependencies --- cli/dune | 1 + cli/unescape.mll | 2 +- dune-project | 26 +++++++++++++++++++------- index/dune | 3 ++- index/index.ml | 4 +++- query/dune | 4 +--- sherlodoc-www.opam | 36 ++++++++++++++++++++++++++++++++++++ sherlodoc.opam | 4 ++-- www/dune | 2 ++ 9 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 sherlodoc-www.opam diff --git a/cli/dune b/cli/dune index 729873e534..a6c3a958e0 100644 --- a/cli/dune +++ b/cli/dune @@ -3,4 +3,5 @@ (executable (name main) (public_name sherlodoc) + (package sherlodoc) (libraries cmdliner query storage_marshal)) diff --git a/cli/unescape.mll b/cli/unescape.mll index bb2ca23929..7f90d97119 100644 --- a/cli/unescape.mll +++ b/cli/unescape.mll @@ -21,4 +21,4 @@ let string str = let b = Buffer.create (String.length str) in buffer b lexbuf ; Buffer.contents b -} \ No newline at end of file +} diff --git a/dune-project b/dune-project index 83ab1e943a..4ba8f4d1f1 100644 --- a/dune-project +++ b/dune-project @@ -6,18 +6,31 @@ (generate_opam_files true) -(source - (github art-w/sherlodoc)) - +(name sherlodoc) +(source (github art-w/sherlodoc)) (authors "Arthur Wendling") - (maintainers "art.wendling@gmail.com") - (license MIT) (package (name sherlodoc) (synopsis "Fuzzy search in OCaml documentation") + (depends + (ocaml + (>= 4.14.0)) + dune + ; ancient + dream + fpath + odoc + opam-core + tyxml + brr + (alcotest :with-test))) + +(package + (name sherlodoc-www) + (synopsis "Website for fuzzy search in OCaml documentation") (depends (ocaml (>= 4.14.0)) @@ -25,8 +38,7 @@ ancient dream fpath - (odoc - (= 2.1.0)) + odoc opam-core tyxml (alcotest :with-test))) diff --git a/index/dune b/index/dune index 2238eb028f..8079c7695a 100644 --- a/index/dune +++ b/index/dune @@ -1,6 +1,7 @@ (executable (public_name sherlodoc_index) (name index) + (package sherlodoc) (libraries db fpath @@ -12,6 +13,6 @@ odoc.xref2 odoc.odoc cmdliner - storage_ancient + ; storage_ancient storage_marshal storage_js)) diff --git a/index/index.ml b/index/index.ml index 6eff055d36..cae09cd4c8 100644 --- a/index/index.ml +++ b/index/index.ml @@ -16,7 +16,9 @@ let index_file register filename = | Error (`Msg msg) -> Format.printf "Odoc warning or error %s: %s@." filename msg) let storage_module = function - | `ancient -> (module Storage_ancient : Db.Storage.S) + | `ancient -> + (* (module Storage_ancient : Db.Storage.S) *) + failwith "TODO" | `marshal -> (module Storage_marshal : Db.Storage.S) | `js -> (module Storage_js : Db.Storage.S) diff --git a/query/dune b/query/dune index 0b3ee71d72..863f1b1a6e 100644 --- a/query/dune +++ b/query/dune @@ -2,8 +2,6 @@ (name query) (libraries lwt re db)) -(menhir - (modules parser) - (flags --explain)) +(menhir (modules parser)) (ocamllex lexer) diff --git a/sherlodoc-www.opam b/sherlodoc-www.opam new file mode 100644 index 0000000000..2075e9e081 --- /dev/null +++ b/sherlodoc-www.opam @@ -0,0 +1,36 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "Website for fuzzy search in OCaml documentation" +maintainer: ["art.wendling@gmail.com"] +authors: ["Arthur Wendling"] +license: "MIT" +homepage: "https://github.com/art-w/sherlodoc" +bug-reports: "https://github.com/art-w/sherlodoc/issues" +depends: [ + "ocaml" {>= "4.14.0"} + "dune" {>= "2.9"} + "ancient" + "dream" + "fpath" + "odoc" + "opam-core" + "tyxml" + "alcotest" {with-test} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "--promote-install-files=false" + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] + ["dune" "install" "-p" name "--create-install-files" name] +] +dev-repo: "git+https://github.com/art-w/sherlodoc.git" diff --git a/sherlodoc.opam b/sherlodoc.opam index 3bfb703b4e..5237687f96 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -9,12 +9,12 @@ bug-reports: "https://github.com/art-w/sherlodoc/issues" depends: [ "ocaml" {>= "4.14.0"} "dune" {>= "2.9"} - "ancient" "dream" "fpath" - "odoc" {= "2.1.0"} + "odoc" "opam-core" "tyxml" + "brr" "alcotest" {with-test} ] build: [ diff --git a/www/dune b/www/dune index d2c4eff609..30d027709f 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,5 @@ (executable + (public_name sherlodoc-www) (name www) + (package sherlodoc-www) (libraries cmdliner dream tyxml db query storage_ancient storage_marshal)) From 23520a830fe302afdf69a4e00d6bebd32ce9b900 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 1 Dec 2023 16:31:41 +0100 Subject: [PATCH 147/285] update tyxml --- www/ui.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/ui.ml b/www/ui.ml index 02feb02384..cb0b7ec94f 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -108,7 +108,7 @@ let search_form query = ; a_value query ; a_placeholder "Search..." ; a_autofocus () - ; a_autocomplete false ] + ; a_autocomplete `Off ] () ; input ~a:[ a_input_type `Submit; a_value "Search!" ] () ] From ae7b10f0c3aea5c57a0784d4e4144c11b7ddf5ce Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 1 Dec 2023 16:33:54 +0100 Subject: [PATCH 148/285] remove print and whitespaces --- db/db.ml | 3 --- index/index.ml | 3 --- index/load_doc.ml | 4 ++-- jsoo/main.ml | 3 +-- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/db/db.ml b/db/db.ml index 3bc6572240..accd939c65 100644 --- a/db/db.ml +++ b/db/db.ml @@ -16,14 +16,11 @@ let make () = } let export db = - let t0 = Unix.gettimeofday () in let db = { db_names = Suffix_tree.With_elts.export db.writer_names ; db_types = Suffix_tree.With_occ.export db.writer_types } in - let t1 = Unix.gettimeofday () in - Format.printf "Export in %fms@." (1000.0 *. (t1 -. t0)) ; db let store db name elt ~count = diff --git a/index/index.ml b/index/index.ml index cae09cd4c8..0aecfa1838 100644 --- a/index/index.ml +++ b/index/index.ml @@ -31,10 +31,7 @@ let main files index_docstring index_name type_search db_filename db_format = (Odoc_search.Entry.entries_of_item id item) in let h = Storage.open_out db_filename in - let t0 = Unix.gettimeofday () in List.iter (index_file register) files ; - let t1 = Unix.gettimeofday () in - Format.printf "Indexing in %fms@." (1000.0 *. (t1 -. t0)) ; let t = Db.export db in Storage.save ~db:h t ; Storage.close_out h diff --git a/index/load_doc.ml b/index/load_doc.ml index f9d2cd6341..fbc55e9986 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -36,8 +36,8 @@ let cost ~name ~kind ~doc_html = generic_cost ~ignore_no_doc name has_doc + kind_cost kind (* - - todo : check usefulness + + todo : check usefulness let rec type_size = function | Odoc_model.Lang.TypeExpr.Var _ -> 1 | Any -> 1 diff --git a/jsoo/main.ml b/jsoo/main.ml index 4e6db8882b..064981df09 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -28,7 +28,7 @@ let stream_of_string str = let don't_wait_for fut = Fut.await fut Fun.id module Decompress_browser = struct - (** This module contains binding to the browser string compression api. It is + (** This module contains binding to the browser string compression api. It is much faster than using an OCaml library, and does not require sending code over the network. *) @@ -105,7 +105,6 @@ let search message = let _pretty_query, results = Query.(api ~shards:db { query; packages = []; limit = 50 }) in - Printf.printf "Got %i results\n%!" (List.length results) ; let _ = Jv.(apply (get global "postMessage")) [| Jv.of_list From 3150a5c8971f3651301df983eb5d16f89c383976 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 1 Dec 2023 16:34:11 +0100 Subject: [PATCH 149/285] fix tests --- .../cram/base.t/base_internalhash_types.odocl | Bin 3271 -> 3125 bytes test/cram/base.t/caml.odocl | Bin 32791 -> 28624 bytes test/cram/base.t/md5_lib.odocl | Bin 2258 -> 2256 bytes test/cram/base.t/page-index.odocl | Bin 36967 -> 36966 bytes test/cram/base.t/run.t | 210 ++++++++++-------- test/cram/base.t/shadow_stdlib.odocl | Bin 81029 -> 81027 bytes test/cram/cli.t/run.t | 11 +- test/cram/cli_poly.t/run.t | 2 - test/cram/cli_small.t/run.t | 2 - test/cram/simple.t/run.t | 50 +++-- 10 files changed, 157 insertions(+), 118 deletions(-) diff --git a/test/cram/base.t/base_internalhash_types.odocl b/test/cram/base.t/base_internalhash_types.odocl index e102815121b1e59aa05c3ed01da02db8c6b34438..1e7621ab4ad1ae95c242683eb59de0228dd99653 100644 GIT binary patch delta 29 lcmX>uxm9Aq5&`aJ1_q`;1_ll`1_t)>1(P;zZQy2f004JH2g3jW delta 176 zcmdlgaa?l352tUQ$0mRdT@G?DsTAdcK k>~jPgoa^M^0MvQ`!Yg!ixFGDX0B9eCU*-T*?BePG0AZ&+Pyhe` diff --git a/test/cram/base.t/caml.odocl b/test/cram/base.t/caml.odocl index 0ffde547cee1a0cb835ac1f140ebd874397ef983..eba8d21ece6aaa7025ac80a95d8469699141ca87 100644 GIT binary patch delta 31 ncmbQ3$w6zyBSGSkjX>9nP|pv<&xRID4u1#mjkQWQ~%5L{8v1R_-sh>Bt#E+`R{ z3MfV)JcBDPY>MC#_Z5weqA?*ZaYIE6sEAw8bMLw1{5$uYyL`+2?wj5(yk&F!o*QbT zg%uV3ixm~)rdCv(H7Q;kue+l-E$WGTdR*PkCB6I=;#{r}7ammW*1KKZ$6=z-7Uy%r z#2O~Tuosd;6{N$k&{mA|hZ5G38>C!604Vc=2oDq~&{0Yb1S*!=<6KK2lBmrh7Ih2x z7FFj4tGLx74JJ2)T&r>?Y07*nso_K?v(%CZHOo-dc3PaFq(^I?9V22} z=Qt6wreV}iU|y;xG1G8TlNIF(8mNnD<9va5x{@xKUzC;33InXu1(Bj_!yr<4wZb`J zz=~bnNA04Hpq71c!3-7569Lc^Me~7*Kob-#_+L9-@m;1Jt!Sy`ZC7-!CW7n9Mcx1V zjXg%$m4*&iw93%IiXKtVQag6a)h*W|S3|(9a=`!X^v|bkHp~Iy|>o4K%Tmy(l2yk@0tIzgwpqI#rC*q;>;PeY{i!7 z4@q4cZJ$|;NrYbl;!@U}jsBBeM8_9UL1q)-cUD2Fhgh3Fb}8Ew^n3vsUFIp$yUX$& z#J@9HT8EVL{xrJJJkrwlD6P+IK%BpizLyhqi7m?ej(p-J!lcl=LgQ&kNk9paSxiHg z3Hw$M;swyvokQ5aEU(;2!$C~oMik-*tM~I(KsqLWi1Et_kI({Q*LN=Qk)-=}5FRbG zK1-*?uHiWvkJFrT3R0$yLgx*9M%Du?^N<2zqB3{-0 zG)UtkUR9b<8ej8O-qa?i>Yq=(at+}{5)TjccEU>_$M=V;97%WWdug5YClpBMOZA({ zPbDl@hsMXL$snwGlY$wVUtH4cMt?R7NS()k81TX-*hoJ5Uf=&dm(%|ijVKG&uMFqk zCIQ9aRSMAh#8ZiF#wWT7m&*F!p0HzHR+fK7emSs2vvjef!_08$wd7a9p!X~@orZ@c zfViXw(C~z~03J`cMiR!Z-)KUa`=t?`adX$iD=(vIBU=$6GJIcrbiahi9z;R(GGo;G z#ILc&zI<8yw+vcmY!PQHv8ihsd)@y)6BJ;X*~JK-=z|Dsif#HqhN7-5`+NZlwyB{C z4$^;L$ugzH>lk6XmG}_hk5XZK2ZnA#Gc7xHU+6Q3rak8K2;m>%6E|Hk&Gz9RDHADb zrYIkHl-CU8%@4wI36GN3o<~J|;{r6iOc7MT4i9Qr0U}n<(z_M(W5nd+41lRG`I0LM z2N+yJs3TvlN_BJuEzJ~E^PmHp`qi~$(ee7my80JrXx02kkPet0LtpY$)sR0)9e^Jr z9x8g_`ThoNthQ>lt-l>u>Zy90`p&YRQ!F^c^xu#^t4#BV0(8DU1l;XlywS;ka-I1I z&Ic>Nz?a?Bp%&F`pk|WzNQtQ{X_&&8sk;cJ`^k6GaFy}r6Uy92FQl#@#N5|l96!PJ zB9;S8EhXP=B}S=zG+^p$Yw5o)7u@=Px(~@Ov~=GRF0yog5H7ZGsrQM|`Wo#J!uv#x z6_3OV-8hl96`CR9q8d3W0_k|!gZ|Xu+g>MAijypO(&!TDbwcCRQnm+A8*MwdNocG& z`7!0sYes}mzC;5izrO#89mH=~x@4M{>TPj=J~5BjKKPRhDAzB3xiq%u@;86-RPvun zIM6o|ZUaOg<3r?W8a_vO&0m|O0bc=BvhJ;#FV)wTOcO7vdR^71lNp z;xj-q)ci)=C>ijfaRK20mY@&MCzQ{C$@tejhvOz}vTw)y96oB{VSKgn-7O3-m``gr e|E9a}SU#=!?!n|wFrI(aU3iKH?C3mwRN+6pc^d`* diff --git a/test/cram/base.t/md5_lib.odocl b/test/cram/base.t/md5_lib.odocl index ca0df220b7f164c02c3be1cefab74e399c8f3a07..f7a80f9e1f8df32e0adcbfa4031f0132a147c2d7 100644 GIT binary patch delta 26 gcmca4ctLPN3%@-B1LJN62G)B(+`M4Y#woTO0BuhQ3IG5A delta 29 jcmca0cu8 megaodocl $ du -sh megaodocl - 4.9M megaodocl + 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: {For_generated_code}1.t - Warning, resolved hidden path: {For_generated_code}1.t - Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar - Warning, resolved hidden path: Base__.Hash_set_intf.M_sexp_grammar - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Either0.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Set_intf.Named.t - Warning, resolved hidden path: Base__.Either0.t - Indexing in 1491.415977ms - Export in 645.585060ms - - real 0m2.677s - user 0m2.586s - sys 0m0.083s + + real 0m3.077s + user 0m2.886s + sys 0m0.122s + $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null @@ -67,43 +27,19 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ du -s *.js *.gz 2700 db.js 2036 db.js.gz - 1552 megaodocl.gz + 1544 megaodocl.gz $ for f in $(find . -name '*.odocl'); do - > odoc html-generate --search-file=db.js --search-file=sherlodoc.js --output-dir html $f + > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f > done - odoc: unknown option '--search-file'. - unknown option '--search-file'. - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - odoc: unknown option '--search-file'. - unknown option '--search-file'. - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - odoc: unknown option '--search-file'. - unknown option '--search-file'. - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - odoc: unknown option '--search-file'. - unknown option '--search-file'. - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - odoc: unknown option '--search-file'. - unknown option '--search-file'. - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - odoc: unknown option '--search-file'. - unknown option '--search-file'. - Usage: odoc html-generate [OPTION]… FILE.odocl - Try 'odoc html-generate --help' or 'odoc --help' for more information. - [2] $ odoc support-files -o html $ cp db.js html/ $ cp ../../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 5.0M html/sherlodoc.js + 5.1M html/sherlodoc.js $ ls html + base db.js fonts highlight.pack.js @@ -112,29 +48,69 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr odoc.css odoc_search.js sherlodoc.js - $ cp -r html /tmp +indent to see results +$ cp -r html /tmp $ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - Indexing in 939.327955ms - Export in 508.702993ms - $ sherlodoc --db=db_marshal.bin "group b" | sort + $ sherlodoc --db=db_marshal.bin "group b" + val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t + val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t + val Base.List.groupi : 'a t -> break:(int -> 'a -> 'a -> bool) -> 'a t t + val Base.List.sort_and_group : 'a t -> compare:('a -> 'a -> int) -> 'a t t + val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t + val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t + val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list + val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list + val Base.Hashtbl.group : ?growth_allowed:bool -> + ?size:int -> 'a Key.t -> + get_key:('r -> 'a) -> + get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> 'r list -> ('a, 'b) t + val Base.Hashtbl.Creators.group : ?growth_allowed:bool -> ?size:int -> + 'a Key.t -> + get_key:('r -> 'a) -> + get_data:('r -> 'b) -> combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t + val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list + val Base.Hashtbl.S_poly.group : ?growth_allowed:bool -> + ?size:int -> + get_key:('r -> 'a key) -> get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t + val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + val Base.Hashtbl.Poly.group : ?growth_allowed:bool -> + ?size:int -> + get_key:('r -> 'a key) -> + get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t + val Base.Hashtbl.Creators.group : ?growth_allowed:bool -> + ?size:int -> + get_key:('r -> 'a Key.t) -> + get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t_ + val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> + ?size:int -> + 'a Key.t -> get_key:('r -> 'a) -> - val Base.Hashtbl.group : ?growth_allowed:bool -> - val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t - val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t - val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t - val Base.List.groupi : 'a t -> break:(int -> 'a -> 'a -> bool) -> 'a t t - val Base.List.sort_and_group : 'a t -> compare:('a -> 'a -> int) -> 'a t t - val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t - val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + get_data:('r -> 'b) -> + combine:('b -> 'b -> 'b) -> + 'r list -> + ('a, 'b) t + val Base.Set.Creators_and_accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list $ sherlodoc --db=db_marshal.bin "group by" val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list @@ -154,6 +130,50 @@ $ firefox /tmp/html/base/index.html mod Base.Applicative.Make2_using_map2_local mod Base.Applicative.Make3_using_map2_local sig Base.Applicative.Basic_using_map2_local + sig Base.Applicative.Basic2_using_map2_local + sig Base.Applicative.Basic3_using_map2_local + mod Base.Applicative.Make_using_map2.Applicative_infix + mod Base.Applicative.Make2_using_map2.Applicative_infix + mod Base.Applicative.Make3_using_map2.Applicative_infix + val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + mod Base.Applicative.Make_using_map2_local.Applicative_infix + mod Base.Applicative.Make2_using_map2_local.Applicative_infix + mod Base.Applicative.Make3_using_map2_local.Applicative_infix + type Base.Applicative.Basic_using_map2.t + val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + type Base.Applicative.Basic2_using_map2.t + type Base.Applicative.Basic3_using_map2.t + type Base.Applicative.Make_using_map2.X.t + val Base.Applicative.Basic_using_map2.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] + type Base.Applicative.Make2_using_map2.X.t + type Base.Applicative.Make3_using_map2.X.t + val Base.Applicative.Basic2_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] + val Base.Applicative.Basic3_using_map2.map : [ `Define_using_map2 + | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] + val Base.Applicative.Make_using_map2.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] + val Base.Applicative.Make2_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] + val Base.Applicative.Make3_using_map2.X.map : [ `Define_using_map2 + | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] + type Base.Applicative.Basic_using_map2_local.t + val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + type Base.Applicative.Basic2_using_map2_local.t + type Base.Applicative.Basic3_using_map2_local.t + type Base.Applicative.Make_using_map2_local.X.t + val Base.Applicative.Basic_using_map2_local.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] + type Base.Applicative.Make2_using_map2_local.X.t + type Base.Applicative.Make3_using_map2_local.X.t + val Base.Applicative.Basic2_using_map2_local.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] + val Base.Applicative.Basic3_using_map2_local.map : [ `Define_using_map2 + | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] + val Base.Applicative.Make_using_map2_local.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] + val Base.Applicative.Make_using_map2.return : 'a -> 'a X.t + val Base.Applicative.Make2_using_map2_local.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] + val Base.Applicative.Make3_using_map2_local.X.map : [ `Define_using_map2 + | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] + val Base.Applicative.Make_using_map2.X.return : 'a -> 'a t + val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + val Base.Applicative.Make2_using_map2.return : 'a -> ('a, _) X.t $ sherlodoc --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> ?size:int -> diff --git a/test/cram/base.t/shadow_stdlib.odocl b/test/cram/base.t/shadow_stdlib.odocl index 869648b23bca481f8646c99dade957b08b439770..ee36e459420e1ca1aa260b24ba7b7b49b52103b8 100644 GIT binary patch delta 37 tcmZqu$=_se_AQvyxM1r7#tW9)3#}MMm;fOt4pIOB delta 38 wcmV+>0NMY8`2>ae1dxyr=l}p6`TzioLI418!Jv|$fuFUX0nj extensible_type val Main.consume : moo -> unit + type Main.extensible_type = .. + val Main.nesting_priority : foo + val Main.consume_2 : moo -> moo -> unit + val Main.Nest.nesting_priority : foo + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + val Main.consume_2_other : moo -> t -> unit + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + doc $ sherlodoc "qwertyuiopasdfghjklzxcvbnm" [No results] TODO : get a result for the query bellow diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index 3576fb4a20..4a48da8e4c 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -7,8 +7,6 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.751019ms - Export in 0.050068ms $ export SHERLODOC_DB=db.bin TODO : get a result for the query bellow $ sherlodoc ":'a" diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index d415a3dee5..0412a3c99c 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,8 +5,6 @@ $ du -sh megaodocl 4.0K megaodocl $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') - Indexing in 0.252008ms - Export in 0.079870ms $ export SHERLODOC_DB=db.bin $ sherlodoc --print-cost "list" 36 mod Main.List diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index e02300d93c..d5f7b7fd64 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -1,23 +1,26 @@ $ ocamlc -c main.ml -bin-annot -I . - $ odoc compile --child asset-db.js --child asset-sherlodoc.js --child module-main --search-asset=db.js --search-asset=sherlodoc.js -I . page.mld - $ odoc compile --parent page --search-asset=db.js --search-asset=sherlodoc.js -I . main.cmt + $ odoc compile --child module-main -I . page.mld + $ odoc compile --parent page -I . main.cmt $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 12K megaodocl $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - Indexing in 1.780987ms - Export in 0.813007ms Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 5.0M sherlodoc.js + 5.1M sherlodoc.js + $ mkdir html + $ cp sherlodoc.js html + $ cp db.js html $ odoc support-files -o html $ for f in $(find . -name '*.odocl'); do > echo $f ; - > odoc html-generate --asset db.js --asset sherlodoc.js --output-dir html $f + > cd html ; + > odoc html-generate --search-uri db.js --search-uri sherlodoc.js --output-dir . ../$f ; + > cd .. > done ./page-page.odocl ./main.odocl @@ -36,6 +39,7 @@ Here cat is used to remove weird permissions on executable built by dune page.mld sherlodoc.js $ ls html + db.js fonts highlight.pack.js katex.min.css @@ -43,20 +47,32 @@ Here cat is used to remove weird permissions on executable built by dune odoc.css odoc_search.js page + sherlodoc.js $ ls html/page Main - db.js index.html - sherlodoc.js - $ find .html -type f | sort - find: '.html': No such file or directory - $ cp -r html /tmp - $ cp sherlodoc.js /tmp/html - $ cp db.js /tmp/html - $ firefox /tmp/html/page/index.html - $ grep -E -o "'[\./]*db\.js" html/page/index.html - 'db.js - $ grep -E -o "'[\./]*db\.js" html/page/Main/index.html + $ find . -name "*.html" -type f | sort + ./html/page/Main/Modulule/index.html + ./html/page/Main/Trucmuche/index.html + ./html/page/Main/class-istack/index.html + ./html/page/Main/class-type-my_class_type/index.html + ./html/page/Main/index.html + ./html/page/Main/module-type-Signature/index.html + ./html/page/index.html + $ find . -name "*.js" -type f | sort + ./db.js + ./html/db.js + ./html/highlight.pack.js + ./html/katex.min.js + ./html/odoc_search.js + ./html/sherlodoc.js + ./sherlodoc.js + +Indent to see results +$ cp -r html /tmp +$ firefox /tmp/html/page/index.html + $ grep -E -o "'[\./a-zA-Z0-9_]*\.js" html/page/index.html '../db.js + '../sherlodoc.js From 5d50cda3a564f7170302835babf47bf54cfb6f70 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 4 Dec 2023 12:04:56 +0100 Subject: [PATCH 150/285] add dependencies to opam file --- dune-project | 19 +- installable_packages | 3668 ++++++++++++++++++++++++++++++++++++++++++ sherlodoc-www.opam | 6 +- sherlodoc.opam | 7 +- 4 files changed, 3686 insertions(+), 14 deletions(-) create mode 100644 installable_packages diff --git a/dune-project b/dune-project index 4ba8f4d1f1..499e55ecd5 100644 --- a/dune-project +++ b/dune-project @@ -7,9 +7,14 @@ (generate_opam_files true) (name sherlodoc) -(source (github art-w/sherlodoc)) + +(source + (github art-w/sherlodoc)) + (authors "Arthur Wendling") + (maintainers "art.wendling@gmail.com") + (license MIT) (package @@ -19,12 +24,13 @@ (ocaml (>= 4.14.0)) dune - ; ancient - dream + decompress + bigstringaf + base64 fpath odoc opam-core - tyxml + (tyxml (>= 4.6.0)) brr (alcotest :with-test))) @@ -35,10 +41,7 @@ (ocaml (>= 4.14.0)) dune + sherlodoc ancient dream - fpath - odoc - opam-core - tyxml (alcotest :with-test))) diff --git a/installable_packages b/installable_packages new file mode 100644 index 0000000000..2433070cdf --- /dev/null +++ b/installable_packages @@ -0,0 +1,3668 @@ +# Packages matching: installable +# Name # Installed # Synopsis +0install -- Decentralised installation system +0install-gtk -- Decentralised installation system - GTK UI +0install-solver -- Package dependency solver +ANSITerminal -- Basic control of ANSI compliant terminals and the windows shell +aacplus -- Bindings for the aacplus library which provides functions for decoding AAC audio files +abella -- Interactive theorem prover based on lambda-tree syntax +absolute 0.3 AbSolute solver +abstract_algebra -- A small library describing abstract algebra concepts +accessor v0.16.0 A library that makes it nicer to work with nested functional data structures +accessor_async -- Accessors for Async types, for use with the Accessor library +accessor_base -- Accessors for Base types, for use with the Accessor library +accessor_core -- Accessors for Core types, for use with the Accessor library +acgtk -- Abstract Categorial Grammar development toolkit +aches 1.0.0 Caches (bounded-size stores) for in-memory values and for resources +aches-lwt 1.0.0 Caches (bounded-size stores) for Lwt promises +acp4 1.0.1 ACP4: AutoCorrelation of Pharmacophore Features +acpc -- Chemoinformatics tool for ligand-based virtual screening +advi -- Active DVI Dune package! +aez -- Alt-Ergo Zero is an OCaml library for an SMT solver. +afl -- American Fuzzy Lop fuzzer by Michal Zalewski, repackaged for convenient use in opam +afl-persistent -- Use afl-fuzz in persistent mode +ago -- ago(1) - compute the number of days between two calendar dates +agrid -- Adjustable grid (two dimensional array) library +ahrocksdb -- A binding to RocksDB +aifad -- AIFAD - Automated Induction of Functions over Algebraic Datatypes +aio -- Linux kernel AIO access library for ocaml +alba -- Alba compiler +albatross -- Albatross - orchestrate and manage MirageOS unikernels with Solo5 +alcotest 1.7.0 Alcotest is a lightweight and colourful test framework +alcotest-async -- Async-based helpers for Alcotest +alcotest-js -- Virtual package containing optional JavaScript dependencies for Alcotest +alcotest-lwt -- Lwt-based helpers for Alcotest +alcotest-mirage -- Mirage implementation for Alcotest +alg_structs -- Interfaces and module combinators for algebraic structures +alg_structs_qcheck -- Provides qCheck generators for laws of alg_structs +aliases -- In memory indexes +alonzo -- STLC type system +alsa 0.3.0 Bindings for the ALSA library which provides functions for using soundcards +alt-ergo 2.5.2 The Alt-Ergo SMT prover +alt-ergo-free -- Alt-Ergo, an SMT Solver for Software Verification +alt-ergo-lib 2.5.2 The Alt-Ergo SMT prover library +alt-ergo-parsers 2.5.2 The Alt-Ergo SMT prover parser library +alt-ergo-plugin-ab-why3 -- An experimental Why3 frontend for Alt-Ergo +altgr-ergo -- The GUI for the Alt-Ergo SMT prover +ambient-context -- Abstraction over thread-local / continuation-local storage mechanisms for communication with transitive dependencies +ambient-context-lwt -- Storage backend for ambient-context using Lwt's sequence-associated storage +amqp-client -- Amqp client base library +amqp-client-async -- Amqp client library, async version +amqp-client-lwt -- Amqp client library, lwt version +ancient 0.9.1 Use data structures larger than available memory +anders -- Modal Homotopy Type System +angstrom 0.15.0 Parser combinators built for speed and memory-efficiency +angstrom-async -- Async support for Angstrom +angstrom-lwt-unix -- Lwt_unix support for Angstrom +angstrom-unix -- Unix support for Angstrom +ansi -- ANSI escape sequence parser +ansi-parse -- Ansiparse is a library for converting raw terminal output, replete with escape codes, into formatted HTML +ansicolor -- Simple ANSI terminal color library (deprecated in favor of ANSITerminal). +antic -- Stub of the C library Antic. Algebraic number +anycache -- Scan-resistant LRU/2Q cache +anycache-lwt -- Scan-resistant LRU/2Q cache +ao -- Bindings for the AO library which provides high-level functions for using soundcards +apron v0.9.14 APRON numerical abstract domain library +apronext 1.0.4 Apron extension +arb -- Stub of the C library Arb. Ball approximation +archetype -- Archetype language compiler +archi -- A library for managing the lifecycle of stateful components in OCaml +archi-async -- Async runtime for Archi, a library for managing the lifecycle of stateful components in OCaml +archi-lwt -- Lwt runtime for Archi, a library for managing the lifecycle of stateful components in OCaml +archimedes -- Extensible 2D plotting library. +archsat -- A first-order theorem prover with formal proof output +arg-complete -- Bash completion support for Stdlib.Arg +argon2 -- OCaml bindings to Argon2 +arp -- Address Resolution Protocol purely in OCaml +arp-mirage -- Address Resolution Protocol for MirageOS +arrakis 1.0.0 A RISC-V simulator +art 0.2.0 Adaptive Radix Tree +ascii85 -- ascii85 - Adobe's Ascii85 encoding as a module and a command line tool +asetmap 0.8.1 Alternative, compatible, OCaml standard library Sets and Maps +ask -- Create/Answer questionnaires +ask-integrator -- Link questionnaires to an uuid of 'a type +asl -- Bindings for the Apple System Log API +asli -- Interpreter for Arm's Architecture Specification Language (ASL) +asn1-combinators 0.2.6 Embed typed ASN.1 grammars in OCaml +assertions -- Basic assert statements +assimp -- OCaml bindings to Assimp, Open Asset Import Library +ast_generic -- Abstract Syntax Tree (AST) supporting 31 programming languages +astring 0.8.5 Alternative String module for OCaml +async v0.16.0 Monadic concurrency library +async-uri -- Open Async (TLS) TCP connections with Uri.t +async_durable -- Durable connections for use with async +async_extra -- Monadic concurrency library +async_find -- Directory traversal with Async +async_graphics -- Async wrapper for the OCaml Graphics library +async_inotify -- Async wrapper for inotify +async_interactive -- Utilities for building simple command-line based user interfaces +async_js -- A small library that provide Async support for JavaScript platforms +async_kernel v0.16.0 Monadic concurrency library +async_rpc_kernel v0.16.0 Platform-independent core of Async RPC library +async_rpc_websocket -- Library to serve and dispatch Async RPCs over websockets +async_sendfile -- Thin wrapper around [Linux_ext.sendfile] to send full files +async_shell -- Shell helpers for Async +async_smtp -- SMTP client and server +async_ssl -- An Async-pipe-based interface with OpenSSL +async_udp -- Monadic concurrency library +async_unix v0.16.0 Monadic concurrency library +async_websocket v0.16.0 A library that implements the websocket protocol on top of Async +atable -- Basic spreadsheet tool with HTML tables +atd -- Parser for the ATD data format description language +atd2cconv -- Convert ATD definitions to OCaml code that uses the CConv 0.1 library +atdd -- DLang code generation for ATD APIs +atdgen -- Generates efficient JSON serializers, deserializers and validators +atdgen-codec-runtime -- Runtime for atdgen generated bucklescript converters +atdgen-runtime -- Runtime library for code generated by atdgen +atdj -- Java code generation for ATD +atdpy -- Python/mypy code generation for ATD APIs +atds -- ATD Code generator for Scala +atdts -- TypeScript code generation for ATD APIs +atomic -- Compatibility package for OCaml's Atomic module starting from 4.12 +autofonce -- A modern runner for GNU Autoconf Testsuites +autofonce_config -- A modern runner for GNU Autoconf Testsuites +autofonce_core -- A modern runner for GNU Autoconf Testsuites +autofonce_lib -- A modern runner for GNU Autoconf Testsuites +autofonce_m4 -- A modern runner for GNU Autoconf Testsuites +autofonce_misc -- A modern runner for GNU Autoconf Testsuites +autofonce_patch -- A modern runner for GNU Autoconf Testsuites +autofonce_share -- A modern runner for GNU Autoconf Testsuites +avro -- Runtime library for encoding/decoding Avro +avro-compiler -- Schema compiler for Avro +awa -- SSH implementation in OCaml +awa-lwt -- SSH implementation in OCaml +awa-mirage -- SSH implementation in OCaml +aws -- Amazon Web Services SDK +aws-async -- Amazon Web Services SDK bindings for async +aws-autoscaling -- Amazon Web Services SDK bindings to Auto Scaling +aws-cloudformation -- Amazon Web Services SDK bindings to AWS CloudFormation +aws-cloudtrail -- Amazon Web Services SDK bindings to AWS CloudTrail +aws-cloudwatch -- Amazon Web Services SDK bindings to Amazon CloudWatch +aws-config -- Read AWS configuration in OCaml +aws-ec2 -- Amazon Web Services SDK bindings to Amazon Elastic Compute Cloud +aws-elasticache -- Amazon Web Services SDK bindings to Amazon ElastiCache +aws-elasticloadbalancing -- Amazon Web Services SDK bindings to Elastic Load Balancing +aws-lwt -- Amazon Web Services SDK bindings for lwt +aws-rds -- Amazon Web Services SDK bindings to Amazon Relational Database Service +aws-route53 -- Amazon Web Services SDK bindings to Amazon Route 53 +aws-s3 -- Ocaml library for accessing Amazon S3 +aws-s3-async -- Ocaml library for accessing Amazon S3 - Async version +aws-s3-lwt -- Ocaml library for accessing Amazon S3 - Lwt version +aws-sdb -- Amazon Web Services SDK bindings to Amazon SimpleDB +aws-sqs -- Amazon Web Services SDK bindings to Amazon Simple Queue Service +aws-ssm -- Amazon Web Services SDK bindings to Amazon Simple Systems Management Service +aws-sts -- Amazon Web Services SDK bindings to AWS Security Token Service +awsm -- AWS API base library +awsm-async -- AWS API base library Async +awsm-codegen -- AWS botocore code generator +awsm-lwt -- AWS API base library Lwt +azblob -- A trivial Azure Blob Storage interface for OCaml +azblob-async -- A trivial Azure Blob Storage interface for OCaml +azure-cosmos-db -- Azure cosmos db interface +BetterErrors -- Better compiler error output. +b0 0.0.5 Software construction and deployment kit +babel -- A library for defining Rpcs that can evolve over time without breaking backward compatibility. +backoff -- Exponential backoff mechanism for OCaml +bag -- Bags (aka multisets) +baguette_sharp -- The Baguette# Interpreter REPL +balancer -- A collection of load balancing algorithms implemented in pure Ocaml +bap -- Binary Analysis Platform +bap-abi -- BAP ABI integration subsystem +bap-analyze -- Implements the analyze command +bap-api -- A pass that adds parameters to subroutines based on known API +bap-arm -- BAP ARM lifter and disassembler +bap-beagle -- BAP obfuscated string solver +bap-beagle-strings -- Finds strings of characters using microexecution +bap-bil -- Controls the BIL transformation pipeline +bap-build -- BAP build automation tools +bap-bundle -- BAP bundler +bap-byteweight -- BAP facility for indentifying code entry points +bap-byteweight-frontend -- BAP Toolkit for training and controlling Byteweight algorithm +bap-c -- A C language support library for BAP +bap-cache -- BAP caching service +bap-callgraph-collator -- Collates programs based on their callgraphs +bap-callsites -- Inject data definition terms at callsites +bap-constant-tracker -- Constant Tracking Analysis based on Primus +bap-core -- Binary Analysis Platform +bap-core-theory -- BAP Semantics Representation +bap-cxxfilt -- A demangler that relies on a c++filt utility +bap-demangle -- Provides names service and demangling facilities +bap-dependencies -- Analyzes program dependencies +bap-disassemble -- Implements the disassemble command +bap-dump-symbols -- BAP plugin that dumps symbols information from a binary +bap-dwarf -- BAP DWARF parsing library +bap-elementary -- BAP floating point approximations of elementary functions +bap-elf -- BAP ELF parser and loader written in native OCaml +bap-emacs-dot -- Will automatically detect graph specifications in a dot syntax and display them using overlaying +bap-emacs-goodies -- A collection of useful Emacs tools for BAP +bap-emacs-mode -- Emacs major mode for reading and analyzing programs in BAP's IR +bap-extra -- Binary Analysis Platform +bap-flatten -- A BAP plugin, that translates a program into the flatten form +bap-frontc -- A C language frontend for based on FrontC library +bap-frontend -- BAP frontend +bap-future -- A library for asynchronous values +bap-ghidra -- BAP Ghidra backend +bap-glibc-runtime -- Detects the presence of glibc runtime +bap-ida-plugin -- Plugins for IDA and BAP integration +bap-knowledge -- Knowledge Representation Library +bap-llvm -- BAP LLVM backend +bap-main -- Build BAP Main Framework Configuration Library +bap-mc -- BAP machine instruction playground +bap-microx -- A micro execution framework +bap-mips -- BAP MIPS lifter +bap-objdump -- Extract symbols from binary, using binutils objdump +bap-optimization -- A BAP plugin that removes dead IR code +bap-patterns -- Applies semantic actions to the matching byte patterns +bap-phoenix -- BAP plugin that dumps information in a phoenix decompiler format +bap-piqi -- BAP plugin for serialization based on piqi library +bap-plugins -- BAP plugins support library +bap-powerpc -- BAP PowerPC lifter +bap-primus -- The BAP Microexecution Framework +bap-primus-dictionary -- BAP Primus Lisp library that provides dictionaries +bap-primus-exploring-scheduler -- Evaluates all machines, prioritizing the least visited +bap-primus-greedy-scheduler -- Evaluates all machines in the DFS order +bap-primus-limit -- Ensures termination by limiting Primus machines +bap-primus-lisp -- BAP Primus Lisp Runtime +bap-primus-loader -- Generic program loader for Primus +bap-primus-mark-visited -- Registers the bap:mark-visited component +bap-primus-powerpc -- Performs the PowerPC target specific setup +bap-primus-print -- Prints Primus states and observations +bap-primus-promiscuous -- Enables the promiscuous mode of execution +bap-primus-propagate-taint -- A compatibility layer between different taint analysis frameworks +bap-primus-random -- Provides components for Primus state randomization +bap-primus-region -- Provides a set of operations to store and manipulate interval trees +bap-primus-round-robin-scheduler -- Evaluates all machines in the BFS order +bap-primus-support -- Provides supporting components for Primus +bap-primus-symbolic-executor -- Primus Symbolic Executor +bap-primus-systems -- Loads Primus systems and registers them in the system repository +bap-primus-taint -- A taint analysis control interface +bap-primus-test -- BAP Primus Testing and Program Verification module +bap-primus-track-visited -- Tracks basic blocks visited by Primus +bap-primus-wandering-scheduler -- Evaluates all machines while +bap-primus-x86 -- The x86 CPU support package for BAP Primus CPU emulator +bap-print -- Print plugin - print project in various formats +bap-radare2 -- Extract symbols from binary using radare2 +bap-raw -- Provides a loader for raw binaries +bap-recipe -- Stores command line parameters and resources in a single file +bap-recipe-command -- Provides commands to manipulate the recipe subsystem +bap-relation -- A set of relations (bimap) +bap-relocatable -- Extracts symbolic information from the program relocations +bap-report -- A BAP plugin that reports program status +bap-riscv -- BAP RISCV lifter and disassembler +bap-run -- A BAP plugin that executes a binary +bap-signatures -- A data package with binary signatures for BAP +bap-specification -- Implements the specification command +bap-ssa -- A BAP plugin, that translates a program into the SSA form +bap-std -- The Binary Analysis Platform Standard Library +bap-strings -- Text utilities useful in Binary Analysis and Reverse Engineering +bap-stub-resolver -- Identifies and manages stub functions in a binary +bap-symbol-reader -- BAP plugin that reads symbol information from files +bap-systemz -- A target support package for the Systemz (Z9) ISA +bap-taint -- BAP Taint Analysis Framework +bap-taint-propagator -- BAP Taint propagation engine using based on microexecution +bap-term-mapper -- A BAP DSL for mapping program terms +bap-thumb -- A target support package for the Thumb instruction set +bap-toplevel -- BAP toplevel, baptop +bap-trace -- A plugin to load and run program execution traces +bap-traces -- BAP Library for loading and parsing execution traces +bap-trivial-condition-form -- Eliminates complex conditionals in branches +bap-warn-unused -- Emit a warning if an unused result may cause a bug or security issue +bap-x86 -- BAP x86 lifter +bare -- BAP Rule Engine Library +bare_encoding -- BARE encoding, see https://baremessages.org/ +bark -- Unofficial OCaml port of elm/parser (v1.1.0) +base v0.16.3 Full standard library replacement for OCaml +base-bigarray base +base-bytes base Bytes library distributed with the OCaml compiler +base-native-int63 -- Virtual package for enabling native int63 support in Base +base-threads base +base-unix base +base32 -- Base32 encoding for OCaml +base58 -- Base58 encoding and decoding +base64 3.5.1 Base64 encoding for OCaml +base_bigstring v0.16.0 String type based on [Bigarray], for use in I/O and C-bindings +base_quickcheck v0.16.0 Randomized testing framework, designed for compatibility with Base +base_trie -- Trie data structure library +bastet -- An OCaml library for category theory and abstract algebra +bastet_async -- Async implementations for bastet +bastet_lwt -- Lwt implementations for bastet +batch_jaro_winkler -- Fast batch jaro winkler distance implementation in C99 +batsat -- OCaml bindings for batsat, a SAT solver in rust +batteries 3.7.1 A community-maintained standard library extension +bdd -- Quick implementation of a Binary Decision Diagrams (BDD) library for OCaml +bddrand -- A simple front-end to the lutin Random toss machinary +bear -- Bare essential additions to the stdlib +bech32 -- Bech32 addresses for OCaml (see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) +bechamel -- Yet Another Benchmark in OCaml +bechamel-js -- HTML generator for bechamel's output +bechamel-notty -- CLI generator for bechamel's output +bechamel-perf -- Linux perf's metrics for bechamel +beluga -- Implementation of contextual modal logic for reasoning with higher-order abstract syntax +benchmark -- Benchmark running times of code +benchpress -- Tool to run one or more logic programs, on a set of files, and collect the results +benchpress-server -- Server and web UI for benchpress +bencode -- Bencode (`.torrent` file format) reader/writer in OCaml +bentov -- 1D histogram sketching +bestline -- OCaml bindings for the bestline C library +bheap 2.0.0 Priority queues +bibtex2html -- BibTeX to HTML translator +bidirectional_map -- A library for bidirectional maps and multimaps. +bigarray-compat 1.1.0 Compatibility library to use Stdlib.Bigarray when possible +bigarray-overlap 0.2.1 Bigarray.overlap +bigdecimal -- Arbitrary-precision decimal based on Zarith +bignum -- Core-flavoured wrapper around zarith's arbitrary-precision rationals +bigstring 0.3 A set of utils for dealing with `bigarrays` of `char` +bigstring-unix -- I/O functions for bigstrings using file descriptors and memory-maps +bigstringaf 0.9.1 Bigstring intrinsics and fast blits based on memcpy/memmove +bimage -- A simple, efficient image-processing library +bimage-display -- Window system for Bimage +bimage-gtk -- Bimage_gtk allows images to be displayed in GTK windows +bimage-io -- Input/output for Bimage using OpenImageIO +bimage-lwt -- A simple, efficient image-processing library (LWT bindings) +bimage-sdl -- Bimage_gtk allows images to be displayed using SDL +bimage-unix -- Bimage_unix provides methods for encoding/decoding images in many formats using ImageMagick/stb_image +bimap -- An OCaml library implementing bi-directional maps and multi-maps +bin_prot v0.16.0 A binary protocol generator +binaryen -- OCaml bindings for Binaryen +binaryen_dsl -- Writing Webassembly text format in DSL +binbin -- Convenient and human-readable bitmap manipulation +bindlib -- OCaml Bindlib library for bound variables +biniou -- Binary data format designed for speed, safety, ease of use and backward compatibility as protocols evolve +binning -- A datastructure to accumulate values in bins +binsec -- Semantic analysis of binary executables +bio_io -- A library for reading and writing common file formats used in bioinformatics like FASTA files +biocaml -- The OCaml Bioinformatics Library +biotk -- Bioinformatics toolkit +bip32 -- Hierarchical Deterministic Wallets +bisect -- Code coverage tool for the OCaml language (deprecated) +bisect_ppx -- Code coverage for OCaml +bisect_ppx-ocamlbuild -- Ocamlbuild plugin for Bisect_ppx, the coverage tool +bistro -- A library to build and run distributed scientific workflows +bistro-bio -- Bistro workflows for computational biology +bitcoin -- Bitcoin Client API logic-only +bitcoin-cohttp-async -- Bitcoin Client API cohttp-async interface +bitcoin-cohttp-lwt -- Bitcoin Client API cohttp-lwt interface +bitcoin-ocurl -- Bitcoin Client API ocurl interface +bitlib -- A library for writing binary files +bitmasks -- BitMasks over int and int64 exposed as sets +bitpack_serializer -- This library provides functions for encoding efficiently simple OCaml data +bitstring -- Bitstrings and bitstring matching for OCaml +bitv -- A bit vector library for OCaml +bitvec -- Fixed-size bitvectors and modular arithmetic, based on Zarith +bitvec-binprot -- Janestreet's Binprot serialization for Bitvec +bitvec-order -- Base style comparators and orders for Bitvec +bitvec-sexp -- Sexp serializers for Bitvec +bitwuzla -- SMT solver for AUFBVFP +bitwuzla-bin -- Bitwuzla SMT solver executable +bitwuzla-c -- SMT solver for AUFBVFP (C API) +bitwuzla-cxx -- SMT solver for AUFBVFP (C++ API) +bjack -- Bindings for the Jack library which provides functions for linking audio programs +blake2 -- Blake2 cryptography +blake3 -- Blake3 cryptography +bloomf -- Efficient Bloom filters for OCaml +bls12-381 18.0 Implementation of the BLS12-381 curve (wrapper for the Blst library) +bls12-381-gen -- Functors to generate BLS12-381 primitives based on stubs +bls12-381-hash -- Implementation of some cryptographic hash primitives using the scalar field of BLS12-381 +bls12-381-js -- JavaScript version of BLS12-381 primitives implementing the virtual package bls12-381 +bls12-381-js-gen -- Functors to generate BLS12-381 JavaScript primitives based on stubs +bls12-381-legacy -- UNIX version of BLS12-381 primitives. Not implementating the virtual package bls12-381 +bls12-381-signature -- Implementation of BLS signatures for the pairing-friendly curve BLS12-381 +bls12-381-unix -- UNIX version of BLS12-381 primitives implementing the virtual package bls12-381 with blst backend +blurhash -- A BlurHash encoder in OCaml +bn128 -- Barreto-Naehrig 128 Elliptic Curve pairing function library in OCAML +bnfgen -- Random text generator that takes context-free grammars from BNF files +bogue -- GUI library for ocaml, with animations, based on SDL2 +bogue-tutorials -- Bogue Tutorials +boltzgen -- Generate tests using boltzman sampling +bonsai -- A library for building dynamic webapps, using Js_of_ocaml +bookaml -- Library for retrieving information about published books +bos 0.2.1 Basic OS interaction for OCaml +boulangerie -- B# Package Manager +box -- Render boxes in the terminal +bpf -- Embedded eBPF assembler +bracetax -- Simple and deterministic text processing syntax +broken -- The Broken package is a simple testsuite framework. +brr 0.0.6 Browser programming toolkit for OCaml +brr-lwd -- Make reactive webpages in Js_of_ocaml using Brr and Lwd +bsdowl -- This collection of BSD Make directives aims at providing a highly +bst 7.0.1 Bisector tree implementation in OCaml +buffer-pool -- A pool of buffers which automatically increases in size as required +build_path_prefix_map -- An OCaml implementation of the BUILD_PATH_PREFIX_MAP specification +builder -- Scheduling and executing shell jobs +builder-web -- Web interface for builder +bun -- Simple management of afl-fuzz processes +bwd -- Backward lists +bwrap -- Use Bubblewrap to sandbox executables +bytearray -- Efficient marshaling to and from bigarrays +bytebuffer -- Extensible buffers built on top of bigarrays +ca-certs 0.2.3 Detect root CA certificates from the operating system +ca-certs-nss -- X.509 trust anchors extracted from Mozilla's NSS +cactus -- A B-Tree based index implementation +cairn -- A derivation explorer and logger for menhir parser +cairo2 -- Binding to Cairo, a 2D Vector Graphics Library +cairo2-gtk -- Rendering Cairo on Gtk2 canvas +cairo2-pango -- Interface between Cairo and Pango (for Gtk2) +caisar -- A platform for characterizing the safety and robustness of artificial intelligence based software +caisar-ir -- CAISAR's intermediate representation +caisar-nnet -- NNet parser for CAISAR +caisar-onnx -- ONNX parser for CAISAR +caisar-ovo -- OVO parser for CAISAR +caisar-xgboost -- XGBOOST parser for CAISAR +calcium -- Stub of the C library Antic. For exact computation with real and complex numbers, presently in early development +calculon -- Library for writing IRC bots in OCaml and a collection of plugins +calculon-redis -- A redis plugin for Calculon +calculon-redis-lib -- A library to interact with Calculon via Redis +calculon-web -- A collection of web plugins for Calculon +caldav -- A CalDAV server +calendar -- Library for handling dates and times in your program +calendars -- Convert dates between gregorian/julian/french/hebrew calendars +calipso -- Rewrites C programs to remove non-structured control-flow +callipyge -- Pure OCaml implementation of Curve25519 +camelot -- An OCaml Linter / Style Checker +camels -- A game about camels +camelsnakekebab -- A Ocaml library for word case conversion +caml-mode -- Caml mode for GNU Emacs +camlbz2 -- Bindings for bzip2 +camlgpc -- Interface to Alan Murta's General Polygon Clipper +camlidl 1.11 Stub code generator for OCaml +camlimages -- Image processing library +camlix -- Simple circuit breaker +camllib -- Utility Library (including various datatypes) +camlmix -- Camlmix is a generic preprocessor which converts text with embedded +camlon -- Caml Object Notion, parsing and printing OCaml like data expressions +camlp-streams 5.0.1 The Stream and Genlex libraries for use with Camlp4 and Camlp5 +camlp4 -- Camlp4 is a system for writing extensible parsers for programming languages +camlp5 -- Preprocessor-pretty-printer of OCaml +camlp5-buildscripts -- Camlp5 Build scripts (written in OCaml) +camlpdf -- Read, write and modify PDF files +camlprime -- Primality testing with lazy lists of prime numbers +camlrack -- S-Expression parsing for OCaml +camltc -- OCaml bindings for tokyo cabinet +camlzip 1.11 Accessing compressed files in ZIP, GZIP and JAR format +camomile -- A Unicode library +camyll -- A static site generator +canary -- Capture unhandled exceptions and automatically report them through various channels +capnp -- OCaml code generation plugin for the Cap'n Proto serialization framework +capnp-rpc -- Cap'n Proto is a capability-based RPC system with bindings for many languages +capnp-rpc-lwt -- Cap'n Proto is a capability-based RPC system with bindings for many languages +capnp-rpc-mirage -- Cap'n Proto is a capability-based RPC system with bindings for many languages +capnp-rpc-net -- Cap'n Proto is a capability-based RPC system with bindings for many languages +capnp-rpc-unix -- Cap'n Proto is a capability-based RPC system with bindings for many languages +captureio -- Capture output to Stderr and Stdout +caqti 1.9.0 Unified interface to relational database libraries +caqti-async -- Async support for Caqti +caqti-driver-mariadb -- MariaDB driver for Caqti using C bindings +caqti-driver-pgx -- PostgreSQL driver for Caqti based on the pure-OCaml PGX library +caqti-driver-postgresql -- PostgreSQL driver for Caqti based on C bindings +caqti-driver-sqlite3 -- Sqlite3 driver for Caqti using C bindings +caqti-dynload -- Dynamic linking of Caqti drivers using findlib.dynload +caqti-lwt 1.9.0 Lwt support for Caqti +caqti-mirage -- MirageOS support for Caqti +caqti-type-calendar -- Date and time field types using the calendar library +carray -- Contiguous arrays in OCaml +carton -- Implementation of PACKv2 file in OCaml +carton-git -- Implementation of PACK file in OCaml +carton-lwt -- Implementation of PACK file in OCaml +catala -- Compiler and library for the literate programming language for tax code specification +catapult -- Tracing system based on the Catapult/TEF format +catapult-client -- Network client for catapult, to be paired with catapult-daemon +catapult-daemon -- Daemon for reliable multi-process logging with catapult +catapult-file -- File logger for catapult +catapult-sqlite -- Sqlite-based backend for Catapult tracing +cb-check -- Json schema checker for current-bench +cbor -- CBOR encoder/decoder (RFC 7049) - native OCaml implementation +cborl -- CBOR library +cca -- A framework for differential source code analyses +ccbg -- Wallpaper utility for Wayland +cconv -- Combinators for Type Conversion in OCaml +cdrom -- Query the state and contents of CDROM devices under Linux +certify -- CLI utilities for simple X509 certificate manipulation +cf -- OCaml bindings to macOS CoreFoundation +cf-lwt -- Lwt interface to macOS CoreFoundation +cfg -- CFG - Context-Free Grammars +cfgen -- This package was renamed to bnfgen. +cfml -- The CFML program verification tool +cfstream -- Stream operations in the style of Core's API +cgi -- Library for writing CGIs +cgroups -- An OCaml interface for the Linux control groups +chacha -- The Chacha functions, in OCaml +chalk -- Composable and simple terminal highlighting package +chamelon -- Subset of littlefs filesystem fulfilling MirageOS KV +chamelon-unix -- Command-line Unix utilities for chamelon filesystems +chamo -- A kind of emacs-like editor, using OCaml instead of lisp +charInfo_width -- Determine column width for a character +charrua -- DHCP wire frame encoder and decoder +charrua-client -- DHCP client implementation +charrua-client-lwt -- A DHCP client using lwt as effectful layer +charrua-client-mirage -- A DHCP client for MirageOS +charrua-server -- DHCP server +charrua-unix -- Unix DHCP daemon +charset -- Fast char sets +chartjs -- OCaml bindings for Chart.js +chartjs-annotation -- OCaml bindigns for Chart.js annotation plugin +chartjs-colorschemes -- OCaml bindigns for Chart.js colorschemes plugin +chartjs-datalabels -- OCaml bindigns for Chart.js datalabels plugin +chartjs-streaming -- OCaml bindings for Chart.js streaming plugin +chase -- Model finder for geometric theories using the chase +checkseum 0.5.2 Adler-32, CRC32 and CRC32-C implementation in C and OCaml +choice -- Choice monad, for easy backtracking +chrome-trace 3.11.1 Chrome trace event generation library +cid -- Content-addressed Identifiers +cinaps -- Trivial metaprogramming tool +clangml -- OCaml bindings for Clang API +clangml-transforms -- Code transformers for clangml +clap -- Command-Line Argument Parsing, imperative style with a consumption mechanism +clarity-lang -- Clarity smart contract parser and AST +class_group_vdf 0.0.4 Verifiable Delay Functions bindings to Chia's VDF +clim -- Command Line Interface Maker +cloudi -- OCaml CloudI API +clp_operations -- A Clp domain +clz -- Compression support for cohttp-lwt client using decompress +cmark -- OCaml bindings for the CMark Common Markdown parsing and rendering library. +cmarker -- Bindings for a local installation of CMark +cmarkit -- CommonMark parser and renderer for OCaml +cmdliner 1.2.0 Declarative definition of command line interfaces for OCaml +cmdliner-stdlib -- A collection of cmdliner terms to control OCaml runtime parameters +cmdtui -- Interactive command completion and execution for building REPLs +cmdtui-lambda-term -- Interactive command completion and execution for building REPLs +cmitomli -- Converts compiled interface files (.cmi) into source interface files (.mli) +cmon -- A library for printing OCaml values with sharing +coccinelle -- Coccinelle is a C source code matching and transformation engine +codept -- Alternative ocaml dependency analyzer +cohttp 5.3.0 An OCaml library for HTTP clients and servers +cohttp-async -- CoHTTP implementation for the Async concurrency library +cohttp-curl -- Shared code between the individual cohttp-curl clients +cohttp-curl-async -- Cohttp client using Curl & Async as the backend +cohttp-curl-lwt -- Cohttp client using Curl & Lwt as the backend +cohttp-lwt 5.3.0 CoHTTP implementation using the Lwt concurrency library +cohttp-lwt-jsoo -- CoHTTP implementation for the Js_of_ocaml JavaScript compiler +cohttp-lwt-unix 5.3.0 CoHTTP implementation for Unix and Windows using Lwt +cohttp-mirage -- CoHTTP implementation for the MirageOS unikernel +cohttp-server-lwt-unix -- Lightweight Cohttp + Lwt based HTTP server +cohttp-top -- CoHTTP toplevel pretty printers for HTTP types +cohttp_async_websocket -- Websocket library for use with cohttp and async +cohttp_static_handler -- A library for easily creating a cohttp handler for static files +coin -- Mapper of KOI8-{U,R} to Unicode +colibri2 -- A CP solver for smtlib +colibrics -- A CP solver proved in Why3 +colibrilib -- A library of domains and propagators proved in Why3 +colombe -- SMTP protocol in OCaml +color -- +color-brewery -- Offer colors palettes and functions to brew colors +combinaml -- Simple, customizable, dependency free parser combinator library +combinat -- Fast combinatorics for OCaml +combine -- Combine is a library for combinatorics problem solving. +comby -- A tool for structural code search and replace that supports ~every language +comby-kernel -- A match engine for structural code search and replace that supports ~every language +comby-semantic -- A match engine for structural code search and replace that supports ~every language +command_rpc -- Utilities for Versioned RPC communication with a child process over stdin and stdout +commons -- Yet another set of common utilities +conan -- Identify type of your file (such as the MIME type) +conan-cli -- Identify type of your file (such as the MIME type) +conan-database -- A database of decision trees to recognize MIME type +conan-lwt -- Identify type of your file (such as the MIME type) +conan-unix -- Identify type of your file (such as the MIME type) +conduit 6.2.0 A network connection establishment library +conduit-async -- A network connection establishment library for Async +conduit-lwt 6.2.0 A portable network connection establishment library using Lwt +conduit-lwt-unix 6.2.0 A network connection establishment library for Lwt_unix +conduit-mirage -- A network connection establishment library for MirageOS +conex -- Establishing trust in community repositories +conex-mirage-crypto -- Establishing trust in community repositories: crypto provided via mirage-crypto +conex-nocrypto -- Establishing trust in community repositories: crypto provided via nocrypto +conf-aclocal -- Virtual package relying on aclocal +conf-adwaita-icon-theme -- Virtual package relying on adwaita-icon-theme +conf-alsa 1 Virtual package relying on alsa +conf-antic -- Virtual package relying on a Antic lib system installation +conf-ao -- Virtual package relying on libao +conf-arb -- Virtual package relying on a Arb lib system installation +conf-asciidoc -- Virtual package relying on asciidoc +conf-assimp -- Check if assimp (Open Asset Import Library) is installed +conf-autoconf 0.1 Virtual package relying on autoconf installation +conf-automake -- Virtual package relying on GNU automake +conf-bap-llvm -- Checks that supported version of LLVM is installed +conf-bash -- Virtual package to install the Bash shell +conf-binutils -- Checks that binutils are installed +conf-bison -- Virtual package relying on GNU bison +conf-blas -- Virtual package for BLAS configuration +conf-bluetooth -- Virtual package for Bluetooth library +conf-bmake -- Virtual package relying on a BSD Make compatible program +conf-boost -- Virtual package relying on boost +conf-brotli -- Virtual package relying on a brotli system installation +conf-c++ -- Virtual package relying on the c++ compiler +conf-cairo -- Virtual package relying on a Cairo system installation +conf-calcium -- Virtual package relying on a Calcium lib system installation +conf-capnproto -- Virtual package relying on captnproto installation +conf-clang -- Virtual package relying on clang +conf-clang-format -- Virtual package relying on clang-format +conf-cmake 1 Virtual package relying on cmake +conf-cosmopolitan -- Virtual package relying on APE/Cosmopolitan +conf-cpio -- Virtual package relying on cpio +conf-csdp -- Virtual package relying on a CSDP binary system installation +conf-dbm -- Virtual package relying on gdbm +conf-diffutils -- Virtual package relying on diffutils +conf-dpkg -- Virtual package relying on dpkg +conf-dssi -- Virtual package relying on dssi +conf-efl -- Virtual package relying on the EFL system installation +conf-emacs -- Virtual package to install the Emacs editor +conf-env-travis -- Detect Travis CI and lift its environment to opam +conf-expat -- Virtual package relying on an expat system installation +conf-faad -- Virtual package relying on libfaad +conf-fdkaac -- Virtual package relying on fdk-aac +conf-ffmpeg -- Virtual package relying on FFmpeg +conf-fftw3 -- Virtual package relying on a FFTW3 lib system installation +conf-findutils -- Virtual package relying on findutils +conf-flex -- Virtual package relying on GNU flex +conf-flint -- Virtual package relying on a Flint lib system installation +conf-freetype -- Virtual package relying on a freetype lib system installation +conf-frei0r -- Virtual package relying on frei0r +conf-fswatch -- Virtual package relying on libfswatch installation +conf-ftgl -- Virtual package relying on an ftgl system installation +conf-fts -- Virtual package relying on the fts.h header +conf-g++ 1.0 Virtual package relying on the g++ compiler (for C++) +conf-gcc -- Virtual package relying on the gcc compiler (for C) +conf-gd -- Virtual package relying on a libgd system installation +conf-gfortran -- Virtual package relying on a gfortran system installation +conf-ghostscript -- Virtual package relying on ghostscript +conf-git -- Virtual package relying on git +conf-glade -- Virtual package relying on a libglade system installation +conf-gles2 -- Virtual package relying on a OpenGL ES 2 system installation +conf-glew -- Virtual package relying on a GLEW system installation +conf-glfw3 -- Virtual package relying on a GLFW3 system installation +conf-glib-2 -- Virtual package relying on a system GLib 2 installation +conf-glpk -- Virtual package for GLPK (GNU Linear Programming Kit) +conf-gmp 4 Virtual package relying on a GMP lib system installation +conf-gmp-powm-sec 3 Virtual package relying on a GMP lib with constant-time modular exponentiation +conf-gnome-icon-theme3 -- Virtual package relying on gnome-icon-theme +conf-gnuplot -- Virtual package relying on gnuplot installation +conf-gnutls -- Virtual package relying on a gnutls system installation +conf-gobject-introspection -- Virtual package relying on a system gobject-introspection installation +conf-goocanvas2 -- Virtual package relying on a Goocanvas-2 system installation +conf-gpiod -- C libgpiod library for GPIO on recent (>4.8) Linux kernels +conf-graphviz -- Virtual package relying on graphviz installation +conf-gsl -- Virtual package relying on a GSL lib system installation +conf-gssapi -- Virtual package relying on a krb5-gssapi system installation +conf-gstreamer -- Virtual package relying on libgstreamer +conf-gtk2 -- Virtual package relying on gtk2 +conf-gtk3 -- Virtual package relying on GTK+ 3 +conf-gtksourceview -- Virtual package relying on a GtkSourceView system installation +conf-gtksourceview3 -- Virtual package relying on a GtkSourceView-3 system installation +conf-guile -- Virtual package relying on an GNU Guile system installation +conf-haveged -- Check if havaged is installed on the system +conf-hidapi 0 Virtual package relying on a hidapi system installation +conf-ida -- Checks that IDA Pro is installed +conf-jack -- Virtual package relying on jack +conf-jq -- Virtual package relying on jq +conf-ladspa -- Virtual package relying on ladspa +conf-lame -- Virtual package relying on lame +conf-lapack -- Virtual package for LAPACK configuration +conf-leveldb -- Virtual package relying on a LevelDB lib system installation +conf-libargon2 -- Virtual package relying on libargon2 +conf-libbz2 -- Virtual package relying on libbz2 +conf-libclang -- Virtual package relying on the installation of llvm and clang libraries (<= 15.0.x) +conf-libcurl -- Virtual package relying on a libcurl system installation +conf-libdw -- Virtual package relying on libdw +conf-libev 4-12 High-performance event loop/event model with lots of features +conf-libevent -- Virtual package relying on libevent +conf-libffi 2.0.0 Virtual package relying on libffi system installation +conf-libflac -- Virtual package relying on libFLAC +conf-libfontconfig -- Virtual package relying on fontconfig +conf-libfuse -- Virtual package relying on FUSE +conf-libgif -- Virtual package relying on a libgif system installation +conf-libgsasl -- Virtual package relying on a GSASL lib system installation +conf-libjpeg -- Virtual package relying on a libjpeg system installation +conf-liblinear-tools -- Virtual package relying on liblinear-{train|predict} installation +conf-liblo -- Virtual package relying on liblo +conf-liblz4 -- Virtual package relying on liblz4 system installation +conf-liblzma -- Virtual package relying on liblzma +conf-libMagickCore -- Virtual package relying on an ImageMagick system installation +conf-libmagic -- Virtual package relying on a libmagic system installation +conf-libmaxminddb -- Virtual package relying on a libmaxminddb system installation +conf-libmosquitto -- Virtual package relying on a libmosquitto system installation +conf-libmpg123 -- Virtual package relying on libmpg123 +conf-libnl3 -- Virtual package relying on a libnl system installation +conf-libogg -- Virtual package relying on libogg +conf-libopus -- Virtual package relying on libopus +conf-libpcre -- Virtual package relying on a libpcre system installation +conf-libpcre2-8 -- Virtual package relying on a libpcre2 system installation +conf-libpng -- Virtual package relying on a libpng system installation +conf-libportmidi -- Virtual package relying on libportmidi +conf-librsvg2 -- Virtual package relying on Librsvg2 system installation +conf-libsamplerate -- Virtual package relying on libsamplerate +conf-libseccomp -- Virtual package relying on a libseccomp system installation +conf-libsodium -- Virtual package relying on a libsodium system installation +conf-libspeex -- Virtual package relying on libspeex +conf-libssl 4 Virtual package relying on an OpenSSL library system installation +conf-libsvm -- Virtual package relying on libsvm library installation +conf-libsvm-tools -- Virtual package relying on libsvm-tools installation +conf-libtheora -- Virtual package relying on libtheora +conf-libtool -- Virtual package relying on libtool installation +conf-libudev -- Virtual package relying on a libudev system installation +conf-libuv -- Virtual package relying on a libuv system installation +conf-libvorbis -- Virtual package relying on libvorbis +conf-libwayland -- Virtual package relying on libwayland +conf-libX11 -- Virtual package relying on an Xlib system installation +conf-libxcb -- Virtual package relying on xcb +conf-libxcb-image -- Virtual package relying on xcb-image +conf-libxcb-keysyms -- Virtual package relying on xcb-shm +conf-libxcb-shm -- Virtual package relying on xcb-shm +conf-libxcb-xkb -- Virtual package relying on xcb-xkb +conf-libxcursor -- Virtual package relying on an libXcursor system installation +conf-libxi -- Virtual package relying on an libXi system installation +conf-libxinerama -- Virtual package relying on an libXinerama system installation +conf-libxrandr -- Virtual package relying on an libXRandR system installation +conf-lilv -- Virtual package relying on lilv +conf-linux-libc-dev -- Virtual package relying on the installation of the Linux kernel headers files +conf-lldb -- Virtual package to check the availability of LLDB 3.5 development packages +conf-llvm -- Virtual package relying on llvm library installation +conf-lua -- Virtual package relying on a Lua system installation +conf-lz4 -- Virtual package requiring the lz4 command to be available +conf-m4 -- Virtual package relying on m4 +conf-mad -- Virtual package relying on mad +conf-mariadb -- Virtual package relying on a libmariadbclient system installation +conf-mbedtls -- Virtual package relying on an mbedtls system installation +conf-mecab -- Virtual package relying on MeCab library installation +conf-mesa -- Virtual package relying on an mesa system installation +conf-mpfr 3 Virtual package relying on library MPFR installation +conf-mpi -- Virtual package relying on a mpi system installation +conf-mysql -- Virtual package relying on a libmysqlclient system installation +conf-nanomsg -- Virtual package relying on a nanomsg system installation +conf-nauty -- Virtual package relying on nauty +conf-ncurses -- Virtual package relying on ncurses +conf-neko -- Virtual package relying on a Neko system installation +conf-netsnmp -- Package relying on net-snmp libs +conf-nlopt -- Virtual package relying on nlopt +conf-nmap -- Virtual package relying on nmap installation +conf-npm -- Virtual package relying on npm installation +conf-numa -- Package relying on libnuma +conf-ode -- Virtual package relying on a ODE system installation +conf-oniguruma -- Virtual package relying on an Oniguruma system installation +conf-openbabel -- Virtual package relying on openbabel library installation +conf-openblas -- Virtual package to install OpenBLAS and LAPACKE +conf-opencc0 -- Virtual package relying on opencc v0 (libopencc.so.1) installation +conf-opencc1 -- Virtual package relying on opencc v1 (libopencc.so.2) installation +conf-opencc1_1 -- Virtual package relying on opencc v1.1 (libopencc.so.1.1) installation +conf-openimageio -- Virtual package relying on OpenImageIO development package installation +conf-openjdk -- Virtual package relying on OpenJDK / Javac +conf-openssl -- Virtual package relying on an OpenSSL binary system installation +conf-pam -- Virtual package relying on a system installation of PAM +conf-pandoc -- Virtual package relying on pandoc installation +conf-pango -- Virtual package relying on a Pango system installation +conf-perl 2 Virtual package relying on perl +conf-perl-ipc-system-simple -- Virtual package relying on perl's IPC::System::Simple +conf-perl-string-shellquote -- Virtual package relying on perl's String::ShellQuote +conf-pixz -- Virtual package relying on pixz +conf-pkg-config 3 Check if pkg-config is installed and create an opam switch local pkgconfig folder +conf-plplot -- Virtual package relying on plplot +conf-portaudio -- Virtual package relying on portaudio +conf-postgresql -- Virtual package relying on a PostgreSQL system installation +conf-ppl -- Virtual package relying on the Parma Polyhedra Library (PPL) system installation +conf-protoc -- Virtual package to install protoc compiler +conf-pulseaudio -- Virtual package relying on pulseaudio +conf-python-2-7 -- Virtual package relying on Python-2.7 installation +conf-python-2-7-dev -- Virtual package relying on Python-2.7 development package installation +conf-python-3 -- Virtual package relying on Python-3 installation +conf-python-3-7 -- Virtual package relying on Python >=3.7 installation +conf-python-3-dev -- Virtual package relying on Python 3 development package installation +conf-python3-yaml -- Virtual package relying on PyYAML +conf-qt -- Installation of Qt5 using APT packages or from source +conf-r -- Virtual package relying on the R interpreter +conf-r-mathlib -- Virtual package relying on a system installation of R Standalone Mathlib +conf-radare2 -- Checks that radare2 is installed +conf-rdkit -- Virtual package relying on rdkit library installation +conf-readline -- Virtual package relying on a readline system installation +conf-rocksdb -- Virtual package relying on a system installation of RocksDB +conf-ruby -- Virtual package relying on Ruby +conf-rust 0.1 Virtual package relying on cargo (rust build system) +conf-rust-2018 -- Virtual package relying on cargo (rust build system) +conf-rust-2021 1 Virtual package relying on cargo (rust build system) +conf-samplerate -- Virtual package relying on samplerate +conf-sdl-gfx -- Virtual package relying on a sdl-gfx system installation +conf-sdl-image -- Virtual package relying on a sdl-image system installation +conf-sdl-mixer -- Virtual package relying on a sdl-mixer system installation +conf-sdl-net -- Virtual package relying on a sdl-net system installation +conf-sdl-ttf -- Virtual package relying on a sdl-ttf system installation +conf-sdl2 1 Virtual package relying on a SDL2 system installation +conf-sdl2-image -- Virtual package relying on a sdl2-image system installation +conf-sdl2-mixer -- Virtual package relying on a sdl2-mixer system installation +conf-sdl2-net -- Virtual package relying on a sdl2-net system installation +conf-sdl2-ttf -- Virtual package relying on a sdl2-ttf system installation +conf-sdpa -- Virtual package relying on a SDPA binary system installation +conf-secp256k1 -- Virtual package relying on a secp256k1 lib system installation +conf-sfml2 -- Virtual package relying on a SFML2 system installation +conf-shine -- Virtual package relying on libshine +conf-snappy -- Virtual package relying on snappy +conf-soundtouch -- Virtual package relying on soundtouch +conf-sqlite3 -- Virtual package relying on an SQLite3 system installation +conf-srt -- Virtual package relying on srt +conf-srt-gnutls -- Virtual package relying on srt build with gnutls +conf-srt-openssl -- Virtual package relying on srt compiled with openssl +conf-sundials -- Virtual package relying on sundials +conf-swi-prolog -- Virtual package to install the swi-prolog interpreter +conf-taglib -- Virtual package relying on taglib +conf-tcl -- Virtual package relying on tcl +conf-texlive -- Virtual package relying on texlive / pdflatex +conf-tidy -- Virtual package relying on libtidy installation +conf-time -- Virtual package relying on the "time" command +conf-timeout -- Virtual package relying on the "timeout" command +conf-tk -- Virtual package relying on tk +conf-tree-sitter -- Check if tree-sitter is installed +conf-trexio -- Virtual package relying on trexio library installation +conf-tzdata -- Virtual package relying on tzdata +conf-unwind -- Virtual package relying on libunwind +conf-vim -- Virtual package to install the Vim editor +conf-wayland-protocols -- Virtual package relying on wayland-protocols +conf-wget -- Virtual package relying on wget +conf-which 1 Virtual package relying on which +conf-wxwidgets -- Virtual package to check the availability of wxWidgets 3.0 development packages +conf-xen -- Virtual package relying on Xen headers +conf-xkbcommon -- Virtual package relying on xkbcommon +conf-xxhash -- Virtual package relying on a xxhash system installation +conf-zig -- Virtual package relying on zig +conf-zlib 1 Virtual package relying on zlib +conf-zmq -- Virtual package relying on zmq library installation +conf-zstd -- Virtual package relying on zstd +confero -- Unicode Collation +config-file -- A library used to manage configuration files +configuration -- Analyse configuration files +conformist -- Conformist allows you to define schemas to decode, validate and sanitize input data declaratively +conjury -- Conjury library for OMake +containers -- A modular, clean and powerful extension of the OCaml standard library +containers-data -- A set of advanced datatypes for containers +containers-thread -- An extension of containers for threading +content_security_policy -- A library for building content-security policies +cookie -- Cookie handling for OCaml and ReasonML +cookies -- HTTP cookies library for OCaml +coq -- The Coq Proof Assistant +coq-core -- The Coq Proof Assistant -- Core Binaries and Tools +coq-lsp -- Language Server Protocol native server for Coq +coq-native -- Package flag enabling coq's native-compiler flag +coq-of-ocaml -- Compile a subset of OCaml to Coq +coq-serapi -- Serialization library and protocol for machine interaction with the Coq proof assistant +coq-shell -- Simplified OPAM shell for Coq +coq-stdlib -- The Coq Proof Assistant -- Standard Library +coq-waterproof -- Coq proofs in a style that resembles non-mechanized mathematical proofs +coqide -- The Coq Proof Assistant --- GTK3 IDE +coqide-server -- The Coq Proof Assistant, XML protocol server +cordova -- Binding OCaml to cordova Javascript object. +cordova-plugin-activity-indicator -- Binding OCaml to cordova-plugin-activity-indicator using gen_js_api. +cordova-plugin-background-mode -- Binding to cordova-plugin-background-mode using gen_js_api. +cordova-plugin-barcode-scanner -- Binding OCaml to cordova-plugin-barcode-scanner using gen_js_api. +cordova-plugin-battery-status -- Binding OCaml to cordova-plugin-battery-status using gen_js_api. +cordova-plugin-camera -- Binding OCaml to cordova-plugin-camera using gen_js_api. +cordova-plugin-clipboard -- Binding OCaml to cordova-plugin-clipboard using gen_js_api. +cordova-plugin-device -- Binding OCaml to cordova-plugin-device using gen_js_api. +cordova-plugin-device-orientation -- Binding OCaml to cordova-plugin-device-orientation using gen_js_api. +cordova-plugin-dialogs -- Binding OCaml to cordova-plugin-dialogs using gen_js_api. +cordova-plugin-email-composer -- Binding OCaml to cordova-plugin-email-composer using gen_js_api. +cordova-plugin-fcm -- Binding OCaml to cordova-plugin-fcm using gen_js_api. +cordova-plugin-file -- Binding OCaml to cordova-plugin-file using gen_js_api. +cordova-plugin-file-opener -- Binding OCaml to cordova-plugin-file-opener using gen_js_api. +cordova-plugin-file-transfer -- Binding OCaml to cordova-plugin-file-transfer using gen_js_api. +cordova-plugin-geolocation -- Binding OCaml to cordova-plugin-geolocation using gen_js_api. +cordova-plugin-image-picker -- Binding OCaml to cordova-plugin-image-picker using gen_js_api. +cordova-plugin-inappbrowser -- Binding OCaml to cordova-plugin-inappbrowser using gen_js_api. +cordova-plugin-insomnia -- Binding OCaml to cordova-plugin-insomnia using gen_js_api. +cordova-plugin-keyboard -- Binding OCaml to cordova-plugin-keyboard using gen_js_api. +cordova-plugin-loading-spinner -- Binding OCaml to cordova-plugin-loading-spinner using gen_js_api. +cordova-plugin-local-notifications -- Binding to cordova-plugin-local-notifications using gen_js_api. +cordova-plugin-media -- Binding OCaml to cordova-plugin-media using gen_js_api. +cordova-plugin-media-capture -- Binding OCaml to cordova-plugin-media-capture using gen_js_api. +cordova-plugin-network-information -- Binding OCaml to cordova-plugin-network-information using gen_js_api. +cordova-plugin-progress -- Binding OCaml to cordova-plugin-progress using gen_js_api. +cordova-plugin-push-notifications -- Binding OCaml to phonegap-plugin-push using gen_js_api. +cordova-plugin-qrscanner -- Binding OCaml to cordova-plugin-qrscanner using gen_js_api. +cordova-plugin-screen-orientation -- Binding OCaml to cordova-plugin-screen-orientation using gen_js_api. +cordova-plugin-sim-card -- Binding OCaml to cordova-plugin-sim-card using gen_js_api. +cordova-plugin-sms -- Binding OCaml to cordova-plugin-sms using gen_js_api. +cordova-plugin-social-sharing -- Binding OCaml to cordova-plugin-x-socialsharing using gen_js_api. +cordova-plugin-statusbar -- Binding OCaml to cordova-plugin-statusbar using gen_js_api. +cordova-plugin-toast -- Binding OCaml to cordova-plugin-toast using gen_js_api. +cordova-plugin-touch-id -- Binding OCaml to cordova-plugin-touch-id using gen_js_api. +cordova-plugin-vibration -- Binding OCaml to cordova-plugin-vibration using gen_js_api. +cordova-plugin-videoplayer -- Binding OCaml to cordova-plugin-videoplayer using gen_js_api. +core v0.16.2 Industrial strength alternative to OCaml's standard library +core-and-more -- Includes core, and some more useful extensions +core_bench -- Benchmarking library +core_compat -- Compatibility for core 0.14 +core_extended -- Extra components that are not as closely vetted or as stable as Core +core_kernel v0.16.0 Industrial strength alternative to OCaml's standard library +core_profiler -- Profiling library +core_unix v0.16.0 Unix-specific portions of Core +corecount -- Get count of cores on machine +cosovo -- An OCaml library parsing CSV files +cow -- Caml on the Web +cpdf -- High-level PDF tools based on CamlPDF +cpm 12.2.0 The Classification and Regression Performance Metrics library +cppffigen -- A C++ foreign-function-interface generator for Ocaml based on C++ STL Containers +cppo 1.6.9 Code preprocessor like cpp for OCaml +cppo_ocamlbuild -- Plugin to use cppo with ocamlbuild +cps_toolbox -- A partial OCaml standard library replacement written with continuation passing style in mind +cpu 2.0.0 Pin current process to given core number +cpuid -- Detect CPU features +craml -- A CRAM-testing framework for testing command line applications +crc -- CRC implementation supporting strings and cstructs +crdt-ml -- CRDTs - Conflict-Free Replicated Data Types for OCaml +crlibm -- Binding to CRlibm, a correctly rounded math lib +crontab -- Interacting with cron from OCaml +crowbar -- Write tests, let a fuzzer find failing cases +crunch -- Convert a filesystem into a static OCaml module +cry -- OCaml client for the various icecast & shoutcast source protocols +crypt -- Tiny binding for the unix crypt function +cryptodbm -- Encrypted layer over the dbm library: access to serverless, key-value databases with symmetric encryption. +cryptohash -- hash functions for OCaml +cryptokit 1.16.1 A library of cryptographic primitives +cryptoverif -- CryptoVerif: Cryptographic protocol verifier in the computational model +csexp 1.5.2 Parsing and printing of S-expressions in Canonical form +css -- CSS parser and printer +css-parser -- A CSS parser written in OCaml +cstruct 6.2.0 Access C-like structures directly from OCaml +cstruct-async -- Access C-like structures directly from OCaml +cstruct-lwt 6.2.0 Access C-like structures directly from OCaml +cstruct-sexp -- S-expression serialisers for C-like structures +cstruct-unix -- Access C-like structures directly from OCaml +csv -- A pure OCaml library to read and write CSV files +csv-lwt -- A pure OCaml library to read and write CSV files, LWT version +csvfields -- Runtime support for ppx_xml_conv and ppx_csv_conv_deprecated +csvtool -- Command line tool for handling CSV files +ctoxml -- Parses a C program into Cabs AST and dumps as an XML document +ctypes 0.20.2 Combinators for binding to C libraries without writing any C +ctypes-build -- Support for building Ctypes bindings. +ctypes-foreign 0.18.0 Virtual package for enabling the ctypes.foreign subpackage +ctypes-zarith -- Ctypes wrapper for zarith +ctypes_stubs_js 0.1 Js_of_ocaml Javascript stubs for the OCaml ctypes library +cubicle -- SMT based model checker for parameterized systems +cucumber -- Cucumber BDD for OCaml +cudf -- CUDF library (part of the Mancoosi tools) +cue_sheet_maker -- A library to create cuesheet +cuid -- CUID generator for OCaml. +cumulus -- Differential FRP based on the React library +curly -- Curly is a brain dead wrapper around the curl command line utility +current -- Pipeline language for keeping things up-to-date +current-albatross-deployer -- An ocurrent plugin to deploy MirageOS unikernels +current-web-pipelines -- Simplify the creation of pipeline websites +current_ansi -- ANSI escape sequence parser +current_docker -- OCurrent Docker plugin +current_examples -- Example pipelines for OCurrent +current_git -- Git plugin for OCurrent +current_github -- GitHub plugin for OCurrent +current_gitlab -- GitLab plugin for OCurrent +current_incr -- Self-adjusting computations +current_ocluster -- OCurrent plugin for OCluster builds +current_rpc -- Cap'n Proto RPC plugin for OCurrent +current_slack -- Slack plugin for OCurrent +current_ssh -- SSH plugin for OCurrent +current_web -- Test web UI for OCurrent +curses -- Bindings to ncurses +curve-sampling -- Sampling of parametric and implicit curves +cviode -- Contact variational integrators - native ocaml version +DAGaml -- DAGaml : Abstract DAG manipulation in OCaml +DkSDKFFIOCaml_Std -- DkSDK FFI for OCaml +DkSDKFFIOCaml_StdExport-linux_x86_64 -- The DkSDKFFIOCaml_StdExport foreign library on 64-bit Intel/AMD Linux +daft -- DAFT Allows File Transfers +dap -- Debug adapter protocol +data-encoding 0.7.1 Library of JSON and binary encoding combinators +datakit-server -- A library to write Datakit servers +datakit-server-9p -- Build Datakit servers using the 9P filesystem protocol +datalog -- An in-memory datalog implementation for OCaml +dates_calc -- A date calculation library +daypack-lib -- A schedule, time and time slots handling library +dbf -- DBF format parsing +dbm -- Binding to the NDBM/GDBM Unix "databases" +deadlock -- Frama-C plugin for deadlock detection +debian-formats -- Parse debian files +decimal -- Arbitrary-precision floating-point decimal library +decoders -- Elm-inspired decoders for Ocaml +decoders-bencode -- Bencode backend for decoders +decoders-cbor -- CBOR backend for decoders +decoders-ezjsonm -- Ezjsonm backend for decoders +decoders-ezxmlm -- Ezxmlm backend for decoders +decoders-jsonaf -- Jsonaf backend for decoders +decoders-jsonm -- Jsonm backend for decoders +decoders-msgpck -- Msgpck backend for decoders +decoders-sexplib -- Sexplib backend for decoders +decoders-yojson -- Yojson backend for decoders +decompress 1.5.3 Implementation of Zlib and GZip in OCaml +dedent -- A library for improving redability of multi-line string constants in code. +dedukti -- An implementation of The Lambda-Pi Modulo Theory +delimcc -- Oleg's delimited continuations library for byte-code and native OCaml +delimited_parsing -- Parsing of character (e.g., comma) separated and fixed-width values +depgraph -- dot graphs out of ocamldep output +depyt -- Yet-an-other type combinator library +deriving -- Extension to OCaml for deriving functions from type declarations +devkit -- Development kit - general purpose library +diet -- Discrete Interval Encoding Trees +diffable -- An interface for diffs. +digestif 1.1.4 Hashes implementations (SHA*, RIPEMD160, BLAKE2* and MD5) +directories -- An OCaml library that provides configuration, cache and data paths (and more!) following the suitable conventions on Linux, macOS and Windows +dirsift -- Search for directories by type +dirsp-exchange -- Published protocols for the authenticated message exchange +dirsp-exchange-kbb2017 -- The formally verified KBB2017 protocol for 1-on-1 secure conversations similar to the Signal Protocol +dirsp-proscript -- OCaml-ified interfaces for the ProScript Cryptography Library +dirsp-proscript-mirage -- Mirage crypto backed implementation of the ProScript Cryptography Library +dirsp-ps2ocaml -- ProScript to OCaml translator +diskuvbox -- Cross-platform basic set of script commands +dispatch -- Path-based dispatching for client- and server-side applications +dispatch-js -- Path-based dispatch: js_of_ocaml-specific support +distributed -- Library to provide Erlang style distributed computations. This library is inspired by Cloud Haskell +distributed-lwt -- A library to probide a lwt based implementation of Distributed +diy -- Tool suite for testing shared memory models +dkim -- Implementation of DKIM in OCaml +dkim-bin -- Implementation of DKIM in OCaml +dkim-mirage -- Implementation of DKIM in OCaml for MirageOS +dkml-c-probe -- Cross-compiler friendly ABI and library discovery for OCaml's native C compilers +dkml-compiler-env -- Scripts to configure DKML compilation in various environments +dkml-component-offline-ocamlrun -- DKML staging component for ocamlrun +dkml-component-offline-opam -- Offline install of Opam +dkml-component-staging-ocamlrun -- DKML staging component for ocamlrun +dkml-component-staging-opam32 -- DKML component for 32-bit versions of opam +dkml-component-staging-opam64 -- DKML component for 64-bit versions of opam +dkml-component-xx-console -- Component used by the dkml-package-console Console Packager +dkml-dune-dsl -- Embedded DSL for Dune files to do syntax checking, auto-completion and generate dune.inc include files +dkml-dune-dsl-show -- An interpreter for the embedded DSL of Dune that shows the DSL as a real Dune file +dkml-install -- API and registry for DkML installation components +dkml-install-installer -- Build tools for DkML installers +dkml-install-runner -- Runner executable for DkML installation +dkml-option-vcpkg -- Configures DKML components to support vcpkg +dkml-package-console -- Console setup and uninstall executables for DkML installation +dkml-runtime-common -- Common runtime code used in DKML +dkml-runtime-common-native -- Common runtime code used in DKML +dkml-workflows -- GitLab CI/CD and GitHub Action workflows used by and with Diskuv OCaml (DKML) tooling +dlm -- Libdlm bindings +dmap -- A library that implements dependent (heterogeneous) maps +dns -- An opinionated Domain Name System (DNS) library +dns-certify -- MirageOS let's encrypt certificate retrieval +dns-cli -- Unix command line utilities using uDNS +dns-client -- DNS client API +dns-client-lwt -- DNS client API using lwt +dns-client-mirage -- DNS client API for MirageOS +dns-mirage -- An opinionated Domain Name System (DNS) library +dns-resolver -- DNS resolver business logic +dns-server -- DNS server, primary and secondary +dns-stub -- DNS stub resolver +dns-tsig -- TSIG support for DNS +dnssec -- DNSSec support for OCaml-DNS +docfd -- TUI fuzzy document finder +docker-api -- Binding to the Docker Remote API +docker_hub -- Library aiming to provide data from hub.docker.com +dockerfile -- Dockerfile eDSL in OCaml +dockerfile-cmd -- Dockerfile eDSL -- generation support +dockerfile-opam -- Dockerfile eDSL -- opam support +docout -- Functor to create (text) output functions +docteur -- A simple read-only Key/Value from Git to MirageOS +docteur-solo5 -- A simple read-only Key/Value from Git to MirageOS +docteur-unix -- A simple read-only Key/Value from Git to MirageOS +doculib -- A GUI for tagging and managing document metadata for books, textbooks, or articles +doi2bib -- Small CLI to get a bibtex entry from a DOI, an arXiv ID or a PubMed ID +dokeysto -- The dumb OCaml key-value store +dokeysto_camltc -- The dumb OCaml key-value store w/ tokyocabinet backend +dokeysto_lz4 -- The dumb OCaml key-value store w/ LZ4 compression +dolmen 0.9 A parser library for automated deduction +dolmen_bin -- A linter for logic languages +dolmen_loop 0.9 A tool library for automated deduction tools +dolmen_lsp -- A LSP server for automated deduction languages +dolmen_model -- A model checker for automated deduction languages +dolmen_type 0.9 A typechecker for automated deduction languages +dolog 6.0.0 The dumb OCaml logging library +domain-local-await -- A scheduler independent blocking mechanism +domain-local-timeout -- A scheduler independent timeout mechanism +domain-name 0.4.0 RFC 1035 Internet domain names +domain_shims -- A non-parallel implementation of Domains compatible with OCaml 4 +dose3 -- Dose library (part of Mancoosi tools) +dose3-extra -- Dose-extra libraries and tools (part of Mancoosi tools) +dot-merlin-reader -- Reads config files for merlin +dotenv -- Javascript's dotenv port to OCaml +down -- An OCaml toplevel (REPL) upgrade +dream 1.0.0~alpha5 Tidy, feature-complete Web framework +dream-accept -- Accept headers parsing for Dream +dream-cli -- Command Line Interface for Dream applications +dream-encoding -- Encoding primitives for Dream +dream-html -- HTML generator eDSL for Dream +dream-htmx -- Htmx utilities for Dream +dream-httpaf 1.0.0~alpha2 Internal: shared http/af stack for Dream (server) and Hyper (client) +dream-livereload -- Live reloading for Dream applications +dream-pure 1.0.0~alpha2 Internal: shared HTTP types for Dream (server) and Hyper (client) +dream-serve -- Static HTML website server with live reload +drom -- The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like user experience +drom_lib -- The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like user experience +drom_toml -- The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like user experience +dropbox -- Binding to the Dropbox Remote API +dropbox_lwt_unix -- Binding to the Dropbox Remote API (Unix) +dryunit -- A detection tool for traditional and popular testing frameworks +dssi -- Bindings for the DSSI API which provides audio synthesizers +dtc-pb -- DTC Protocol library autogenerated from Protobuf description +dtoa -- Converts OCaml floats into strings, using the efficient Grisu3 algorithm +dtools -- Library providing various helper functions to make daemons +dual -- Dual numbers library +duff -- Rabin's fingerprint and diff algorithm in OCaml +dum -- Inspect the runtime representation of arbitrary OCaml values +dump_ocamlformat -- Dump preset configuration files for ocamlformat +dune 3.10.0 Fast, portable, and opinionated build system +dune-action-plugin -- [experimental] API for writing dynamic Dune actions +dune-build-info 3.11.1 Embed build information inside executable +dune-compiledb -- Generate compile_commands.json from dune rules +dune-configurator 3.11.1 Helper library for gathering system configuration +dune-deps -- Show dependency graph of a multi-component dune project +dune-expand -- Tool to view ppx-expanded OCaml source files +dune-glob -- Glob string matching language supported by dune +dune-private-libs 3.11.1 Private libraries of Dune +dune-release -- Release dune packages in opam +dune-rpc 3.11.1 Communicate with dune using rpc +dune-rpc-lwt -- Communicate with dune using rpc and Lwt +dune-site 3.11.1 Embed locations information inside executable and libraries +duppy -- Library providing monadic threads +duration 0.2.1 Conversions to various time units +dyn 3.11.1 Dynamic type +dyntype -- syntax extension which makes OCaml types and values easier to manipulate programmatically +earley -- Parsing library based on Earley Algorithm +earlybird -- OCaml debug adapter +easy-format -- High-level and functional interface to the Format module of the OCaml standard library +easy_logging -- Module to log messages. Aimed at being both powerful and easy to use +easy_logging_yojson -- Configuration loader for easy_logging with yojson backend +ecaml -- Library for writing Emacs plugin in OCaml +edn -- Parsing OCaml library for EDN format +efl -- An OCaml interface to the Enlightenment Foundation Libraries (EFL) and Elementary. +ego -- Ego (EGraphs OCaml) is extensible EGraph library for OCaml +eigen -- Owl's OCaml interface to Eigen3 C++ library +either 1.0.0 Compatibility Either module +elasticsearch-cli -- Command-line client for Elasticsearch +electrod -- Formal analysis for the Electrod formal pivot language +elina -- ETH LIBRARY FOR NUMERICAL ANALYSIS +eliom -- Client/server Web and mobile framework +elpi -- ELPI - Embeddable λProlog Interpreter +email_message -- E-mail message parser +embedded_ocaml_templates -- EML is a simple templating language that lets you generate text with plain OCaml +emile -- Parser of email address according RFC822 +emoji -- Use emojis by name +encore -- Library to generate encoder/decoder which ensure isomorphism +enumerators -- Finite lazy enumerators +env_config -- Helper library for retrieving configuration from an environment variable +epictetus -- Elegant Printer of Insanely Complex Tables Expressing Trees with Uneven Shapes +eprover -- E Theorem Prover +eqaf 0.9 Constant-time equal function on string +equinoxe -- An OCaml wrapper for the Equinix API +equinoxe-cohttp -- Equinoxe with the cohttp-lwt-unix request handler +equinoxe-hlc -- Equinoxe with the http-lwt-client request handler +eris -- Encoding for Robust Immutable Storage (ERIS) +eris-lwt -- Lwt bindings to eris +erlang -- Libraries to manipulate Erlang sources +errpy -- Errpy: An Error Recovering Python Parser implemented in Rust +erssical -- Converting RSS event feeds to ical +esgg -- Elasticsearch guided (code) generator +esperanto -- An OCaml compiler with Cosmopolitan +esperanto-cosmopolitan -- Cosmopolitan toolchain for OCaml compiler +ethernet -- OCaml Ethernet (IEEE 802.3) layer, used in MirageOS +euler -- An arithmetic library for OCaml's standard integers +exenum -- Build efficient enumerations for datatypes. Inspired by Feat for Haskell. +exn-source -- Exception backtrace for OCaml with source code printing +expect -- Simple implementation of "expect" to help building unitary testing of interactive program +expect_test_helpers_async -- Async helpers for writing expectation tests +expect_test_helpers_core v0.16.0 Helpers for writing expectation tests +extism -- Extism bindings +extism-manifest -- Extism manifest bindings +extlib -- A complete yet small extension for OCaml standard library +extprot -- Extensible binary protocols for cross-language communication and long-term serialization +extunix -- Collection of thin bindings to various low-level system API +ez_api -- Easy API library and tools +ez_cmdliner -- Easy interface to Cmdliner à la Arg.parse with sub-commands +ez_config -- Easy management of configuration files +ez_file -- Easy file manipulation (read_file, write_file, etc.) +ez_hash -- Ez hash & crypto utilities +ez_opam_file -- Package ez_opam_file is a simple compatibility layer on top of opam-file-format +ez_pgocaml -- A simple library to work with pgocaml +ez_search -- The ez_search library +ez_subst -- Ez_subst is a simple module to perform string substitutions +ezcurl -- Friendly wrapper around OCurl +ezcurl-lwt -- Friendly wrapper around OCurl, Lwt version +ezdl -- Easy dynamic linking of C functions from ocaml +ezgzip -- Simple gzip (de)compression library +ezjs_ace -- Bindings for the Ace editor +ezjs_blockies -- Bindings for Blockies +ezjs_cleave -- Bindings for Cleave +ezjs_crypto -- Bindings for SubtleCrypto +ezjs_cytoscape -- Bindings for Cytoscape +ezjs_d3pie -- Bindings for d3pie +ezjs_extension -- Binding for Chrome and Firefox extension API +ezjs_fetch -- Bindings for Fetch +ezjs_idb -- Bindings for IndexedDB +ezjs_jquery -- Bindings for JQuery +ezjs_min -- A bunch of js_of_ocaml shortcuts +ezjs_odometer -- Bindings for odometer +ezjs_push -- Bindings for Push Notification +ezjs_qrcode -- Bindings for QRCode.js +ezjs_recaptcha -- Bindings for reCAPTCHA +ezjs_timeline -- Bindings for TimelineJS +ezjsonm 1.3.0 Simple interface on top of the Jsonm JSON library +ezjsonm-lwt -- Simple Lwt-based interface to the Jsonm JSON library +ezresto -- A minimal OCaml library for type-safe HTTP/JSON RPCs +ezresto-directory -- A minimal OCaml library for type-safe HTTP/JSON RPCs +ezsqlite -- Simplified SQLite3 bindings for OCaml +ezxmlm -- Combinators for parsing and selection of XML structures +FPauth -- Easy authentication system for Dream framework +FPauth-core -- Easy authentication system for Dream framework +FPauth-responses -- Responses on basic events in FPauth-core authentication system +FPauth-strategies -- Strategies to be used with FPauth-core authentication system +FrontC -- Parses C programs to an abstract syntax tree +faad -- Bindings for the faad library which provides functions for decoding AAC audio files +facile -- A Functional Constraint Library implemented in Objective Caml. +fadbadml -- FADBAD++ for OCaml +faraday 0.8.2 A library for writing fast and memory-efficient serializers +faraday-async -- Async support for Faraday +faraday-lwt 0.8.2 Lwt support for Faraday +faraday-lwt-unix 0.8.2 Lwt_unix support for Faraday +farfadet -- A printf-like for [Faraday](https://github.com/inhabitedtype/faraday) library +farith -- Floating point numbers library extracted from the Flocq Coq Library +farmhash -- Bindings for Google's farmhash library +fasmifra -- Molecular Generation by Fast Assembly of SMILES Fragments +fat-filesystem -- Pure OCaml implementation of the FAT filesystem +fd-send-recv -- Bindings for sendmsg/recvmsg that allow Unix.file_descrs to be sent and received over Unix domain sockets +fdkaac -- Fraunhofer FDK AAC Codec Library +feat -- Facilities for enumerating and sampling algebraic data types, using Zarith for big numbers +feat-core -- Facilities for enumerating and sampling algebraic data types +feat-num -- Facilities for enumerating and sampling algebraic data types, using Num for big numbers +feather -- A minimal shell interface +feather_async -- Async interface to Feather +febusy -- Embedded build system library +ff -- OCaml implementation of Finite Field operations +ff-bench -- Benchmark library for finite fields over the package ff-sig +ff-pbt -- Property based testing library for finite fields over the package ff-sig +ff-sig -- Minimal finite field signatures +ffmpeg -- Bindings for the ffmpeg libraries +ffmpeg-av -- Bindings for the ffmpeg libraries -- top-level helpers +ffmpeg-avcodec -- Bindings for the ffmpeg avcodec library +ffmpeg-avdevice -- Bindings for the ffmpeg avdevice library +ffmpeg-avfilter -- Bindings for the ffmpeg avfilter library +ffmpeg-avutil -- Bindings for the ffmpeg avutil libraries +ffmpeg-swresample -- Bindings for the ffmpeg swresample library +ffmpeg-swscale -- Bindings for the ffmpeg swscale library +fftw3 -- Binding to the Fast Fourier Transform library FFTW +fiat-p256 -- Primitives for Elliptic Curve Cryptography taken from Fiat +fiber 3.7.0 Dune's monadic structured concurrency library +fiber-lwt -- Compatibility layer for fibers inside Lwt +fieldslib v0.16.0 Syntax extension to define first class values representing record fields, to get and set record fields, iterate and fold over all fields of a record and create new record values +file_path -- A library for typed manipulation of UNIX-style file paths +fileutils -- API to manipulate files (POSIX like) and filenames +finch -- Simple and fast site generator +findlib_top -- Exposes findlib_top.cma without the need for using predicates +fit -- A parser for Garmin FIT data files +fix 20230505 Algorithmic building blocks for memoization, recursion, and more +flac -- Bindings to libflac +flex-array -- Flexible arrays +flint -- Stub of the C library Flint2 +flock -- Ctypes bindings to flock for OCaml +fm-simplex-plugin -- Alt-Ergo, an SMT Solver for Software Verification: FM-Simplex Plugin +fmlib 0.5.6 Functional monadic library +fmlib_browser 0.5.6 Write web applications for the browser in elm style +fmlib_js 0.5.6 Library for easy compilation from ocaml to javascript +fmlib_parse 0.5.6 Parsing with combinators and indentation sensitivity +fmlib_pretty 0.5.6 Pretty printing support for tree like structures +fmlib_std 0.5.6 Standard datatypes of Fmlib +fmt 0.9.0 OCaml Format pretty-printer combinators +fontforge-of-ocaml -- OCaml binding of FontForge +format -- Format is a syntax extension which defines quotations for building +fpath 0.7.3 File system paths for OCaml +frama-c -- Platform dedicated to the analysis of source code written in C +frama-c-lannotate -- Lannotate plugin of Frama-C, part of the LTest suite +frama-c-luncov -- Luncov plugin of Frama-C, part of the LTest suite +frama-c-metacsl -- MetAcsl plugin of Frama-C for writing pervasives properties +frama-clang -- Frama-C plug-in based on Clang for parsing C++ files +freetds -- Binding to the FreeTDS library +frei0r -- Bindings for the frei0r API which provides video effects +frenetic -- The Frenetic Programming Language and Runtime System +fromager -- A CLI to format an ocaml codebase +fsevents -- OCaml bindings to macOS FSEvents +fsevents-lwt -- Lwt interface to macOS FSEvents +fsml -- A library for describing and describing synchronous finite state machines +fstar -- Verification system for effectful programs +fstreams -- Functional, lazy, infinite streams. +fswatch -- Bindings for libfswatch -- file change monitor +fswatch_async -- JaneStreet Async extension for fswatch +fswatch_lwt -- Lwt extension for fswatch +functoria -- A DSL to organize functor applications +functoria-runtime -- Runtime support library for functoria-generated code +functory -- Distributed computing library. +funfields -- Functional bit field library +fuzzy_compare -- Fastest bounded Levenshtein comparator over generic structures +fuzzy_match -- Libraries for fuzzy string matching +fzf -- A library for running the fzf command line tool +GT -- Generic programming with extensible transformations +GuaCaml -- GuaCaml : Generic Unspecific Algorithmic in OCaml +gadelac -- Preprocessor for the Game Description Language. +gammu -- Cell phone and SIM card access. +gapi-ocaml -- A simple OCaml client for Google Services +gappa -- Tool intended for formally proving properties on numerical programs dealing with floating-point or fixed-point arithmetic +gavl -- Bindings for the gavl library which provides functions for converting images formats, colorspaces, etc. +gbddml -- The Verimag bdd library +gd -- OCaml interface to the GD graphics library. +gdal -- GDAL and OGR bindings +gdbprofiler -- A profiler for native OCaml and other executables +gedcom -- GEDCOM parsing. +gen 1.1 Iterators for OCaml, both restartable and consumable +gen-bs -- generate bucklescript code from Javascript type specifications +gen_js_api -- Easy OCaml bindings for JavaScript libraries +genspio -- Typed EDSL to generate POSIX Shell scripts +genspir -- Generate almost uniformly points on a sphere +geoip -- Bindings to GeoIP database library. +geojson -- Pure OCaml library for GeoJSON +geoml -- Geoml: 2D Geometry library for OCaml +get_line -- Robustly select lines from file; can replace the head and tail shell commands and do even more +getopt -- Parsing of command line arguments (similar to GNU GetOpt) for OCaml +getopts -- Analyse command line arguments +gettext -- Internationalization library (i18n) +gettext-camomile -- Internationalization library using camomile (i18n) +gettext-stub -- Internationalization using C gettext library (i18n) +gg 1.0.0 Basic types for computer graphics in OCaml +git -- Git format and protocol in pure OCaml +git-cohttp -- A package to use HTTP-based ocaml-git with Unix backend +git-cohttp-mirage -- A package to use HTTP-based ocaml-git with MirageOS backend +git-cohttp-unix -- A package to use HTTP-based ocaml-git with Unix backend +git-http -- Client implementation of the "Smart" HTTP Git protocol in pure OCaml +git-kv -- A Mirage_kv implementation using git +git-mirage -- A package to use ocaml-git with MirageOS backend +git-paf -- A package to use HTTP-based ocaml-git with MirageOS backend +git-unix -- Virtual package to install and configure ocaml-git's Unix backend +github -- GitHub APIv3 OCaml library +github-data -- GitHub APIv3 data library +github-hooks -- GitHub API web hook listener library +github-hooks-unix -- GitHub API web hook listener library using unix functions +github-jsoo -- GitHub APIv3 JavaScript library +github-unix -- GitHub APIv3 Unix library +gitlab -- GitLab APIv4 OCaml library +gitlab-jsoo -- Gitlab APIv4 OCaml library +gitlab-unix -- GitLab APIv4 OCaml library +gitlab_pipeline_notifier -- Watches GitLab pipelines and notifies on status updates using 'send-notify' +gles3 -- OCaml GLES 3.0 bindings +glfw-ocaml -- A GLFW binding for OCaml +glical -- Glical: glancing at iCalendar data. +glicko2 -- Implementation of the Glicko2 algorithm +glMLite -- OpenGL bindings for OCaml +globlon -- A globbing library for OCaml +glpk -- Bindings for glpk +gluten -- A reusable runtime library for network protocols +gluten-async -- Async support for gluten +gluten-lwt -- Lwt-specific runtime for gluten +gluten-lwt-unix -- Lwt + Unix support for gluten +gluten-mirage -- Mirage support for gluten +gmap 0.3.0 Heterogenous maps over a GADT +gmp -- The GNU Multiple Precision Arithmetic Library +gmp-ecm -- GMP-ECM library for the Elliptic Curve Method (ECM) for integer factorization +gmp-freestanding -- The GNU Multiple Precision Arithmetic Library +gmp-xen -- The GNU Multiple Precision Arithmetic Library +gnuplot -- Simple interface to Gnuplot Gnuplot-OCaml provides a simple interface to Gnuplot from OCaml. The API supports only 2D graphs and was inspired by FnuPlot +goblint -- Static analysis framework for C +goblint-cil -- A front-end for the C programming language that facilitates program analysis and transformation +google-drive-ocamlfuse -- A FUSE filesystem over Google Drive +gopcaml-mode -- Ultimate Ocaml editing plugin, providing advanced structural editing, movement and analysis in Emacs +gopcaml-mode-merlin -- Ultimate Ocaml editing plugin, providing advanced structural editing, movement and analysis in Emacs (uses Merlin parser) +gospel -- A tool-agnostic formal specification language for OCaml +gotd -- Quickly start an OCaml project +gperftools -- Bindings to gperftools +gpiod -- A wrapper around the C libgpiod library for GPIO on recent (>4.8) Linux kernels +gpr -- GPR - Library and Application for Gaussian Process Regression +gpx -- Conversions between XML and GPX (1.1) types. +gr -- OCaml bindings to the GR plotting library +gradescope_submit -- A small script to submit to Gradescope via GitHub +grain_dypgen -- Self-extensible parsers and lexers for OCaml +graphics -- The OCaml graphics library +graphicspdf -- Version of OCaml's Graphics library which outputs PDFs. +graphlib -- Generic Graph library +graphql 0.14.0 Build GraphQL schemas and execute queries against them +graphql-async -- Build GraphQL schemas with Async support +graphql-cohttp -- Run GraphQL servers with `cohttp` +graphql-lwt 0.14.0 Build GraphQL schemas with Lwt support +graphql_parser 0.14.0 Library for parsing GraphQL queries +graphql_ppx -- GraphQL PPX rewriter for ReScript/ReasonML +graphv -- Top_level graphv package, includes all dependencies +graphv_core -- Functor for creating a new Graphv library based on a font render and backend renderer +graphv_core_lib -- Primitives for the Graphv vector graphics library +graphv_font -- Functor for generating the Graphv font library +graphv_font_js -- Javascript implementation of the font interface for Graphv +graphv_font_stb_truetype -- STB truetype implementation of the font interface for Graphv +graphv_gles2 -- Functor for creating a Graphv renderer based on GLES2 +graphv_gles2_native -- Full version of the Graphv library based on native GLES2 +graphv_gles2_native_impl -- Native GLES2 implementation of the backend renderer for the Graphv library +graphv_webgl -- Full version of the Graphv library based on WebGL +graphv_webgl_impl -- WebGL implementation of the backend renderer for the Graphv library +gremlin -- Gremlin Client Library +grenier -- A collection of various algorithms in OCaml +grib -- Bindings for the ECMWF GRIB API +grpc -- A modular gRPC library +grpc-async -- An Async implementation of gRPC +grpc-lwt -- An Lwt implementation of gRPC +gsl -- GSL - Bindings to the GNU Scientific Library +gstreamer -- Bindings for the GStreamer library which provides functions for playning and manipulating multimedia streams +guardian -- Role-based access control for OCaml +gufo -- A fonctionnal shell +guile -- Bindings to GNU Guile Scheme for OCaml +gxl-light -- Gxl parser and in-place destructive update library +h1_parser -- Parser for HTTP 1.1 +h2 -- A high-performance, memory-efficient, and scalable HTTP/2 library for OCaml +h2-async -- Async support for h2 +h2-lwt -- Lwt support for h2 +h2-lwt-unix -- Lwt + UNIX support for h2 +h2-mirage -- Lwt support for h2 +hack_parallel -- Parallel and shared memory library +hacl -- Tezos binding for Hacl* +hacl-star 0.7.1 OCaml API for EverCrypt/HACL* +hacl-star-raw 0.7.1 Auto-generated low-level OCaml bindings for EverCrypt/HACL* +hacl_func -- Minimal Hacl bindings +hacl_x25519 -- Primitives for Elliptic Curve Cryptography taken from Project Everest +hamt -- Hash Array Mapped Tries +happy-eyeballs -- Connecting to a remote host via IP version 4 or 6 +happy-eyeballs-lwt -- Connecting to a remote host via IP version 4 or 6 using Lwt_unix +happy-eyeballs-mirage -- Connecting to a remote host via IP version 4 or 6 using Mirage +hardcaml -- RTL Hardware Design in OCaml +hardcaml_axi -- Hardcaml AXI Interface Types +hardcaml_c -- Hardcaml C Simulation Backend +hardcaml_circuits -- Hardcaml Circuits +hardcaml_fixed_point -- Hardcaml fixed point arithmetic +hardcaml_handshake -- Hardcaml Handshake +hardcaml_of_verilog -- Convert Verilog to a Hardcaml design +hardcaml_step_testbench -- Hardcaml Testbench Monad +hardcaml_verify -- Hardcaml Verification Tools +hardcaml_verilator -- Hardcaml Verilator Simulation Backend +hardcaml_waveterm -- A terminal based digital waveform viewer for Hardcaml +hardcaml_xilinx -- Hardcaml wrappers for Xilinx memory primitives +hardcaml_xilinx_components -- Hardcaml Xilinx component definitions +hardcaml_xilinx_reports -- Hardcaml Xilinx Reports +hashcons 1.3 OCaml hash-consing library +hashset -- Sets as hash tables +haxe -- Multi-target universal programming language +hdfs -- Bindings to libhdfs +hdr_histogram -- OCaml bindings to Hdr Histogram +headache -- Automatic generation of files headers +header-check -- A tool to check and update source headers, using checksums +heptagon -- Compiler for the Heptagon/BZR synchronous programming language +herdtools7 -- The herdtools suite for simulating and studying weak memory models +hevea -- A quite complete and fast LATEX to HTML translator +hex 1.5.0 Library providing hexadecimal converters +hex_encode -- Hexadecimal encoding library +hexstring -- A library to encode to and decode from hexadecimal strings +hg_lib -- A library that wraps the Mercurial command line interface +hidapi 1.1.2 Bindings to Signal11's hidapi library +higher -- Library for higher-kinded programming +higher_kinded v0.16.0 A library with an encoding of higher kinded types in OCaml +higlo -- Syntax highlighting library +hilite -- Build time syntax highlighting +hiredis -- Redis tools based on the Hiredis C library +hiredis-value -- Hiredis Value type +hkdf 1.0.4 HMAC-based Extract-and-Expand Key Derivation Function (RFC 5869) +hlarp -- Normalize and compare HLA typing output. +hll -- +hmap 0.8.1 Heterogeneous value maps for OCaml +hockmd -- A library to access hackmd's api +hpack -- An HPACK (Header Compression for HTTP/2) implementation in OCaml +htmlfromtexbooks -- From TeX To Human-Readable HTML +htmlit 0.1.0 HTML generation combinators for OCaml +hts_shrink -- Distance-Based Boolean Applicability Domain for High Throughput Screening data +http -- Type definitions of HTTP essentials +http-cookie -- HTTP cookie library for OCaml +http-date -- HTTP Datetime encoder/decoder +http-lwt-client -- A simple HTTP client using http/af, h2, and lwt +http-mirage-client -- HTTP client for MirageOS +http-multipart-formdata -- Http multipart/formdata parser +http_async -- Async library for HTTP/1.1 servers +httpaf -- A high-performance, memory-efficient, and scalable web server for OCaml +httpaf-lwt-unix -- Lwt support for http/af +httpaf_caged -- A higher-level httpaf-async server interface +httph -- Minimal OCaml to the httpserver.h http server toolkit +huffman -- An OCaml library to manipulate Huffman trees +humane-re -- A human friendly interface to regular expressions in OCaml +hvsock -- Bindings for Hyper-V AF_VSOCK +hweak -- An hastable with weak pointer enabling the GC to collect things that are in the hashtable +hxd -- Hexdump in OCaml +hyper -- Web client with HTTP/1, HTTP/2, TLS, and WebSocket support +ISO3166 -- OCaml library for working with ISO3166 +ISO8601 -- ISO 8601 and RFC 3999 date parsing for OCaml +i2c -- i2c +i3ipc -- A pure OCaml implementation of the i3 IPC protocol +icalendar -- A library to parse and print the iCalendar (RFC 5545) format +idd -- Identity-suppressed decision diagrams (IDDs) +idds -- Identity-suppressed decision diagrams (IDDs) +igvxml -- Create IGV session files from the command-line +imagelib -- Library implementing parsing of image formats such as PNG, BMP, PPM +incr_dom -- A library for building dynamic webapps, using Js_of_ocaml +incr_dom_interactive -- A monad for composing chains of interactive UI elements +incr_dom_partial_render -- A library for simplifying rendering of large amounts of data +incr_dom_sexp_form -- A library for building forms that allow the user to edit complicated types +incr_map -- Helpers for incremental operations on map like data structures +incr_select -- Handling of large set of incremental outputs from a single input +incremental -- Library for incremental computations +indentation_buffer -- A library for building strings with indentation +index 1.6.1 A platform-agnostic multi-level index for OCaml +index-bench -- Index benchmarking suite +inferno -- A library for constraint-based Hindley-Milner type inference +influxdb -- InfluxDB client library +influxdb-async -- InfluxDB client library using async for concurrency +influxdb-lwt -- InfluxDB client library using lwt for concurrency +inotify -- Inotify bindings for OCaml +inquire -- Create beautiful interactive command line interface in OCaml +inquirer_oc -- A collection of common interactive command line user interfaces +inspect -- Inspect the runtime representation of arbitrary OCaml values. +int_repr v0.16.0 Integers of various widths +integers 0.7.0 Various signed and unsigned integer types for OCaml +integers_stubs_js 1.0 Javascript stubs for the integers library in js_of_ocaml +integration1d -- Collection of 1D numerical integration routines +interface-prime -- Interfaces for common design patterns +interface-prime-lwt -- Interfaces for common design patterns (LWT implementation) +interval -- An interval arithmetic library for OCaml (meta package) +interval-map -- An immutable interval map data structure +interval_base -- An interval library for OCaml (base package) +interval_crlibm -- An interval library for OCaml (crlibm version) +interval_intel -- An interval library for OCaml +inuit -- Make interactive text-based user-interfaces in OCaml +io -- Simple, secure and composable abstraction for efficient component +io-page -- Support for efficient handling of I/O memory pages +io-page-unix -- Support for efficient handling of I/O memory pages on Unix +iomux -- IO Multiplexer bindings +iostream -- Generic, composable IO input and output streams +ip2location -- IP2Location OCaml module to get geolocation data +ip2locationio -- IP2Location.io OCaml module to get geolocation and WHOIS data +ipaddr 5.5.0 A library for manipulation of IP (and MAC) address representations +ipaddr-cstruct -- A library for manipulation of IP address representations using Cstructs +ipaddr-sexp 5.5.0 A library for manipulation of IP address representations using sexp +ipv6-multicast -- UNIX bindings for IPv6 multicast +ipv6-multicast-lwt -- UNIX bindings for IPv6 multicast — Lwt +irc-client -- IRC client library - core functionality +irc-client-lwt -- IRC client library - Lwt implementation +irc-client-lwt-ssl -- IRC client library - Lwt SSL implementation +irc-client-tls -- IRC client library - TLS implementation +irc-client-unix -- IRC client library - Unix implementation +iri -- Implementation of Internationalized Resource Identifiers (IRIs) +irmin 3.7.2 Irmin, a distributed database that follows the same design principles as Git +irmin-bench -- Irmin benchmarking suite +irmin-chunk -- Irmin backend which allow to store values into chunks +irmin-cli -- CLI for Irmin +irmin-client -- A client for irmin-server +irmin-containers -- Mergeable Irmin data structures +irmin-fs -- Generic file-system backend for Irmin +irmin-git -- Git backend for Irmin +irmin-graphql -- GraphQL server for Irmin +irmin-http -- HTTP client and server for Irmin +irmin-indexeddb -- Irmin backend using the web-browser's IndexedDB store +irmin-layers -- Combine different Irmin stores into a single, layered store +irmin-mem -- Generic in-memory Irmin stores +irmin-mirage -- MirageOS-compatible Irmin stores +irmin-mirage-git -- MirageOS-compatible Irmin stores +irmin-mirage-graphql -- MirageOS-compatible Irmin stores +irmin-pack 3.7.2 Irmin backend which stores values in a pack file +irmin-pack-tools -- Utils for Irmin-pack +irmin-server -- A high-performance server for Irmin +irmin-test -- Irmin test suite +irmin-tezos -- Irmin implementation of the Tezos context hash specification +irmin-tezos-utils -- Utils for Irmin tezos +irmin-unix -- Unix backends for Irmin +irmin-watcher -- Portable Irmin watch backends using FSevents or Inotify +iso639 -- Language Codes for OCaml +iter -- Simple abstraction over `iter` functions, intended to iterate efficiently on collections while performing some transformations +itv-tree -- Float intervals tree library +jane-street-headers v0.16.0 Jane Street C header files +jane_rope -- String representation with cheap concatenation. +janestreet_cpuid -- A library for parsing CPU capabilities out of the `cpuid` instruction. +janestreet_csv -- Tools for working with CSVs on the command line +jasmin -- Compiler for High-Assurance and High-Speed Cryptography +javalib -- Javalib is a library written in OCaml with the aim to provide a high level representation of Java .class files +javascriptcore -- OCaml bindings to JavaScriptCore +jbuilder -- Fast, portable and opinionated build system +jekyll-format -- Jekyll post parsing library +jemalloc -- Bindings to jemalloc mallctl api +jext -- Js_of_ocaml tools to help handling web extension +jhupllib -- A collection of OCaml utilities used by the JHU PL lab +jingoo -- Template engine almost compatible with Jinja2(python template engine) +jose -- JOSE implementation for OCaml and ReasonML +js-build-tools -- Collection of tools to help building Jane Street Packages +js_of_ocaml 5.4.0 Compiler from OCaml bytecode to JavaScript +js_of_ocaml-camlp4 -- Compiler from OCaml bytecode to Javascript +js_of_ocaml-compiler 5.4.0 Compiler from OCaml bytecode to JavaScript +js_of_ocaml-lwt -- Compiler from OCaml bytecode to JavaScript +js_of_ocaml-ocamlbuild -- An ocamlbuild plugin to compile to JavaScript using js_of_ocaml +js_of_ocaml-ppx 5.4.0 Compiler from OCaml bytecode to JavaScript +js_of_ocaml-ppx_deriving_json -- Compiler from OCaml bytecode to JavaScript +js_of_ocaml-toplevel 5.4.0 Compiler from OCaml bytecode to JavaScript +js_of_ocaml-tyxml -- Compiler from OCaml bytecode to JavaScript +js_of_ocaml-webgpu -- Js_of_ocaml bindings for webgpu +js_of_ocaml-webidl -- Generate js_of_ocaml bindings from webidl definitions +js_of_ocaml_patches -- Additions to js_of_ocaml's standard library that are required by Jane Street libraries. +json-data-encoding 0.12.1 Type-safe encoding to and decoding from JSON +json-data-encoding-browser -- Type-safe encoding to and decoding from JSON (browser support) +json-data-encoding-bson 0.12.1 Type-safe encoding to and decoding from JSON (bson support) +json-derivers -- Common Derivers for Jsonm/Yjson +json-rpc -- JSON RPC +json-static -- JSON camlp4 syntax extension using json-wheel +json-wheel -- JSON parser and writer, with optional C-style comments +json_decoder -- +json_of_jsonm -- json_of_jsonm_lib is a JSON encoder and decoder library that converts text to and from a +jsonaf -- A library for parsing, manipulating, and serializing data structured as JSON +jsondiff -- JSON sensitive diffing +jsonm 1.0.2 Non-blocking streaming JSON codec for OCaml +jsonoo -- JSON library for Js_of_ocaml +jsonrpc -- Jsonrpc protocol implemenation +jsonxt -- Jsonxt - JSON parsers for files, strings and more +jsoo-react -- Bindings to ReactJS for js_of_ocaml, including JSX ppx +jsoo_broadcastchannel -- A wrapper in Js_of_ocaml to deal with BroadcastChannel +jsoo_storage -- A wrapper in Js_of_ocaml for the WebStorage API +jst-config v0.16.0 Compile-time configuration for Jane Street libraries +junit -- JUnit XML reports generation library +junit_alcotest -- JUnit XML reports generation for alcotest tests +junit_ounit -- JUnit XML reports generation for OUnit tests +jupyter -- An OCaml kernel for Jupyter notebook +jupyter-kernel -- Library to write jupyter kernels (interactive notebooks) +jwt -- Implementation of JWT in OCaml. +jwto -- JWT encoding, decoding and verification +kafka -- OCaml bindings for Kafka +kafka_async -- OCaml bindings for Kafka, Async bindings +kafka_lwt -- OCaml bindings for Kafka, Lwt bindings +kaputt -- Testing tool +kcas -- Software transactional memory based on lock-free multi-word compare-and-set +kcas_data -- Compositional lock-free data structures and primitives for communication and synchronization +kdl -- An implementation of the KDL document laguage +ke 0.6 Queue implementation +key-parsers -- Parsers for multiple key formats +kicadsch -- Library to read and convert Kicad Sch files +kind2 -- Multi-engine, parallel, SMT-based automatic model checker for safety properties of Lustre programs +kinetic-client -- Client API for Seagate's Kinetic drives +kittyimg -- An implementation of Kitty's terminal graphics protocol +kkmarkdown -- A safe markdown engine +kmt -- Framework for deriving Kleene Algebras with Tests (KAT) +knights_tour -- Solves the 'Knights Tour' and various 'Poyomino' puzzles +kqueue -- OCaml bindings for kqueue event notification interface +krb -- A library for using Kerberos for both Rpc and Tcp communication +kyotocabinet -- OCaml bindings for Kyoto Cabinet DBM +lab -- GitLab cli +lablgl -- Interface to OpenGL +lablgtk -- OCaml interface to GTK+ +lablgtk3 -- OCaml interface to GTK+3 +lablgtk3-extras -- A collection of additional tools and libraries to develop ocaml applications based on Lablgtk3 +lablgtk3-goocanvas2 -- OCaml interface to GTK+ GooCanvas library +lablgtk3-gtkspell3 -- OCaml interface to GTK+3 +lablgtk3-sourceview3 -- OCaml interface to GTK+ gtksourceview library +lablqml -- OCamlfind package and PPX extension to interface OCaml and QtQuick +labltk -- OCaml interface to Tcl/Tk +labrys -- A toy language based on LLVM that implements the System Fω type-system +lacaml -- Lacaml - OCaml-bindings to BLAS and LAPACK +ladspa -- Bindings for the LADSPA API which provides audio effects +lambda -- λ-calculus ocaml library +lambda-runtime -- A custom runtime for AWS Lambda written in OCaml +lambda-term -- Terminal manipulation library for OCaml +lambda_streams -- Lambda-based streaming library +lambda_streams_async -- Async helpers for lambda_streams +lambda_streams_lwt -- Lwt helpers for lambda_streams +lambdapi -- Proof assistant for the λΠ-calculus modulo rewriting +lambdasoup -- Easy functional HTML scraping and manipulation with CSS selectors +lame -- MP3 encoding library +landmarks -- A simple profiling library +landmarks-ppx -- Preprocessor instrumenting code using the landmarks library +lascar -- A library for manipulating Labeled Transition Systems in OCaml +lastfm -- The lastfm library is an implementation of the API used by the last.fm to keep count of played songs +lazy-trie -- Implementation of lazy prefix trees +lbfgs -- Bound-constrainted optimization in many variables +lbvs_consent -- Chemoinformatics software for consensus fingerprint queries +ldap -- Implementation of the Light Weight Directory Access Protocol +ldp -- Library to build LDP applications +ldp_curl -- Library to build LDP applications using Curl +ldp_js -- Library to build LDP applications in JS +ldp_tls -- Library to build LDP applications using TLS +leaflet -- Bindings for the Leaflet JavaScript library +ledgerwallet 0.3.0 Ledger wallet library for OCaml +ledgerwallet-tezos 0.3.0 Ledger wallet library for OCaml: Tezos app +ledit -- Line editor, a la rlwrap +lem -- Lem is a tool for lightweight executable mathematics +lemonade -- A monad library with bubbles +lemonade-sqlite -- A monadic interface to sqlite +lens -- Functional lenses +let-if -- A let%if syntax inspired by Rust's if let syntax +letsencrypt -- ACME implementation in OCaml +letsencrypt-app -- ACME implementation in OCaml +letsencrypt-dns -- DNS solver for ACME implementation in OCaml +letsencrypt-mirage -- ACME implementation in OCaml for MirageOS +letters -- Client library for sending emails over SMTP +leveldb -- OCaml bindings for Google's LevelDB library +lib_parsing -- Small library to help writing parsers +libabsolute 0.1 Libabsolute +libbinaryen -- Libbinaryen packaged for OCaml +libdash -- Bindings to the dash shell's parser +libevent -- OCaml wrapper for the libevent API +libirmin -- C bindings for irmin +libsail -- Sail is a language for describing the instruction semantics of processors +libssh -- Bindings to libssh +libsvm -- LIBSVM bindings for OCaml +libtensorflow -- TensorFlow library package +libtorch -- LibTorch library package +libudev -- Bindings to libudev for OCaml +libwasmer -- The official Wasmer library +libwasmtime -- The libwasmtime library package +libzipperposition -- Library for Zipperposition +lilac -- Get the value of any field in a YAML file as a string +lilv -- Bindings to lilv library for using LV2 audio plugins +line-up-words -- Align words in an intelligent way +line_oriented 1.3.0 Library to operate on files made of lines of text +linenoise -- Lightweight readline alternative +linkage -- easier plugin loading +links -- The Links Programming Language +links-mysql -- MySQL database driver for the Links Programming Language +links-postgresql -- Postgresql database driver for the Links Programming Language +links-sqlite3 -- SQLite database driver for the Links Programming Language +linksem -- A formalisation of the core ELF and DWARF file formats written in Lem +linol -- LSP server library +linol-lwt -- LSP server library (with Lwt for concurrency) +lintcstubs -- OCaml C stub static analyzer +lintcstubs-arity -- Generate headers for C bindings +lintcstubs-gen -- OCaml C stub wrapper generator +linwrap -- Wrapper on top of liblinear-tools +lipsum -- lipsum - self-contained tool for literate programming in tradition of NoWeb +liquid_interpreter -- The interpreter for Liquid +liquid_ml -- Shopify's Liquid templating language in OCaml +liquid_parser -- The parser for Liquid +liquid_std -- The Standard Libarary for Liquid +liquid_syntax -- The Syntax Definitions for Liquid +liquidsoap -- Swiss-army knife for multimedia streaming +liquidsoap-core -- Liquidsoap core library and binary +liquidsoap-daemon -- Daemonization scripts for liquidsoap +liquidsoap-js -- Liquidsoap language - javascript wrapper +liquidsoap-lang -- Liquidsoap language library +liquidsoap-libs -- Liquidosap standard library +liquidsoap-libs-extra -- Liquidosap standard library -- extra functionalities +liquidsoap-mode -- Liquidosap emacs mode +little_logger -- A tiny, little logger <3 +llama -- Language for Live Audio Module Arrangement +llama-cpp-ocaml -- Ctypes bindings to llama.cpp +llama_core -- Core types and operations for the Llama synthesizer library +llama_interactive -- Visualization and live interaction for Llama synthesizer library +llama_midi -- Minimal library for parsing and representing midi data +llopt -- Just a tiny LLVM-IR optimizer for testing stuff. +llvm -- The OCaml bindings distributed with LLVM +llvmgraph -- Ocamlgraph overlay for llvm +lmdb -- Bindings for LMDB, a fast in-file database with ACID transactions +lo -- Bindings for the lo library which provides functions for communicating with input controls using the OSC protocol +lockfree -- Lock-free data structures for multicore OCaml +logger-p5 -- Camlp5 syntax extension for logging +logical -- Logical is a minimalistic logic programming inspired by microKanren +logs 0.7.0 Logging infrastructure for OCaml +logs-async -- Jane Street Async logging with Logs +logs-async-reporter -- Logs reporter compatible with Async +logs-ppx -- PPX to cut down on boilerplate when using Logs +logs-syslog -- Logs reporter to syslog (UDP/TCP/TLS) +logtk -- Core types and algorithms for logic +lp -- LP and MIP modeling in OCaml +lp-glpk -- LP and MIP modeling in OCaml (GLPK interface) +lp-glpk-js -- LP and MIP modeling in OCaml (glpk.js interface) +lp-gurobi -- LP and MIP modeling in OCaml (Gurobi interface) +lpd -- A Line Printer Daemon (LPD) server library written entirely in OCaml. +lpi -- A REPL and library for a small dependently-typed language. +lreplay -- Executes a test suite and computes test coverage +lru 0.3.1 Scalable LRU caches +lru-cache -- A simple implementation of a LRU cache. +lru_cache -- An LRU Cache implementation. +lsp -- LSP protocol implementation in OCaml +lt-code -- OCaml implementation of a Luby Transform code +lua-ml -- An embeddable Lua 2.5 interpreter implemented in OCaml +lua_parser -- A Lua 5.2 Parser +lua_pattern -- Implementation of Lua patterns +lucid -- Super simple logging library for OCaml +lun -- Optics in OCaml +lustre-v6 -- The Lustre V6 Verimag compiler +lutils -- Tools and libs shared by Verimag/synchronous tools (lustre, lutin, rdbg) +lutin -- Lutin: modeling stochastic reactive systems +luv -- Binding to libuv: cross-platform asynchronous I/O +luv_unix -- Helpers for interfacing Luv and Unix +lwd -- Lightweight reactive documents +lwt 5.7.0 Promises and event-driven I/O +lwt-canceler 0.3 Cancellation synchronization object +lwt-dllist -- Mutable doubly-linked list with Lwt iterators +lwt-exit 1.0 An opinionated clean-exit and signal-handling library for Lwt programs +lwt-parallel -- Lwt-enabled Parallel Processing Library +lwt-pipe -- An alternative to `Lwt_stream` with interfaces for producers and consumers and a bounded internal buffer +lwt-pipeline -- Pipeline library for Lwt +lwt-watcher 0.2 One-to-many broadcast in Lwt +lwt_camlp4 -- Camlp4 syntax extension for Lwt (deprecated) +lwt_glib -- GLib integration for Lwt +lwt_log -- Lwt logging library (deprecated) +lwt_ppx 2.1.0 PPX syntax for Lwt, providing something similar to async/await from JavaScript +lwt_ppx_let -- Dummy package context for ppx_let tests +lwt_react -- Helpers for using React with Lwt +lwt_ssl 1.2.0 OpenSSL binding with concurrent I/O +lymp -- Use Python functions and objects from OCaml +lz4 -- Bindings to the LZ4 compression algorithm +lz4_chans -- LZ4-compressed binary channels +lzo -- Bindings to LZO - a portable lossless data compression library +m_tree -- An implementation of M-trees +macaddr 5.5.0 A library for manipulation of MAC address representations +macaddr-cstruct -- A library for manipulation of MAC address representations using Cstructs +macaddr-sexp -- A library for manipulation of MAC address representations using sexp +macaque -- DSL for SQL Queries in Caml +macaroons -- Macaroons for OCaml +mad -- Mad decoding library +magic -- Bindings for libmagic (to determine the type of files) +magic-mime 1.3.1 Map filenames to common MIME types +magic-trace -- Collects and displays high-resolution traces of what a process is doing +maildir -- This is a preliminary release of an OCaml library to access directories in the Maildir format. +make-random -- Helper to build a module similar to Stdlib.Random +malfunction -- Compiler back-end for functional languages, based on OCaml +man_in_the_middle_debugger -- Man-in-the-middle debugging library +mariadb -- OCaml bindings for MariaDB +markdown -- Markdown processor for Ocsigen +markup -- Error-recovering functional HTML5 and XML parsers and writers +markup-lwt -- Adapter between Markup.ml and Lwt +mastodon-archive-viewer -- View your Mastodon archive offline +matita -- An experimental, interactive theorem prover +matplotlib -- Plotting using Matplotlib through python +maxminddb -- Bindings to Maxmind.com's libmaxminddb library, like geoip2 +mbr-format -- A simple library for manipulating Master Boot Records +mc2 -- A mcsat-based SMT solver in pure OCaml +mccs -- MCCS (which stands for Multi Criteria CUDF Solver) is a CUDF problem solver developed at UNS during the European MANCOOSI project +md2mld -- Little cli tool to convert md files into mld files +mdx 2.3.1 Executable code blocks inside markdown files +mec -- Mec - Mini Elliptic Curve library +mechaml -- A functional web scraping library +mehari -- A cross-platform library for building Gemini servers +mehari-lwt-unix -- Mehari IO implementation using Lwt and Unix bindings +mehari-mirage -- Mehari IO implementation for MirageOS +mel -- Build system for Melange that defers to Dune for build orchestration +melange -- Toolchain to produce JS from Reason/OCaml +melange-compiler-libs -- Compiler libraries for Melange, a toolchain to produce JavaScript from OCaml +meldep -- Melange counterpart to `ocamldep` that understands Melange-specific constructs +mem_usage -- Cross-platform stats about memory usage +memcad -- The MemCAD analyzer +memcpy -- Safe and efficient copying between blocks of memory. +memgraph -- A small library to inspect memory representation of ocaml values +memgraph_kitty -- Display the representation of memory values in the Kitty terminal emulator +memprof-limits -- Memory limits, allocation limits, and thread cancellation +memtrace -- Streaming client for Memprof +memtrace-mirage -- Streaming client for Memprof using MirageOS API +memtrace_viewer -- Interactive memory profiler based on Memtrace +menhir 20230608 An LR(1) parser generator +menhirLib 20230608 Runtime support library for parsers generated by Menhir +menhirSdk 20230608 Compile-time library for auxiliary tools related to Menhir +merge-fmt -- Git mergetool leveraging code formatters +mergeable-vector -- Mergeable vector based on operational transformation +merlin -- Editor helper, provides completion, typing and source browsing in Vim and Emacs +merlin-extend -- A protocol to provide custom frontend to Merlin +merlin-lib 4.12-414 Merlin's libraries +merlin-of-pds -- Simple script that turns a pds.conf into a .merlin file +mesh -- Triangular mesh generation and manipulation +mesh-easymesh -- Triangular mesh generation with EasyMesh +mesh-graphics -- Triangular mesh representation using the graphics module +mesh-triangle -- Binding to the triangle mesh generator +metadata -- Read metadata from various file formats +metadb -- A database for storing and managing file metadata in JSON format +metapp -- Meta-preprocessor for OCaml +metaquot -- OCaml syntax extension for quoting code +metrics -- Metrics infrastructure for OCaml +metrics-influx -- Influx reporter for the Metrics library +metrics-lwt -- Lwt backend for the Metrics library +metrics-mirage -- Mirage backend for the Metrics library +metrics-rusage -- Resource usage (getrusage) sources for the Metrics library +metrics-unix -- Unix backend for the Metrics library +mew -- Modal editing witch +mew_vi -- Modal editing witch, VI interpreter +mikmatch -- OCaml syntax extension for regexps +mimic -- A simple protocol dispatcher +mimic-happy-eyeballs -- A happy-eyeballs integration into mimic +mindstorm -- Drive Lego Mindstorms bricks from OCaml +mindstorm-lwt -- Drive Lego Mindstorms bricks from OCaml (LWT version) +minicaml -- A simple, didactical, purely functional programming language +minicli 5.0.2 Minimalist library for command line parsing +minilight -- Minimal global illumination renderer. +minima-theme -- OCaml port of the Jekyll Minima theme +minimal -- Minima.l, a minimal Lisp +minios-xen -- A minimal OS for running under the Xen hypervisor +minisat -- Bindings to the SAT solver Minisat, with the solver included. +minivpt -- Minimalist vantage point tree implementation in OCaml. +mirage -- The MirageOS library operating system +mirage-block -- Block signatures and implementations for MirageOS +mirage-block-ccm -- AES-CCM encrypted Mirage Mirage_types.BLOCK storage +mirage-block-combinators -- Block signatures and implementations for MirageOS using Lwt +mirage-block-lwt -- Block signatures and implementations for MirageOS using Lwt +mirage-block-partition -- Mirage block device partitioning +mirage-block-ramdisk -- In-memory BLOCK device for MirageOS +mirage-block-solo5 -- Solo5 implementation of MirageOS block interface +mirage-block-unix -- MirageOS disk block driver for Unix +mirage-block-xen -- MirageOS block driver for Xen that implements the blkfront/back protocol +mirage-bootvar-solo5 -- Solo5 implementation of MirageOS Bootvar interface +mirage-bootvar-unix -- Unix implementation of MirageOS Bootvar interface +mirage-bootvar-xen -- Handle boot-time arguments for Xen platform +mirage-btrees -- An implementation of BTrees designed for use with MirageOS's BLOCK interface +mirage-channel -- Buffered channels for MirageOS FLOW types +mirage-channel-lwt -- Buffered Lwt channels for MirageOS FLOW types +mirage-clock 4.2.0 Libraries and module types for portable clocks +mirage-clock-freestanding -- Paravirtual implementation of the MirageOS Clock interface +mirage-clock-lwt -- Lwt-based implementation of the MirageOS Clock interface +mirage-clock-solo5 -- Paravirtual implementation of the MirageOS Clock interface +mirage-clock-unix -- Unix-based implementation for the MirageOS Clock interface +mirage-clock-xen -- A Mirage-compatible Clock library for Xen +mirage-console -- Implementations of Mirage console devices +mirage-console-lwt -- Implementation of Mirage consoles using Lwt +mirage-console-solo5 -- Solo5 implementation of MirageOS console interface +mirage-console-unix -- Implementation of Mirage consoles for Unix +mirage-console-xen -- Implementation of Mirage console for Xen +mirage-console-xen-backend -- Implementation of Mirage console backend for Xen +mirage-console-xen-proto -- Implementation of Mirage console protocol for Xen +mirage-crypto 0.11.2 Simple symmetric cryptography for the modern age +mirage-crypto-ec 0.11.2 Elliptic Curve Cryptography with primitives taken from Fiat +mirage-crypto-entropy -- Entropy source for MirageOS unikernels +mirage-crypto-pk 0.11.2 Simple public-key cryptography for the modern age +mirage-crypto-rng 0.11.2 A cryptographically secure PRNG +mirage-crypto-rng-async -- Feed the entropy source in an Async-friendly way +mirage-crypto-rng-lwt 0.11.2 A cryptographically secure PRNG +mirage-crypto-rng-mirage -- Entropy collection for a cryptographically secure PRNG +mirage-device -- Abstract devices for MirageOS +mirage-entropy -- Entropy source for MirageOS unikernels +mirage-flow -- Flow implementations and combinators for MirageOS +mirage-flow-combinators -- Flow implementations and combinators for MirageOS specialized to lwt +mirage-flow-lwt -- Flow implementations and combinators for MirageOS specialized to lwt +mirage-flow-rawlink -- Expose rawlink interfaces as MirageOS flows +mirage-flow-unix -- Flow implementations and combinators for MirageOS on Unix +mirage-fs -- MirageOS signatures for filesystem devices +mirage-fs-lwt -- MirageOS signatures for filesystem devices using Lwt +mirage-fs-mem -- In-memory file system for for MirageOS +mirage-fs-unix -- Passthrough filesystem for MirageOS on Unix +mirage-kv -- MirageOS signatures for key/value devices +mirage-kv-lwt -- MirageOS signatures for key/value devices +mirage-kv-mem -- In-memory key value store for MirageOS +mirage-kv-unix -- Key-value store for MirageOS backed by Unix filesystem +mirage-logs -- A reporter for the Logs library that writes log messages to stderr, using a Mirage `CLOCK` to add timestamps +mirage-monitoring -- Monitoring of MirageOS unikernels +mirage-nat -- Mirage-nat is a library for network address translation to be used with MirageOS +mirage-net -- Network signatures for MirageOS +mirage-net-fd -- MirageOS network interfaces using raw sockets +mirage-net-flow -- Build MirageOS network interfaces on top of MirageOS flows +mirage-net-lwt -- Network signatures for MirageOS +mirage-net-solo5 -- Solo5 implementation of MirageOS network interface +mirage-net-unix -- Unix implementation of the Mirage_net_lwt interface +mirage-net-xen -- Network device for reading and writing Ethernet frames via then Xen netfront/netback protocol +mirage-no-solo5 -- Virtual package conflicting with mirage-solo5 +mirage-no-xen -- Virtual package conflicting with mirage-xen +mirage-os-shim -- Portable shim for MirageOS OS API +mirage-profile -- Collect runtime profiling information in CTF format +mirage-profile-unix -- Collect runtime profiling information in CTF format +mirage-protocols -- MirageOS signatures for network protocols +mirage-protocols-lwt -- MirageOS signatures for network protocols +mirage-qubes -- Implementations of various Qubes protocols for MirageOS +mirage-qubes-ipv4 -- Implementations of IPv4 stack which reads configuration from QubesDB for MirageOS +mirage-random -- Random-related devices for MirageOS +mirage-random-stdlib -- Random device implementation using the OCaml stdlib +mirage-random-test -- Stub random device implementation for testing +mirage-runtime -- The base MirageOS runtime library, part of every MirageOS unikernel +mirage-seal -- Serve static files over HTTPS, using Mirage+ocaml-TLS. +mirage-solo5 -- Solo5 core platform libraries for MirageOS +mirage-stack -- MirageOS signatures for network stacks +mirage-stack-lwt -- MirageOS signatures for network stacks +mirage-tc -- MirageOS type-classes +mirage-time -- Time operations for MirageOS +mirage-time-lwt -- Time operations for MirageOS with Lwt +mirage-time-unix -- Time operations for MirageOS on Unix +mirage-types -- Module type definitions for MirageOS applications +mirage-types-lwt -- Lwt module type definitions for MirageOS applications +mirage-unix -- Unix core platform libraries for MirageOS +mirage-vnetif -- Virtual network interface and software switch for Mirage +mirage-vnetif-stack -- Vnetif implementation of mirage-stack for Mirage TCP/IP +mirage-xen -- Xen core platform libraries for MirageOS +mirage-xen-minios -- Xen MiniOS guest operating system library +mirage-xen-posix -- MirageOS library for posix headers +misuja -- A library to drive the MIDI system of the Jack Audio Connection Kit. +mixture -- The Mixture package is a mixin library for the module system +mkaudio -- CLI program for generating audio files +mkocaml -- Tool to generate OCaml projects +mlbdd -- An OCaml library for Binary Decision Diagrams (BDDs) +mlcuddidl -- OCaml interface to the CUDD BDD library +mlfenv -- OCaml C bindings for fenv(3) +mlgmpidl 1.2.15 OCaml interface to the GMP library +mlmpfr -- OCaml C bindings for MPFR-4.1.1 +mlt_parser -- Parsing of top-expect files +mm -- The mm library contains high-level APIs to create and manipulate multimedia streams (audio, video, MIDI) +mmap -- File mapping functionality +mmdb -- Binding to the MaxMind DB library for GeoIP lookups +mmseg -- This is a transition package, mmseg is now named wseg. Use the wseg package instead +mnd -- A small monads library +mock -- Configurable functions to test impure code +mock-ounit -- OUnit wrapper for OCaml mock +modular-arithmetic -- A library for operations on integers modulo some integer (the modulus) +module-graph -- The module-graph tool generates a graph of dependencies between OCaml modules using compiled object files +molenc -- Molecular encoder/featurizer using rdkit and OCaml +monaco_jsoo -- JSOO interface for Monaco-editor +monadlib -- A starter library for monads, with transformers and applicatives. +monads -- A missing monad library +monocypher -- OCaml bindings to the Monocypher cryptographic library +monolith -- A framework for testing a library using afl-fuzz +monomorphic -- A small library used to shadow polymorphic operators (and functions) contained in the stdlib +monorobot -- Notification bot for monorepos +moonpool -- Pools of threads supported by a pool of domains +morbig -- A trustworthy parser for POSIX shell +more-ocaml -- Support code for the book 'More OCaml' +morsmall -- A concise AST for POSIX shell +mosquitto -- mosquitto +moss -- A client for the MOSS plagiarism detection service +mparser -- A simple monadic parser combinator library +mparser-pcre -- MParser plugin: PCRE-based regular expressions +mparser-re -- MParser plugin: RE-based regular expressions +mperf -- Bindings to Linux perf's metrics +mpg123 -- MP3 decoding library +mpi -- OCaml binding to the Message Passing Interface (MPI) +mpp -- MPP is both a preprocessor and a meta preprocessor +mpris -- Client library for the MPRIS D-Bus media player interface +mpris-clients -- Client implementations of the MPRIS D-Bus media player interface +mrmime -- Mr. MIME +msat -- Library containing a SAT solver that can be parametrized by a theory +msat-bin -- SAT solver binary based on the msat library +msgpack -- Msgpack library for OCaml +msgpck -- Fast MessagePack (http://msgpack.org) library +msgpck-repr -- Fast MessagePack (http://msgpack.org) library -- ocplib-json-typed interface +mssql -- Async SQL Server client using FreeTDS +mstruct -- A mutable interface to Cstruct buffers +mtime 1.4.0 Monotonic wall-clock time for OCaml +mtl -- A Monad Transformers Library for OCaml +mugen -- Universe levels and universe polymorphism +mula -- ML's Universal Levenshtein Automata library +multibase -- Self-describing base encodings +multicodec -- Canonical codec of values and types used by various multiformats +multicore-magic -- Low-level multicore utilities for OCaml +multihash -- Self-describing Hash Functions +multihash-digestif -- Self-describing Hash Functions using Digestif +multipart-form-data -- Parser for multipart/form-data (RFC2388) +multipart_form 0.5.0 Multipart-form: RFC2183, RFC2388 & RFC7578 +multipart_form-cohttp-lwt -- Multipart-form for CoHTTP +multipart_form-lwt 0.5.0 Multipart-form: RFC2183, RFC2388 & RFC7578 +murmur3 -- Bindings for murmur3 hash implementation +mustache -- Mustache logic-less templates in OCaml +mutaml -- A mutation tester for OCaml +mutf8 -- The Modified UTF-8 encoding used by Java and related systems +mvar -- Threadsafe mutable variables for Unix threads +mwt -- Mediumweight thread library for OCaml via Lwt +mybuild -- Collection of ocamlbuild plugins (extprot, atdgen, ragel, etc) and utility to generate version from VCS +mysql -- Bindings to C client library for interacting with Mysql/MariaDB/Percona databases +mysql8 -- OCaml interface for mysql-connector-c +mysql_protocol -- OCaml implementation of the native MySQL/MariaDB Protocol with the Bitstring library +n_ary -- A library for N-ary datatypes and operations. +naboris -- Simple http server +nacc -- Not Another Compiler Compiler +namespaces -- Turn directories into OCaml modules (deprecated) +nanoid -- Nano ID implementation for OCaml +nanosvg -- Simple SVG parser and rasterizer +nanosvg_text -- Text rendering for NanoSVG text nodes +nbd -- Network Block Device (NBD) protocol implementation +nbd-tool -- Network Block Device (NBD) protocol implementation +nbd-unix -- Network Block Device (NBD) protocol implementation +netchannel -- Network device for reading and writing Ethernet frames via then Xen netfront/netback protocol +netlink -- Bindings to the Netlink Protocol Library Suite (libnl) +netsnmp -- An interface to the Net-SNMP client library +nice_parser -- Nice parsers without the boilerplate +nlopt -- OCaml bindings to the NLOpt optimization library +nlopt-ocaml -- This is a transition package, nlopt-ocaml is now named nlopt +nlp -- Natural Language Processing tools for OCaml +nmea -- Nmea parser +noCanren -- Translator from subset of OCaml to OCanren +nocoiner -- A Commitment Scheme library for Coin Flipping/Tossing algorithms and sort +nocrypto -- Simpler crypto +node_of_ocaml -- An OCaml ppx to require node modules +non_empty_list -- A non empty list library for OCaml +nonstd -- Non-standard mini-library +nosetup -- An `.ocamlinit` helper to `#require` packages in an OCaml toplevels +not-ocamlfind -- A small frontend for ocamlfind that adds a few useful commands +note -- Declarative events and signals for OCaml +nottui -- UI toolkit for the terminal built on top of Notty and Lwd +nottui-lwt -- Run Nottui UIs in Lwt +nottui-pretty -- A pretty-printer based on PPrint rendering UIs +notty -- Declaring terminals +notty_async -- An Async driver for Notty +np -- Fundamental scientific computing with Numpy for OCaml +nproc -- Process pool implementation for OCaml. +npy -- Numpy npy file format reading/writing. +nsq -- A client library for the NSQ messaging platform +num 1.4 The legacy Num library for arbitrary-precision integer and rational arithmetic +numalib -- Interface to Linux NUMA API +numeric_string -- A comparison function for strings that sorts numeric fragments of strings according to their numeric value, so that e.g. "abc2" < "abc10". +nuscr -- A tool to manipulate and validate Scribble-style multiparty protocols +OCADml -- Types and functions for building CAD packages in OCaml +OCanren -- Implementation of miniKanren relational (logic) EDSL +OCanren-ppx -- Implementation of miniKanren relational (logic) EDSL: PPX extensions +OSCADml -- OCaml DSL for 3D solid modelling in OpenSCAD +oasis -- Tooling for building OCaml libraries and applications +oasis2debian -- Create and maintain Debian package for an OASIS package +oasis2opam -- Tool to convert OASIS metadata to OPAM package descriptions +obandit -- Ocaml Multi-Armed Bandits +obelisk -- Pretty-printing for Menhir files +objsize -- Small library to compute sizes of OCaml heap values +obuild -- simple package build system for OCaml +obuilder -- Run build scripts for CI +obuilder-spec -- Build specification format +obus -- Pure Ocaml implementation of the D-Bus protocol +obytelib -- OCaml bytecode library tools to read, write and evaluate OCaml bytecode files +oc45 -- Pure OCaml implementation of the C4.5 algorithm. +ocal -- An improved Unix `cal` utility +ocaml 4.14.1 The OCaml compiler (virtual package) +ocaml-base-compiler 4.14.1 Official release 4.14.1 +ocaml-basics -- Implements common functionnal patterns / abstractions +ocaml-buddy -- Bindings for the Buddy BDD library. +ocaml-canvas -- The OCaml-Canvas library +ocaml-compiler-libs v0.12.4 OCaml compiler libraries repackaged +ocaml-config 2 OCaml Switch Configuration +ocaml-embed-file -- Files contents as module constants +ocaml-expat -- Write XML-Parsers using the SAX method +ocaml-freestanding -- Freestanding OCaml runtime +ocaml-http -- Library freely inspired from Perl's HTTP::Daemon module +ocaml-in-python -- Effortless Python bindings for OCaml modules +ocaml-inifiles -- An ini file parser +ocaml-lsp-server -- LSP Server for OCaml +ocaml-lua -- Lua bindings +ocaml-makefile -- Generic Makefile for building OCaml projects +ocaml-manual -- The OCaml system manual +ocaml-markdown -- This is a transition package, ocaml-markdown is now named markdown. +ocaml-migrate-parsetree 2.4.0 Convert OCaml parsetrees between different versions +ocaml-monadic -- A PPX extension to provide an OCaml-friendly monadic syntax +ocaml-options-vanilla 1 Ensure that OCaml is compiled with no special options enabled +ocaml-print-intf -- Display human-readable OCaml interface from a compiled .cmi +ocaml-probes -- USDT probes for OCaml: command line tool +ocaml-protoc -- Protobuf compiler for OCaml +ocaml-protoc-plugin -- Plugin for protoc protobuf compiler to generate ocaml definitions from a .proto file +ocaml-protoc-yojson -- JSON Runtime based on Yojson library for `ocaml-protoc` generated code +ocaml-r -- Objective Caml bindings for the R interpreter +ocaml-sat-solvers -- An abstraction layer for integrating SAT Solvers into OCaml +ocaml-secondary-compiler -- OCaml 4.08.1 Secondary Switch Compiler +ocaml-solo5 -- Freestanding OCaml compiler +ocaml-src -- Compiler sources +ocaml-syntax-shims 1.0.0 Backport new syntax to older OCaml versions +ocaml-system -- The OCaml compiler (system version, from outside of opam) +ocaml-systemd -- OCaml module for native access to the systemd facilities +ocaml-top -- The OCaml interactive editor for education +ocaml-twt -- The Whitespace Thing, a layout preprocessor for OCaml code +ocaml-vdom -- This is a transition package, ocaml-vdom is now named vdom. Use the vdom package instead +ocaml-version 3.6.2 Manipulate, parse and generate OCaml compiler version strings +ocaml-xdg-basedir -- This is a transition package, ocaml-xdg-basedir is now named xdg-basedir. Use the xdg-basedir package instead +ocaml_db_model -- An Ocaml library and utility for creating modules out of thin air that describe database tables and types, with functions for running queries and commands. Aka database modelling +ocaml_intrinsics v0.16.0 Intrinsics +ocaml_pgsql_model -- An Ocaml library and utility for creating modules out of thin air that describe database tables and types, with functions for running queries and commands; Aka database modelling +ocaml_plugin -- Automatically build and dynlink OCaml source files +ocamlbrowser -- OCamlBrowser Library Explorer +ocamlbuild 0.14.2 OCamlbuild is a build system with builtin rules to easily build most OCaml projects +ocamlbuild-atdgen -- Atdgen plugin for OCamlbuild +ocamlbuild-pkg -- An ocamlbuild plugin that helps packaging softwares. +ocamlbuild-protoc -- ocaml-protoc plugin for Ocamlbuild +ocamlc-loc 3.11.1 Parse ocaml compiler output into structured form +ocamlclean -- Reduce size of OCaml bytecode files by dead-code removing +ocamlcodoc -- Extract test code from doc-comments +ocamldap -- Transitional package for ldap (renaming) +ocamldiff -- OCamldiff is a small OCaml library providing functions to parse and display diff results +ocamldot -- Parsing and printing graphviz files in OCaml +ocamldsort -- Sorts a set of OCaml source files according to their dependencies +ocamlfind 1.9.6 A library manager for OCaml +ocamlfind-lint -- Simple tool performing checks on installed findlib META files +ocamlfind-secondary -- Adds support for ocaml-secondary-compiler to ocamlfind +ocamlformat 0.26.1 Auto-formatter for OCaml code +ocamlformat-lib 0.26.1 OCaml Code Formatter +ocamlformat-rpc -- Auto-formatter for OCaml code (RPC mode) +ocamlformat-rpc-lib 0.26.1 Auto-formatter for OCaml code (RPC mode) +ocamlfuse -- OCaml bindings for FUSE (Filesystem in UserSpacE) +ocamlgraph 2.1.0 A generic graph library for OCaml +ocamlify -- Include files in OCaml code +ocamline -- Command line interface for user input +ocamlmod -- Generate OCaml modules from source files +ocamlnet -- Internet protocols (HTTP, CGI, e-mail etc.) and helper data structures +ocamlog -- Simple Logger for OCaml +ocamlregextkit -- A regular expression toolkit for OCaml +ocamlrss -- Library providing functions to parse and print RSS 2.0 files +ocamlscript -- Tool which compiles OCaml scripts into native code +ocamlsdl -- Interface between OCaml and SDL +ocamlsdl2 -- Interface to the SDL2 library +ocamlsdl2-image -- Interface to the SDL2_image library +ocamlsdl2-ttf -- Interface to the SDL2_ttf library +ocamlwc -- Count lines in OCaml source code +ocamlyices -- Yices SMT solver binding +ocapic -- Development tools to run OCaml programs on PIC microcontrollers +ocb -- SVG badge generator +ocb-stubblr -- OCamlbuild plugin for C stubs +ocephes -- Bindings to special math functions from the Cephes library +ocf -- OCaml library to read and write configuration files in JSON syntax +ocf_ppx -- Preprocessor for Ocf library +ockt -- OCaml library for parsing ckt files into hashtables +oclock -- Oclock: Precise POSIX clock for OCaml +ocluster -- Distribute build jobs to workers +ocluster-api -- Cap'n Proto API for OCluster +ocluster-worker -- OCluster library for defining workers +ocolor -- Print with style in your terminal using Format's semantic tags +ocp-browser -- Console browser for the documentation of installed OCaml libraries +ocp-indent 1.8.1 A simple tool to indent OCaml programs +ocp-indent-nlfork -- ocp-indent library, "newline tokens" fork +ocp-index -- Lightweight completion and documentation browsing for OCaml libraries +ocp-ocamlres 0.4 Manipulation, injection and extraction of embedded resources +ocp-pack-split -- ocp-pack and ocp-split +ocp-reloc -- Relocation of OCaml bytecode executables +ocp-search -- The ocp-search tool to index/search source packages +ocp_reveal -- OCaml bindings for Reveal.js, an HTML presentation framework +ocplib-endian 1.2 Optimised functions to read and write int16/32/64 from strings and bigarrays +ocplib-json-typed -- Type-aware JSON and JSON schema utilities +ocplib-json-typed-browser -- Json_repr interface over JavaScript's objects +ocplib-json-typed-bson -- A Json_repr compatible implementation of the JSON compatible subset of BSON +ocplib-simplex 0.5 A library implementing a simplex algorithm, in a functional style, for solving systems of linear inequalities and optimizing linear objective functions +ocplib_stuff -- Basic stuff used by some OCP libraries and tools +ocsfml -- Binding to the C++ SFML gaming library. +ocsigen-i18n -- I18n made easy for web sites written with eliom +ocsigen-ppx-rpc -- This PPX adds a syntax for RPCs for Eliom and Ocsigen Start +ocsigen-start -- An Eliom application skeleton ready to use to build your own application with users, (pre)registration, notifications, etc +ocsigen-toolkit -- Reusable UI components for Eliom applications (client only, or client-server) +ocsigenserver -- A full-featured and extensible Web server +ocsipersist -- Persistent key/value storage (for Ocsigen) using multiple backends +ocsipersist-dbm -- Persistent key/value storage (for Ocsigen) using DBM +ocsipersist-lib -- Persistent key/value storage (for Ocsigen) - support library +ocsipersist-pgsql -- Persistent key/value storage (for Ocsigen) using PostgreSQL +ocsipersist-sqlite -- Persistent key/value storage (for Ocsigen) using SQLite +octavius -- Ocamldoc comment syntax parser +octez 18.0 Main virtual package for Octez, an implementation of Tezos +octez-accuser-Proxford 18.0 Tezos/Protocol: accuser binary +octez-accuser-PtKathma -- Tezos/Protocol: accuser binary +octez-accuser-PtLimaPt -- Tezos/Protocol: accuser binary +octez-accuser-PtMumbai -- Tezos/Protocol: accuser binary +octez-accuser-PtNairob 18.0 Tezos/Protocol: accuser binary +octez-alcotezt 18.0 Provide the interface of Alcotest for Octez, but with Tezt as backend +octez-baker-Proxford 18.0 Tezos/Protocol: baker binary +octez-baker-PtKathma -- Tezos/Protocol: baker binary +octez-baker-PtLimaPt -- Tezos/Protocol: baker binary +octez-baker-PtMumbai -- Tezos/Protocol: baker binary +octez-baker-PtNairob 18.0 Tezos/Protocol: baker binary +octez-bls12-381-hash -- Implementation of some cryptographic hash primitives using the scalar field of BLS12-381 +octez-bls12-381-polynomial -- Polynomials over BLS12-381 finite field - Temporary vendored version of Octez +octez-bls12-381-signature -- Implementation of BLS signatures for the pairing-friendly curve BLS12-381 +octez-client 18.0 Tezos: `octez-client` binary +octez-codec 18.0 Tezos: `octez-codec` binary to encode and decode values +octez-crawler 18.0 Octez: library to crawl blocks of the L1 chain +octez-dac-client 18.0 Tezos: `octez-dac-client` binary +octez-dac-node 18.0 Tezos: `octez-dac-node` binary +octez-distributed-internal 18.0 Fork of distributed. Use for Octez only +octez-distributed-lwt-internal 18.0 Fork of distributed-lwt. Use for Octez only +octez-injector 18.0 Octez: library for building injectors +octez-l2-libs 18.0 Octez layer2 libraries +octez-libs 18.0 A package that contains multiple base libraries used by the Octez suite +octez-mec -- Modular Experimental Cryptography library +octez-node 18.0 Tezos: `octez-node` binary +octez-node-config 18.0 Octez: `octez-node-config` library +octez-plompiler -- Library to write arithmetic circuits for Plonk +octez-plonk -- Plonk zero-knowledge proving system +octez-polynomial -- Polynomials over finite fields +octez-proto-libs 18.0 Octez protocol libraries +octez-protocol-000-Ps9mPmXa-libs 18.0 Octez protocol 000-Ps9mPmXa libraries +octez-protocol-001-PtCJ7pwo-libs 18.0 Octez protocol 001-PtCJ7pwo libraries +octez-protocol-002-PsYLVpVv-libs 18.0 Octez protocol 002-PsYLVpVv libraries +octez-protocol-003-PsddFKi3-libs 18.0 Octez protocol 003-PsddFKi3 libraries +octez-protocol-004-Pt24m4xi-libs 18.0 Octez protocol 004-Pt24m4xi libraries +octez-protocol-005-PsBabyM1-libs 18.0 Octez protocol 005-PsBabyM1 libraries +octez-protocol-006-PsCARTHA-libs 18.0 Octez protocol 006-PsCARTHA libraries +octez-protocol-007-PsDELPH1-libs 18.0 Octez protocol 007-PsDELPH1 libraries +octez-protocol-008-PtEdo2Zk-libs 18.0 Octez protocol 008-PtEdo2Zk libraries +octez-protocol-009-PsFLoren-libs 18.0 Octez protocol 009-PsFLoren libraries +octez-protocol-010-PtGRANAD-libs 18.0 Octez protocol 010-PtGRANAD libraries +octez-protocol-011-PtHangz2-libs 18.0 Octez protocol 011-PtHangz2 libraries +octez-protocol-012-Psithaca-libs 18.0 Octez protocol 012-Psithaca libraries +octez-protocol-013-PtJakart-libs 18.0 Octez protocol 013-PtJakart libraries +octez-protocol-014-PtKathma-libs 18.0 Octez protocol 014-PtKathma libraries +octez-protocol-015-PtLimaPt-libs 18.0 Octez protocol 015-PtLimaPt libraries +octez-protocol-016-PtMumbai-libs 18.0 Octez protocol 016-PtMumbai libraries +octez-protocol-017-PtNairob-libs 18.0 Octez protocol 017-PtNairob libraries +octez-protocol-018-Proxford-libs 18.0 Octez protocol 018-Proxford libraries +octez-protocol-alpha-libs 18.0 Octez protocol alpha libraries +octez-protocol-compiler 18.0 Tezos: economic-protocol compiler +octez-proxy-server 18.0 Octez: `octez-proxy-server` binary +octez-shell-libs 18.0 Octez shell libraries +octez-signer 18.0 Tezos: `octez-signer` binary +octez-smart-rollup-client-Proxford 18.0 Tezos/Protocol: Smart rollup client +octez-smart-rollup-client-PtMumbai -- Tezos/Protocol: Smart rollup client +octez-smart-rollup-client-PtNairob 18.0 Tezos/Protocol: Smart rollup client +octez-smart-rollup-node -- Octez: library for Smart Rollup node +octez-smart-rollup-node-lib 18.0 Octez: library for Smart Rollup node +octez-smart-rollup-node-Proxford 18.0 Tezos/Protocol: protocol specific Smart rollup node +octez-smart-rollup-node-PtMumbai -- Tezos/Protocol: protocol specific Smart rollup node +octez-smart-rollup-node-PtNairob 18.0 Tezos/Protocol: protocol specific Smart rollup node +octez-smart-rollup-wasm-benchmark-lib -- Smart Rollup WASM benchmark library +octez-smart-rollup-wasm-debugger 18.0 Tezos: Debugger for the smart rollups’ WASM kernels +octez-tx-rollup-client-PtKathma -- Tezos/Protocol: `octez-tx-rollup-client-alpha` client binary +octez-tx-rollup-client-PtLimaPt -- Tezos/Protocol: `octez-tx-rollup-client-alpha` client binary +octez-tx-rollup-node-PtKathma -- Tezos/Protocol: Transaction Rollup node binary +octez-tx-rollup-node-PtLimaPt -- Tezos/Protocol: Transaction Rollup node binary +octez-validator -- Tezos: `octez-validator` binary for external validation of blocks +octez-version 18.0 Tezos: version value generated from Git +ocurl -- Bindings to libcurl +ocveralls -- Generate JSON for http://coveralls.io from bisect code coverage data (deprecated). +odate -- Date & Duration Library +odbc -- Interface to various ODBC drivers +odds -- Dice formula library +odep -- Dependency graphs for OCaml modules, libraries and packages +odepack -- Binding to ODEPACK +odig 0.0.9 Lookup documentation of installed OCaml packages +odnnr -- Regressor using a Deep Neural Network +odoc 2.3.0 OCaml Documentation Generator +odoc-depgraph -- Custom OCamldoc generator to insert clickable dependency graphs in generated html page +odoc-parser 2.3.0 Parser for ocaml documentation comments +of_json -- A friendly applicative interface for Jsonaf. +offheap -- Copies OCaml objects out of the OCaml heap +ofx -- OCaml parser for OFX files +ogg -- Bindings to libogg +ogre -- Open Generic REpresentation NoSQL Database +ojo -- CLI tool to watch for change in the specified files +ojs -- Runtime Library for gen_js_api generated libraries +ojs-base -- Base library for developing OCaml web apps based on websockets and js_of_ocaml +ojs_base -- Base library for developing OCaml web apps based on websockets and js_of_ocaml +ojs_base_all -- Virtual package to install all ojs_base packages +ojs_base_ppx -- PPx extension for the Ojs_base library +ojs_ed -- Using file editor in ojs_base applications, common part +ojs_filetree -- Using filetrees in ojs_base applications, common part +ojs_list -- Using lists in ojs_base applications, common part +olinq -- LINQ inspired queries on in-memory data +ollvm -- ollvm library offers an interface to manipulate LLVM IR in pure OCaml. +ollvm-tapir -- a fork of ollvm with added LLVM-Tapir support +olmi -- Olmi provide functor to generate monadic combinators with a minimal interface +omake -- Build system designed for scalability and portability +omd -- A Markdown frontend in pure OCaml +ometrics -- OCaml analysis in a merge request changes +omigrate -- Database migrations for Reason and OCaml +oml -- Math Library +omlr -- Multiple Linear Regression model +omod -- Lookup and load installed OCaml modules +omtl -- OCaml Minimalist Testing Library +oneffs -- One-file filesystem is a filesystem for storing a single unnamed file +oniguruma -- Bindings to the Oniguruma regular expression library +oolc -- An Ocaml implementation of Open Location Code. +opaca -- A friendly OCaml project scaffolding tool +opal -- Self-contained monadic parser combinators for OCaml +opam-0install -- Opam solver using 0install backend +opam-0install-cudf -- Opam solver using 0install backend using the CUDF interface +opam-bin -- The opam-bin tool is a simple framework to use `opam` with binary packages +opam-build -- An opam plugin to build projects +opam-bundle -- A tool that creates stand-alone source bundles from opam packages +opam-check-npm-deps -- An opam plugin to check for npm depexts inside the node_modules folder +opam-client -- Client library for opam 2.2 +opam-compiler -- Plugin to create switches using custom compilers +opam-core 2.1.5 Core library for opam 2.1 +opam-custom-install -- An opam plugin to install a package using a custom command +opam-depext -- Install OS distribution packages +opam-devel -- Bootstrapped development binary for opam 2.2 +opam-dune-lint -- Ensure dune and opam dependencies are consistent +opam-ed -- Command-line edition tool for handling the opam file syntax +opam-file-format -- Parser and printer for the opam file syntax +opam-format -- Format library for opam 2.2 +opam-graph -- Graphing dependencies of opam packages +opam-grep -- An opam plugin that greps anything in the sources of every opam packages +opam-installer -- Installation of files to a prefix, following opam conventions +opam-lib -- The OPAM library +opam-lock -- Locking of development package definition dependency versions +opam-monorepo -- Assemble and manage fully vendored Dune repositories +opam-package-upgrade -- Upgrades opam package definition files to the latest format +opam-publish -- A tool to ease contributions to opam repositories +opam-repository -- Repository library for opam 2.2 +opam-solver -- Solver library for opam 2.2 +opam-spin -- Opam plugin for Spin, the OCaml project generator +opam-state -- State library for opam 2.2 +opam-test -- An opam plugin to test projects +opam_bin_lib -- The opam-bin tool is a simple framework to use `opam` with binary packages +opamconfig -- Virtual package owning parameters of opam installation. +opamfu -- Functions over OPAM Universes +opasswd -- OCaml bindings to the glibc passwd file and shadow password file interface +open -- Conveniently open files such as PDFs in their default applications. +openai -- OCaml OpenAI binding +openapi -- Openapi documentation generation for Opium +openapi_router -- Http server agnostic Openapi documentation generation +opencc -- Bindings for OpenCC (v1) - Open Chinese Convert +opencc0 -- Bindings for OpenCC (v0) - Open Chinese Convert +opencc1 -- Bindings for OpenCC (v1) - Open Chinese Convert +opencc1_1 -- Bindings for OpenCC (v1.1) - Open Chinese Convert +openQASM -- Parser for OpenQASM (Open Quantum Assembly Language) +openstellina -- A http client for Stellina smart telescope by Vaonis +opentelemetry -- Instrumentation for https://opentelemetry.io +opentelemetry-client-cohttp-lwt -- Collector client for opentelemetry, using cohttp + lwt +opentelemetry-client-ocurl -- Collector client for opentelemetry, using http + ezcurl +opentelemetry-cohttp-lwt -- Opentelemetry tracing for Cohttp HTTP servers +opentelemetry-lwt -- Lwt-compatible instrumentation for https://opentelemetry.io +operf-micro -- Simple tool for benchmarking the OCaml compiler +opine -- Python AST unparse implementation in OCaml +opium -- OCaml web framework +opium-graphql -- Run GraphQL servers with Opium +opium-testing -- Testing library for Opium +opium_kernel -- Sinatra like web toolkit based on Lwt + Cohttp +oplot -- Mathematical plotter library for ocaml +oplsr -- OCaml wrapper for the R 'pls' package +opomodoro -- A simple Pomodoro timer +optal -- A new language for optimization +opti -- DSL to generate fast incremental C code from declarative specifications +optimization1d -- Find extrema of 1D functions +optiml-transport -- Solve optimal transportation problems using the network simplex algorithm +optint 0.3.0 Efficient integer types on 64-bit architectures +opus -- Bindings to libopus +oqamldebug -- Graphical front-end to ocamldebug +oraft -- Raft consensus algorithm implemented in OCaml +orandforest -- A random forest classifier based on OC4.5. +oranger -- OCaml wrapper for the ranger (C++) random forests implementation +order-i3-xfce -- Order-i3-xfce is a small utility that allow you to keep a synchronized order between i3 tabs and the xfce pannel window buttons plugin +ordering 3.11.1 Element ordering +ordinal -- A language interpreter based on the Forth language +ordinal_abbreviation -- A minimal library for generating ordinal names of integers. +orec -- dynamic open records +orewa -- Async-friendly Redis client +orf -- OCaml Random Forests +orgeat -- Ocaml Random Generation of Arbitrary Types +orm -- The ORM library provides a storage backend to persist ML values. +orocksdb -- ctypes based bindings for rocksdb +orpie -- Curses-based RPN calculator +orrandomForest -- Classification or regression using Random Forests +orsetto -- A library of assorted structured data interchange languages +orsvm_e1071 -- OCaml wrapper to SVM R packages e1071 and svmpath +orun -- Run benchmarks and measure performance +orxgboost -- Gradient boosting for OCaml using the R xgboost package +osbx -- Implementation of SeqBox in OCaml +osc -- OpenSoundControl core library +osc-lwt -- OpenSoundControl Lwt library +osc-unix -- OpenSoundControl Unix library +osdp -- OCaml Interface to SDP solvers +oseq -- Simple list of suspensions, as a composable lazy iterator that behaves like a value +osh -- OCaml web API to generate SVG shields +oskel -- Skeleton generator for OCaml projects +osnap -- OCaml random snapshot testing +ostap -- Parser-combinator library +otf -- otf is a simple Output Test Framework +otfm -- OpenType font decoder for OCaml +otoggl -- Bindings for Toggl API in OCaml +otoml -- TOML parsing, manipulation, and pretty-printing library (1.0.0-compliant) +otr -- Off the record implementation purely in OCaml +ott -- A tool for writing definitions of programming languages and calculi +otto -- Otto is a testing / autograding library +ounit -- This is a transition package, ounit-lwt is now ounit2-lwt +ounit-lwt -- This is a transition package, ounit-lwt is now ounit2-lwt +ounit2 -- OUnit testing framework +ounit2-lwt -- OUnit testing framework +owee -- OCaml library to work with DWARF format +owi -- OCaml toolchain to work with WebAssembly, including and interpreter +owl -- OCaml Scientific and Engineering Computing +owl-base -- OCaml Scientific and Engineering Computing - Base +owl-jupyter -- Owl - Jupyter Wrappter +owl-ode -- Owl's ODE solvers +owl-ode-base -- Owl's ODE solvers +owl-ode-odepack -- Owl's ODE solvers, interface with ODEPACK +owl-ode-sundials -- Owl's ODE solvers, interface with SundialsML +owl-opt -- Owl's Optimisation Module +owl-opt-lbfgs -- Owl's Lbfgs Optimisation Module +owl-plplot -- OCaml Scientific and Engineering Computing +owl-top -- OCaml Scientific and Engineering Computing - Top +owork -- A productivity timer for focusing on work +ozulip -- OCaml bindings to Zulip API +p4pp -- P4PP: Preprocessor for P4 Language +p5scm -- Scheme via camlp5 +pa_comprehension -- Syntax extension for comprehension expressions +pa_monad_custom -- Syntactic Sugar for Monads +pa_ppx -- PPX Rewriters for Ocaml, written using Camlp5 +pa_ppx_hashcons -- A PPX Rewriter for Hashconsing +pa_ppx_migrate -- A PPX Rewriter for Migrating AST types (written using Camlp5) +pa_ppx_parsetree -- A Camlp5-based Quasi-Quotation ppx rewriter for OCaml's AST +pa_ppx_q_ast -- A PPX Rewriter for automating generation of data-conversion code for use with Camlp5's Q_ast +pa_ppx_quotation2extension -- A Camlp5 PPX Rewriter for treating PPX extensions as Camlp5 quotations +pa_ppx_regexp -- A Camlp5 PPX Rewriter for Perl Regexp Workalikes +pa_ppx_static -- A Camlp5 PPX Rewriter for static blocks +pa_ppx_string -- A Camlp5 PPX Rewriter for String Interpolation +pa_ppx_unique -- A PPX Rewriter for Uniqifying ASTs +pa_qualified -- A syntax extension that implements support for fully qualified module references +pa_solution -- A DSL for solving programming contest problems +pa_where -- Backward declaration syntax +packstream -- Packstream parses and serializes Packstream binary format +pacomb -- Parsing library based on combinators and ppx extension to write languages +paf -- HTTP/AF and MirageOS +paf-cohttp -- A CoHTTP client with its HTTP/AF implementation +paf-le -- A CoHTTP client with its HTTP/AF implementation +pam -- OCaml bindings for the Linux-PAM library +pandoc -- Library to write pandoc filters +pandoc-abbreviations -- Pandoc filter to add non-breaking spaces after abbreviations +pandoc-crossref -- Pandoc filter to have LaTeX cross-references +pandoc-include -- Pandoc filter to include other files +pandoc-inspect -- Pandoc filter to inspect pandoc's JSON +papi -- Performance Application Programming Interface (PAPI) bindings +parany 14.0.1 Parallelize any computation +pardi -- Parallel execution of command lines, pardi! +pareto -- GSL powered OCaml statistics library. +pari -- Type-safe wrapper over the PARI library +pari-bindings -- OCaml bindings to the PARI library +parmap -- Minimalistic library allowing to exploit multicore architecture +parse-argv -- Process strings into sets of command-line arguments +parsexp v0.16.0 S-expression parsing library +parsexp_io -- S-expression parsing library (IO functions) +parsley -- Parsley library +patch -- Patch library purely in OCaml +patdiff -- File Diff using the Patience Diff algorithm +path_glob -- Globbing file paths +patience_diff -- Diff library using Bram Cohen's patience diff algorithm +pattern -- Run-time patterns that explain match failures +pb -- Library for describing Protobuf messages +pb-plugin -- Plugin for generating pb protobuf message descriptions +pbkdf 1.2.0 Password based key derivation functions (PBKDF) from PKCS#5 +pbrt -- Runtime library for Protobuf tooling +pbs -- Helper library around PBS/Torque +pcap-format -- Decode and encode PCAP (packet capture) files +pci -- Ctypes bindings to libpci for OCaml +pci-db -- Library to parse and query the pci.ids database of PCI devices +pcre -- Bindings to the Perl Compatibility Regular Expressions library +pcre2 -- Bindings to the Perl Compatibility Regular Expressions library (version 2) +pds -- +pds-reachability -- A PDS reachability query library +pecu 0.6 Encoder/Decoder of Quoted-Printable (RFC2045 & RFC2047) +petrol -- Petrol's an OCaml SQL API made to go FAST +pf-qubes -- QubesOS firewall ruleset handling library +pg_query -- Bindings to libpg_query for parsing PostgreSQL +pgocaml -- Native OCaml interface to PostgreSQL databases +pgocaml_ppx -- PPX extension for PGOCaml +pgsolver -- A collection of tools for generating, manipulating and - most of all - solving parity games +pgx -- Pure-OCaml PostgreSQL client library +pgx_async -- Pgx using Async for IO +pgx_lwt -- Pgx using Lwt for IO +pgx_lwt_mirage -- Pgx using Lwt on Mirage for IO +pgx_lwt_unix -- Pgx using Lwt and Unix libraries for IO +pgx_unix -- PGX using the standard library's Unix module for IO (synchronous) +pgx_value_core -- Pgx_value converters for Core types like Date and Time +pgx_value_ptime -- Pgx_value converters for Ptime types +phantom-algebra -- A strongly-typed tensor library à la GLSL +phashtbl -- Persistent hash table library using dbm under the carpet. +phonetic -- Phonetic algorithm in OCaml +phylogenetics -- Algorithms and datastructures for phylogenetics +piaf -- An HTTP library with HTTP/2 support written entirely in OCaml +picasso 0.4.0 Abstract elements drawing library +piece_rope -- A data structure for efficiently manipulating strings +pilat -- Polynomial invariant generator +piqi -- Protocol Buffers, JSON and XML serialization system for OCaml +piqilib -- The Piqi library -- runtime support for multi-format Protobuf/JSON/XML/Piq data serialization and conversion +pkcs11 -- PKCS#11 OCaml types +pkcs11-cli -- Cmdliner arguments to initialize a PKCS#11 session +pkcs11-driver -- Bindings to the PKCS#11 cryptographic API +pkcs11-rev -- Reverse bindings to pkcs11 +pla -- Pla is a simple library and ppx syntax extension to create composable templates based on verbatim strings +plateau -- Print a table in a single line +plato -- Python Library Adapted To OCaml +plebeia -- Functional storage using Merkle Patricia tree +plist -- Create Apple Plists +plist-xml -- Reading and writing of plist files in the XML format in pure OCaml +plist-xml-lwt -- Reading of plist files in the XML format with Lwt +plotkicadsch -- Utilities to print and compare version of Kicad schematics +plotly -- Binding for Plotly Open Source Graphing Library +plplot -- Bindings for the PLplot library +podge -- Shortcuts and helpers for common tasks in OCaml ecosystem +polka -- Polka: convex polyhedron library by Bertrand Jeannet (now part of apron) +poll -- Portable OCaml interface to macOS/Linux/Windows native IO event notification mechanisms +polling_state_rpc -- An RPC which tracks state on the client and server so it only needs to send diffs across the wire. +polly -- Bindings for the Linux epoll system call +polyglot -- Filters to convert XHTML into polyglot HTML5 +polynomial -- Polynomials over finite fields +pomap -- Partially Ordered Maps for OCaml +popper -- Property-based testing at ease +portaudio -- Bindings for the portaudio library which provides high-level functions for using soundcards +portaudio_c_bindings -- Bindings to the C PortAudio library +portia -- Literate Programming Preprocessor +portmidi -- Bindings to libportmidi +posix-base -- Base module for the posix bindings +posix-bindings -- POSIX bindings +posix-clock -- POSIX clock +posix-getopt -- Bindings for posix getopt/getopt_long +posix-math -- POSIX math +posix-mqueue -- POSIX message queues +posix-semaphore -- POSIX semaphore +posix-signal -- Bindings for the types defined in +posix-socket -- Bindings for posix sockets +posix-socket-unix -- Bindings for posix sockets +posix-time -- POSIX time +posix-time2 -- Bindings for posix time functions +posix-types -- Bindings for the types defined in +posix-uname -- Bindings for posix uname +posixat -- Bindings to the posix *at functions +postgres_async -- OCaml/async implementation of the postgres protocol (i.e., does not use C-bindings to libpq) +postgresql -- Bindings to the PostgreSQL library +pp 1.2.0 Pretty-printing library +pp-binary-ints -- Pretty Printing Binary Integers +pp_loc 2.1.0 Quote and highlight input fragments at a given source location +pprint 20230830 A pretty-printing combinator library and rendering engine +ppx-owl-opt -- Ppx tool for owl-opt +ppx_accessor -- [@@deriving] plugin to generate accessors for use with the Accessor libraries +ppx_assert v0.16.0 Assert-like extension nodes that raise useful errors on failure +ppx_bap -- The set of ppx rewriters for BAP +ppx_base v0.16.0 Base set of ppx rewriters +ppx_bench v0.16.0 Syntax extension for writing in-line benchmarks in ocaml code +ppx_bin_prot v0.16.0 Generation of bin_prot readers and writers from types +ppx_bitstring -- Bitstrings and bitstring matching for OCaml - PPX extension +ppx_blob 0.7.2 Include a file as a string at compile time +ppx_camlrack -- PPX for matching S-Expressions +ppx_catch -- A PPX rewriter to catch exceptions and wrap into options or results +ppx_cold v0.16.0 Expands [@cold] into [@inline never][@specialise never][@local never] +ppx_compare v0.16.0 Generation of comparison functions from types +ppx_compose -- Inlined function composition +ppx_const -- Compile-time "if" statement for conditional inclusion of code +ppx_conv_func -- Deprecated +ppx_counters -- Generate useful code for stats gathering from records of counters +ppx_css -- A ppx that takes in css strings and produces a module for accessing the unique names defined within +ppx_cstruct -- Access C-like structures directly from OCaml +ppx_cstubs -- Preprocessor for easier stub generation with ctypes +ppx_csv_conv -- Generate functions to read/write records in csv format +ppx_custom_printf v0.16.0 Printf-style format-strings for user-defined string conversion +ppx_decimal -- A ppx for decimal literals +ppx_default -- Generate default values for your types +ppx_defer -- Go-like [%defer later]; now syntax +ppx_demo -- PPX that exposes the source code string of an expression/module structure. +ppx_derive_at_runtime -- Define a new ppx deriver by naming a runtime module. +ppx_derivers 1.2.1 Shared [@@deriving] plugin registry +ppx_deriving 5.2.1 Type-driven code generation for OCaml +ppx_deriving_cad -- PPX Deriver for OCADml transformation functions +ppx_deriving_cmdliner -- Cmdliner.Term.t generator +ppx_deriving_encoding -- Ppx deriver for json-encoding +ppx_deriving_hardcaml -- Rewrite OCaml records for use as Hardcaml Interfaces +ppx_deriving_hash -- [@@deriving hash] +ppx_deriving_jsoo -- Ppx deriver for Js_of_ocaml +ppx_deriving_madcast -- Library deriving cast functions based on their types +ppx_deriving_popper -- A ppx deriving sample-functions for Popper +ppx_deriving_protobuf -- A Protocol Buffers codec generator for OCaml +ppx_deriving_protocol -- Migrate to ppx_protocol_conv +ppx_deriving_qcheck -- PPX Deriver for QCheck +ppx_deriving_rpc -- Ppx deriver for ocaml-rpc, a library to deal with RPCs in OCaml +ppx_deriving_scad -- PPX Deriver for Scad_ml transformation functions +ppx_deriving_yaml -- Yaml PPX Deriver +ppx_deriving_yojson -- JSON codec generator for OCaml +ppx_disable_unused_warnings v0.16.0 Expands [@disable_unused_warnings] into [@warning "-20-26-32-33-34-35-36-37-38-39-60-66-67"] +ppx_distr_guards -- Extension to distribute guards over or-patterns +ppx_enumerate v0.16.0 Generate a list containing all values of a finite type +ppx_expect v0.16.0 Cram like framework for OCaml +ppx_factory -- PPX to derive factories and default values +ppx_fail -- Add location to calls to failwiths +ppx_fields_conv v0.16.0 Generation of accessor and iteration functions for ocaml records +ppx_fixed_literal v0.16.0 Simpler notation for fixed point literals +ppx_gen_rec -- A ppx rewriter that transforms a recursive module expression into a `struct` +ppx_getenv -- A sample syntax extension using OCaml's new extension points API +ppx_globalize v0.16.0 A ppx rewriter that generates functions to copy local values to the global heap +ppx_hash v0.16.0 A ppx rewriter that generates hash functions from type expressions and definitions +ppx_here v0.16.0 Expands [%here] into its location +ppx_ignore_instrumentation v0.16.0 Ignore Jane Street specific instrumentation extensions +ppx_import 1.10.0 A syntax extension for importing declarations from interface files +ppx_inline_alcotest -- Inline tests backend for alcotest +ppx_inline_test v0.16.0 Syntax extension for writing in-line tests in ocaml code +ppx_interact -- Opens a REPL in context +ppx_irmin 3.7.2 PPX deriver for Irmin type representations +ppx_jane v0.16.0 Standard Jane Street ppx rewriters +ppx_js_style -- Code style checker for Jane Street Packages +ppx_jsobject_conv -- Ppx plugin for Typeconv to derive conversion from ocaml types to js objects to use with js_of_ocaml +ppx_jsonaf_conv -- [@@deriving] plugin to generate Jsonaf conversion functions +ppx_let v0.16.0 Monadic let-bindings +ppx_log v0.16.0 Ppx_sexp_message-like extension nodes for lazily rendering log messages +ppx_lun -- Optics with lun package and PPX +ppx_make -- [@@deriving make] +ppx_map -- A PPX rewriter to simplify the declaration of maps +ppx_matches -- Small ppx to help check if a value matches a pattern +ppx_meta_conv -- PPX for converting between OCaml values and JSON, Sexp and camlon +ppx_minidebug -- Debug logs for selected functions and let-bindings +ppx_module_timer v0.16.0 Ppx rewriter that records top-level module startup times +ppx_monad -- A Syntax Extension for all Monadic Syntaxes +ppx_monoid -- Syntax extension for building values of monoids +ppx_mysql -- Syntax extension for facilitating usage of MySQL bindings +ppx_optcomp v0.16.0 Optional compilation for OCaml +ppx_optint -- Literals for Optint integers +ppx_optional v0.16.0 Pattern matching on flat options +ppx_parser -- OCaml PPX extension for writing stream parsers +ppx_pattern_bind -- A ppx for writing fast incremental bind nodes in a pattern match +ppx_pipebang v0.16.0 A ppx rewriter that inlines reverse application operators `|>` and `|!` +ppx_protocol_conv -- Ppx for generating serialisation and de-serialisation functions of ocaml types +ppx_protocol_conv_json -- Json driver for Ppx_protocol_conv +ppx_protocol_conv_jsonm -- Jsonm driver for Ppx_protocol_conv +ppx_protocol_conv_msgpack -- MessagePack driver for Ppx_protocol_conv +ppx_protocol_conv_xml_light -- Xml driver for Ppx_protocol_conv +ppx_protocol_conv_xmlm -- Xmlm driver for Ppx_protocol_conv +ppx_protocol_conv_yaml -- Yaml driver for Ppx_protocol_conv +ppx_pyformat -- Ppxlib based string format rewriter inspired by Python string `format` +ppx_python -- [@@deriving] plugin to generate Python conversion functions +ppx_rapper -- Syntax extension for Caqti/PostgreSQL queries +ppx_rapper_async -- Async support for ppx_rapper +ppx_rapper_lwt -- Lwt support for ppx_rapper +ppx_regexp -- Matching Regular Expressions with OCaml Patterns +ppx_repr 0.7.0 PPX deriver for type representations +ppx_seq -- Seq literals ppx for OCaml +ppx_sexp_conv v0.16.0 [@@deriving] plugin to generate S-expression conversion functions +ppx_sexp_message v0.16.0 A ppx rewriter for easy construction of s-expressions +ppx_sexp_value v0.16.0 A ppx rewriter that simplifies building s-expressions from ocaml values +ppx_show -- OCaml PPX deriver for deriving show based on ppxlib +ppx_stable v0.16.0 Stable types conversions generator +ppx_stable_witness v0.16.0 Ppx extension for deriving a witness that a type is intended to be stable. In this context, stable means that the serialization format will never change. This allows programs running at different versions of the code to safely communicate. +ppx_string v0.16.0 Ppx extension for string interpolation +ppx_string_interpolation -- String interpolation PPX preprocessor +ppx_subliner -- [@@deriving subliner] and [%%subliner] for Cmdliner +ppx_system -- A ppx to know host operating system at compile time +ppx_test -- A ppx replacement of pa_ounit +ppx_tools -- Tools for authors of ppx rewriters and other syntactic tools +ppx_traverse_builtins -- Builtins for Ppx_traverse +ppx_ts -- A PPX helps binding to typescript modules +ppx_tydi v0.16.0 Let expressions, inferring pattern type from expression. +ppx_type_directed_value -- Get [@@deriving]-style generation of type-directed values without writing a ppx +ppx_typed_fields -- GADT-based field accessors and utilities +ppx_typerep_conv v0.16.0 Generation of runtime types from type declarations +ppx_units -- Generate unit types for every record field +ppx_update -- PPX library to optimize record updates +ppx_variants_conv v0.16.0 Generation of accessor and iteration functions for ocaml variant types +ppx_viewpattern -- View patterns in OCaml +ppx_xml_conv -- Generate XML conversion functions from records +ppx_yojson -- PPX extension for Yojson literals and patterns +ppx_yojson_conv -- [@@deriving] plugin to generate Yojson conversion functions +ppx_yojson_conv_lib v0.16.0 Runtime lib for ppx_yojson_conv +ppxlib 0.31.0 Standard infrastructure for ppx rewriters +ppxx -- Ppxx: a small extension library for writing PPX preprocessors +pratter -- An extended Pratt parser +prbnmcn-basic-structures 0.0.1 Base package for prbnmcn-* packages +prbnmcn-cgrph -- Incremental computation +prbnmcn-clustering -- Clustering library +prbnmcn-dagger -- Probabilistic programming library +prbnmcn-dagger-gsl -- Probabilistic programming library: GSL-based samplers +prbnmcn-dagger-stats -- Probabilistic programming library: prbnmcn-stats-based samplers +prbnmcn-dagger-test -- Probabilistic programming library: tests +prbnmcn-gnuplot -- Declarative generation of gnuplot scripts +prbnmcn-linalg 0.0.1 Functional vector and matrix manipulation +prbnmcn-mcts -- Monte-Carlo tree search based on UCB1 bandits +prbnmcn-proptest -- Property-based test helpers for prbnmcn packages +prbnmcn-stats 0.0.6 Basic statistics +prbnmcn-ucb1 -- UCB1 algorithm for multi-armed bandits +prc -- Utilities for precision-recall curves +preface -- An opinionated library for function programming (à La Haskell) +prettym 0.0.3 An memory-bounded encoder according to RFC 822 +primes -- A small library for dealing with primes. +pringo 1.3 Pseudo-random, splittable number generators +printbox -- Allows to print nested boxes, lists, arrays, tables in several formats +printbox-html -- Printbox unicode handling +printbox-text -- Text renderer for printbox, using unicode edges +proc-smaps -- Proc-smaps: An ocaml parser of /proc/[pid]/smaps +process -- Easy process control +process_limits -- Setting time and memory limits for your program +processor -- Processor Topology & Affinity for ocaml +producer -- Accumulate results using monadic dependency graphs +profiler-plugin -- Alt-Ergo, an SMT Solver for Software Verification: Profiler Plugin +profiling -- Small library to help profile code +profunctor -- A library providing a signature for simple profunctors and traversal of a record +progress 0.2.1 User-definable progress bars +proj4 -- Bindings to the PROJ.4 projection library +prom -- Types and pretty printer for Prometheus text-based exposition format +prometheus 1.2 Client library for Prometheus monitoring +prometheus-app 1.2 Client library for Prometheus monitoring +prometheus-liquidsoap -- Virtual package installing liquidsoap dependencies for prometheus optional features +promise -- Native implementation of a JS promise binding +promise_jsoo -- Js_of_ocaml bindings to JS Promises with supplemental functions +protocell -- A Protobuf plugin for OCaml +protocol-9p -- An implementation of the 9p protocol in pure OCaml +protocol-9p-tool -- An implementation of the 9p protocol in pure OCaml +protocol-9p-unix -- A Unix implementation of the 9p protocol in pure OCaml +protocol_version_header v0.16.0 Protocol versioning +proverif -- ProVerif: Cryptographic protocol verifier in the symbolic model +proverifdoc -- Documentation for ProVerif, a cryptographic protocol verifier in the symbolic model +prr -- A fork of brr, sans browser-only APIs +psmt2-frontend 0.4.0 The psmt2-frontend project +psq 0.2.1 Functional Priority Search Queues +psyche -- A WASM-friendly lightweight programming language implemented in OCaml +ptime 1.1.0 POSIX time for OCaml +ptmap -- Maps of integers implemented as Patricia trees +ptset -- Sets of integers implemented as Patricia trees +publish -- opam-publish transition package +pulseaudio -- Bindings to Pulseaudio client library +pure-splitmix 0.3 Purely functional splittable PRNG +pvec -- Persistent vectors +pvem -- Polymorphic-Variants-based Error Monad +pxp -- Polymorphic XML Parser +py -- Ctypes bindings to Python 3.5 or greater +pyast -- Python AST +pyml 20220905 OCaml bindings for Python +pyml_bindgen -- Generate pyml bindings from OCaml value specifications +pyre-ast -- Full-fidelity Python parser in OCaml +pythonlib -- A library to help writing wrappers around ocaml code for python +qbf -- QBF solving in OCaml, including bindings to solvers +qcheck -- Compatibility package for qcheck +qcheck-alcotest 0.21.2 Alcotest backend for qcheck +qcheck-core 0.21.2 Core qcheck library +qcheck-lin -- A multicore testing library for OCaml +qcheck-multicoretests-util -- Various utility functions for property-based testing of multicore programs +qcheck-ounit -- OUnit backend for qcheck +qcheck-stm -- State-machine testing library for sequential and parallel model-based tests +qcow -- Support for Qcow2 images +qcow-tool -- A command-line tool for manipulating qcow2-formatted data +qcstm -- A simple state-machine framework for OCaml based on QCheck +qfs -- Bindings to libqfs - client library to access QFS +qinap -- A (very small) monadic parsing library +qiskit -- Qiskit for OCaml +qmp -- OCaml implementation of a Qemu Message Protocol (QMP) client +qrc -- QR code encoder for OCaml +qrencode -- Binding to libqrencode (QR-code encoding library) +qtest -- Lightweight inline test extraction from comments +queenshead -- British pub name generator +quest -- quest - generates C code for testing a C compiler's calling convention +quests -- HTTP/1.1 client library like Python requests +quick_print -- Quick and easy printing for lists, arrays, etc +r2pipe -- Deprecated: use radare2 instead +radamsa -- Radamsa bindings for OCaml +radare2 -- OCaml interface to r2 +randii -- A pure OCaml port of the Random123 counter based random number generator from DEShaw Research +randomconv -- Convert from random byte vectors (Cstruct.t) to random native numbers +randoml -- Generating cryptographically-secure random numbers +range -- Fold on integer range +ranger -- A consecutive range slice library for strings, arrays, etc. +rangeSet -- RangeSet: a library for sets over ordered ranges +rankers -- Vanishing Ranking Kernels (VRK) +rawlink -- Portable library to read and write raw packets +rawlink-lwt -- Portable library to read and write raw packets with Lwt bindings +raygui -- OCaml bindings for raygui +raygun4ocaml -- Client for the Raygun error reporting API +raylib -- OCaml bindings for raylib +rdbg -- RDBG: a reactive programs debugger +rdf -- OCaml library to manipulate RDF graphs; implements SPARQL +rdf_json_ld -- Json-ld +rdf_lwt -- Sparql HTTP with Lwt +rdf_mysql -- Mysql backend for rdf +rdf_postgresql -- Postgresql backend for rdf +rdf_ppx -- Syntax extension for rdf +rdr -- Rdr is a cross-platform binary analysis and reverse engineering tool, utilizing a unique symbol map for global analysis. +re 1.11.0 RE is a regular expression library for OCaml +re2 -- OCaml bindings for RE2, Google's regular expression library +re2_stable -- Re2_stable adds an incomplete but stable serialization of Re2 +re_parser -- Typed parsing using regular expressions. +rea -- Effectful OCaml with Objects and Variants +react -- Declarative events and signals for OCaml +reactiveData -- Declarative events and signals for OCaml +reactjs-jsx-ppx -- ReactJS JSX PPX +readline -- OCaml bindings for GNU readline +reanalyze -- Dead values/types, exception, and termination analysis for OCaml/ReScript +reason -- Reason: Syntax & Toolchain for OCaml +reason-react -- Reason bindings for React.js +reason-react-ppx -- React.js JSX PPX +received -- Received field according RFC5321 +record_builder -- A library which provides traversal of records with an applicative +records -- Dynamic records +reddit_api_async -- Async connection and utility functions for Reddit's API +reddit_api_kernel -- OCaml types for Reddit's API +redirect -- Redirect channels +redis 0.7.1 Redis client +redis-async -- Redis client for Async applications +redis-lwt -- Redis client (lwt interface) +redis-sync -- Redis client (blocking) +reedsolomon -- Reed-Solomon Error Correction CODEC +refl -- PPX deriver for reflection +regenerate -- Regenerate is a tool to generate test-cases for regular expression engines +regex_parser_intf -- Interface shared by Re_parser and Re2.Parser +regular -- Library for regular data types +remu_ts -- External type infer +reparse -- Recursive descent parsing library for ocaml +reparse-lwt -- Reparse Lwt_stream.t input support +reparse-lwt-unix -- Reparse lwt-unix based input support +reparse-unix -- Provides support for parsing files as source of input for reparse library +repr 0.7.0 Dynamic type representations. Provides no stability guarantee +repr-bench -- Benchmarks for the `repr` package +repr-fuzz -- Fuzz tests for the `repr` package +res -- RES - Library for resizable, contiguous datastructures +res_tailwindcss -- PPX validates the tailwindcss class names +rescript-syntax -- ReScript syntax packaged as an opam library +resource-pooling -- Library for pooling resources like connections, threads, or similar +resource_cache -- General resource cache +resp -- Redis serialization protocol library +resp-client -- Redis serialization protocol client library +resp-mirage -- Redis serialization protocol for MirageOS +resp-server -- Redis serialization protocol server +resp-unix -- Redis serialization protocol for Unix +resto 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs +resto-acl 1.2 Access Control Lists for Resto +resto-cohttp 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs +resto-cohttp-client 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs +resto-cohttp-self-serving-client 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs +resto-cohttp-server 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs - server library +resto-directory 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs +resto-json -- A minimal OCaml library for type-safe HTTP/JSON RPCs +result 1.5 Compatibility Result module +revops -- Reversible operations +rfc1951 -- Implementation of RFC1951 in OCaml +rfc6287 -- OCRA (OATH Challenge-Response Algorithm) implementation in OCaml +rfc7748 -- Edwards Curves X25519 and X448 from RFC 7748 +rfsm -- A toolset for describing and simulating StateChart-like state diagrams +rhythm -- Data Structures and Algorithms implemented in Reason +ringo 1.0.0 Bounded-length collections +ringo-lwt -- Lwt-wrappers for Ringo caches +river -- RSS2 and Atom feed aggregator for OCaml +rlp -- RLP: Recursive Length Prefix Encoding +rml -- ReactiveML: a programming language for implementing interactive systems +rmlbuild -- rmlbuild is a fork of ocamlbuild that handles ReactiveML projets +rock -- Minimalist framework to build extensible HTTP servers and clients +roman -- Manipulate roman numerals (ocaml.org dune/opam tutorial) +root1d -- Find roots of 1D functions +rope -- Ropes (heavyweight strings) +rosa -- String manipulation library +rosetta -- Universal mapper to Unicode +routes -- Typed routing for OCaml applications +rpc -- A library to deal with RPCs in OCaml - meta-package +rpc_parallel -- Type-safe parallel library built on top of Async_rpc +rpclib -- A library to deal with RPCs in OCaml +rpclib-async -- A library to deal with RPCs in OCaml - Async interface +rpclib-html -- A library to deal with RPCs in OCaml - html documentation generator +rpclib-js -- A library to deal with RPCs in OCaml - Bindings for js_of_ocaml +rpclib-lwt -- A library to deal with RPCs in OCaml - Lwt interface +rresult 0.7.0 Result value combinators for OCaml +rsdd -- Bindings for RSDD +rss -- Library to read and write RSS files +rtop -- Reason toplevel +rtree -- A pure OCaml R-Tree implementation +rungen -- Generates dune files to run benchmarks from centralised config +rusage 1.0.0 Bindings to the GETRUSAGE(2) syscall +Snowflake -- Snowflake : A Generic Symbolic Dynamic Programming framework +SZXX -- Streaming ZIP XML XLSX parser +safa -- Symbolic Algorithms for Finite Automata +safemoney -- A type safe money manipulation library +safepass -- Facilities for the safe storage of user passwords +sail -- Sail is a language for describing the instruction semantics of processors +sail_c_backend -- Sail to C translation +sail_coq_backend -- Sail to Coq translation +sail_doc_backend -- Sail documentation generator +sail_latex_backend -- Sail to LaTeX formatting +sail_lem_backend -- Sail to Lem translation +sail_manifest -- Helper tool for compiling Sail +sail_ocaml_backend -- Sail to OCaml translation +sail_output -- Example Sail output plugin +sail_smt_backend -- Sail to C translation +salsa20 -- Salsa20 family of encryption functions, in pure OCaml +salsa20-core -- The Salsa20 core functions, in OCaml +samplerate -- Samplerate audio conversion library +sanddb -- A simple immutable database for the masses +sarek -- GPGPU kernel DSL for OCaml +satML-plugin -- Alt-Ergo, an SMT Solver for Software Verification: satML Plugin +sattools -- Ctypes and DIMACs interfaces to minisat, picosat and cryptominisat +saturn -- Parallelism-safe data structures for multicore OCaml +saturn_lockfree -- Lock-free data structures for multicore OCaml +satyrographos -- A package manager for SATySFi +sawja -- Sawja provides a high level representation of Java bytecode programs and static analysis tools +scad_ml -- OCaml DSL for 3D solid modelling in OpenSCAD +scfg -- OCaml library and executable to work with the scfg configuration file format +scgi -- Simple Common Gateway Interface (SCGI) protocol support for interface with HTTP servers +schroedinger -- Bindings for the schroedinger library to decode video files in Dirac format +scid -- Sierra Chart's Intraday Data File Format library +scipy -- SciPy scientific computing library for OCaml +scrypt -- C bindings and a high level interface to the official scrypt distribution. +scrypt-kdf -- The scrypt Password-Based Key Derivation Function +sd_logic -- Functionality for time-based finite state machine +sdl-liquidsoap -- Virtual package installing liquidsoap dependencies for SDL optional features +search -- Simple, in-memory search library in pure OCaml +searchTree -- A module to easily implement search trees +secp256k1 -- Elliptic curve library secp256k1 wrapper for Ocaml +secp256k1-internal 0.4.0 Bindings to secp256k1 internal functions (generic operations on the curve) +sedlex 3.2 An OCaml lexer generator for Unicode +sek -- An efficient implementation of ephemeral and persistent sequences +sel -- Simple Event Library +semantic_version -- Semantic versioning +semaphore-compat 1.0.1 Compatibility Semaphore module +semver -- Semantic Versioning (semver) library +semver2 -- Semantic version handling for OCaml +sendmail -- Implementation of the sendmail command +sendmail-lwt -- Implementation of the sendmail command over LWT +sendmsg -- π-calculus? In _my_ kernel? +sentry -- Unofficial Async Sentry error monitoring client +seq base Compatibility package for OCaml's standard iterator type starting from 4.07. +seqes 0.2 Seq with monads +sequence -- Simple sequence abstract datatype. +sequencer_table -- A table of [Async.Sequencer]'s, indexed by key +serde -- A serialization framework for OCaml +serde_debug -- A human-friendly format for Serde that helps you debug any data during development +serde_derive -- Derive-macros for the Serde serialization framework +serde_json -- JSON format support for Serde +serde_sexpr -- S-expression format support for Serde +serde_xml -- XML format support for Serde +serial -- Serial communication module +session -- A session manager for your everyday needs +session-cohttp -- A session manager for your everyday needs - Cohttp-specific support +session-cohttp-async -- A session manager for your everyday needs - Cohttp-specific support for Async +session-cohttp-lwt -- A session manager for your everyday needs - Cohttp-specific support for Lwt +session-cookie -- Session handling for OCaml and ReasonML +session-cookie-async -- Session handling for OCaml and ReasonML +session-cookie-lwt -- Session handling for OCaml and ReasonML +session-postgresql -- A session manager for your everyday needs - Postgresql-specific support +session-postgresql-async -- A session manager for your everyday needs - Postgresql-specific support for Async +session-postgresql-lwt -- A session manager for your everyday needs - Postgresql-specific support +session-redis-lwt -- A session manager for your everyday needs - Redis-specific support for Lwt +session-webmachine -- A session manager for your everyday needs - Webmachine-specific support +sessions -- Library to provide session types to allow for static verification of protocols between concurrent computations +setcore -- Pin current process to given core number +setr -- Abstract domain library for sets +sexp -- S-expression swiss knife +sexp_decode -- A library to decode S-expression into structured data +sexp_diff -- Code for computing the diff of two sexps +sexp_diff_kernel -- Code for computing the diff of two sexps +sexp_grammar -- Sexp grammar helpers +sexp_macro -- Sexp macros +sexp_pretty v0.16.0 S-expression pretty-printer +sexp_select -- A library to use CSS-style selectors to traverse sexp trees +sexp_string_quickcheck -- Quickcheck helpers for strings parsing to sexps +sexplib v0.16.0 Library for serializing OCaml values to and from S-expressions +sexplib0 v0.16.0 Library containing the definition of S-expressions and some base converters +sfml -- Bindings to the SFML multimedia library +sgf -- Parser and pretty printer for SGF files +sha -- Binding to the SHA cryptographic functions +shapefile -- A small library to read ESRI shapefiles +shared-block-ring -- A single-consumer single-producer queue on a block device +shared-memory-ring -- Shared memory rings for RPC and bytestream communications +shared-memory-ring-lwt -- Shared memory rings for RPC and bytestream communications using Lwt +shared-secret -- Exceptions are shared secrets +shcaml -- Library for Unix shell programming +shell -- Yet another implementation of fork&exec and related functionality +shexp -- Process library and s-expression based shell +shine -- Fixed-point MP3 encoder +shuttle -- Reasonably performant non-blocking channels for async +shuttle_http -- Async library for HTTP/1.1 servers and clients +shuttle_ssl -- Async_ssl support for shuttle +shuttle_websocket -- Websocket support for HTTP/1.1 servers using Async +sid -- Handle security identfiers +sifun -- Interpreter for SiFun (Simple Functional) Language with three different type systems (supports Higher Rank Polymorphism) +sihl -- The Sihl web framework +sihl-cache -- Cache service implementations for Sihl +sihl-contract -- Sihl serivce interfaces +sihl-core -- The core of the Sihl web framework +sihl-email -- Email service implementations for Sihl +sihl-facade -- Sihl service facade that uses the facade pattern to hide service implementations +sihl-persistence -- Sihl services to deal with data persistence +sihl-queue -- Queue service implementations for Sihl +sihl-session -- Sihl service to deal with sessions +sihl-storage -- Storage service implementations for Sihl +sihl-token -- Token service implementations for Sihl +sihl-type -- Contains Sihl types that are returned by Sihl services +sihl-user -- User service implementations for Sihl +sihl-web -- Sihl HTTP service and middlewares +simlog -- A simple OCaml logging library +simple-diff -- Simple_diff is a pure OCaml diffing algorithm. +simple63 -- Integer compression and decompression module +simple_pam -- Tiny binding around PAM +sklearn -- Scikit-learn machine learning library for OCaml +slacko -- Type-safe binding to the Slack API +slug -- Url safe slug generator +smart-print -- A pretty-printing library in OCaml +smbc -- Experimental model finder/SMT solver for functional programming +smol -- Small Math Ocaml Library +smol-helpers -- Test helpers for smol +smtlib-utils -- Parser for SMTLIB2 +smtp -- SMTP library with Unix and Lwt backends +snappy -- Bindings to snappy - fast compression/decompression library +snoke -- Snóke is a good old Snake game with new ideas +socketcan -- socketcan +sodium -- Binding to libsodium UNAUDITED +sodium-fmt -- Fmt formatters for Sodium +solid -- Library to build SOLID applications +solid_server -- SOLID server under development +solid_tools -- Library to build SOLID tools +solidity-alcotest -- The ocaml-solidity project +solidity-common -- The ocaml-solidity project +solidity-parser -- The ocaml-solidity project +solidity-test -- The ocaml-solidity project +solidity-typechecker -- The ocaml-solidity project +solo5 -- Solo5 sandboxed execution environment +solo5-bindings-hvt -- Solo5 sandboxed execution environment (hvt target) +solo5-bindings-muen -- Solo5 sandboxed execution environment (muen target) +solo5-bindings-spt -- Solo5 sandboxed execution environment (spt target) +solo5-bindings-virtio -- Solo5 sandboxed execution environment (virtio target) +solo5-bindings-xen -- Solo5 sandboxed execution environment (xen target) +solo5-elftool -- OCaml Solo5 elftool for querying solo5 manifests +solo5-kernel-muen -- Solo5 sandboxed execution environment (muen target) +solo5-kernel-ukvm -- Solo5 sandboxed execution environment (ukvm target) +solo5-kernel-virtio -- Solo5 sandboxed execution environment (virtio target) +sortedseq_intersect -- A divide-and-conquer algorithm to intersect sorted sequences +sosa -- Sane OCaml String API +soundtouch -- Bindings for the soundtouch library which provides functions for changing pitch and timestretching audio data +soupault -- Static website generator based on HTML rewriting +spawn v0.15.1 Spawning sub-processes +spdx_licenses -- A library providing a strict SPDX License Expression parser +spectrum -- Library for colour and formatting in the terminal +speex -- Bindings to libspeex +spelll 0.4 Fuzzy string searching, using Levenshtein automaton +spf -- OCaml bindings for libspf2 +spin -- OCaml project generator +spirv -- SPIR-V Compiler Library +splay_tree -- A splay tree implementation +splittable_random v0.16.0 PRNG that can be split into independent streams +spoc -- High-level GPGPU programming library for OCaml +spoc_ppx -- PPX to declare external GPGPU kernels written in CUDA or OpenCL +spoke -- SPAKE+EE implementation in OCaml +spotify-web-api -- OCaml bindings to the Spotify web API +spotlib -- Useful functions for OCaml programming used by @camlspotter +spreadsheet -- Functor for parsing and building spreadsheets. +sqlgg -- SQL Guided (code) Generator +sqlite3 -- SQLite3 bindings for OCaml +sqlite3_utils -- High-level wrapper around ocaml-sqlite3 +squirrel -- The Squirrel Prover is a proof assistant for protocols, based on first-order logic and provides guarantees in the computational model +srs -- OCaml bindings for libsrs2 +srt -- Binding for the Secure, Reliable, Transport protocol library +ssh-agent -- Ssh-agent protocol parser and serialization implementation +ssh-agent-unix -- Ssh-agent protocol parser and serialization implementation for unix platforms +ssl 0.7.0 Bindings for OpenSSL +statverif -- StatVerif: automated verifier for cryptographic protocols with state, based on ProVerif +stb_image -- OCaml bindings to stb_image, a public domain image loader +stb_image_write -- OCaml bindings to stb_image_write, a public domain image writer +stb_truetype -- OCaml bindings to stb_truetype, a public domain font rasterizer +stdcompat 19 Compatibility module for OCaml standard library +stdint 0.7.2 Signed and unsigned integer types having specified widths +stdint-literals -- Small PPX for fixed size integer literals +stdio v0.16.0 Standard IO library for OCaml +stdlib-diff -- Symmetric Diffs for OCaml stdlib and ReasonML +stdlib-random -- Versioned Random module from the OCaml standard library +stdlib-shims 0.3.0 Backport some of the new stdlib features to older compiler +stdune 3.11.1 Dune's unstable standard library +stemmer -- Porter stemming algorithm in pure OCaml +stemming -- Collection of stemmers +stitch -- Refactoring framework +stk -- SDL-based GUI toolkit +stk_iconv -- Bindings to GNU libiconv +stone -- Simple static website generator, useful for a portfolio or documentation pages +stored_reversed -- A library for representing a list temporarily stored in reverse order. +stramon-lib -- Process behavior monitoring library based on strace +streamable -- A collection of types suitable for incremental serialization +streaming -- Fast, safe and composable streaming abstractions +string_dict -- Efficient static string dictionaries +stringCodepointSplitter -- Split a string to a list of strings of a character by the unicode codepoint +stringext 1.6.0 Extra string functions for OCaml +sturgeon -- A toolkit for communicating with Emacs +subscriptions-transport-ws -- Websocket protocol for exchanging GraphQL requests and responses +subtype-refinement -- Refinement types encoded with private types in OCaml +sugar -- Monadic library for error aware expressions +sun -- Take screenshot under Wayland +sundialsml -- Interface to the Sundials suite of numerical solvers +svmwrap -- Wrapper on top of libsvm-tools +swagger -- Swagger 2.0 code generator for OCaml +swhid -- OCaml library to work with Software Heritage identifiers +swhid_compute -- OCaml library to work with Software Heritage identifiers, compute library used in swhid +swhid_core -- OCaml library to work with swhids +swhid_types -- OCaml library to work with Software Heritage identifiers, types library used in swhid +swipl -- Bindings to SWI-Prolog for OCaml +syguslib-utils -- SyGuS Lib parser and utils +symkat -- Symbolic Algorithms for Kleene algebra with Tests (KAT) +syncweb -- Syncweb, Literate Programming meets Unison +syndic -- RSS1, RSS2, Atom and OPML1 parsing +sys-socket -- Ctypes bindings to system-specific low-level socket structure and data-types +sys-socket-unix -- Ctypes bindings to unix-specific low-level socket structure and data-types +syslog -- syslog(3) routines for ocaml (RFC 3164) +syslog-message -- Syslog message parser +syslog-rfc5424 -- Syslog Protocol (RFC5424) parser and pretty-printer +systemverilog -- SystemVerilog for OCaml +TCSLib -- A multi-purpose library for OCaml. +tablecloth-native -- Native OCaml library implementing Tablecloth, a cross-platform standard library for OCaml, Bucklescript and ReasonML +taglib -- Bindings for the taglib library +talaria-bibtex -- A parser for bibtex files +tar 2.6.0 Decode and encode tar format files in pure OCaml +tar-mirage -- Read and write tar format files via MirageOS interfaces +tar-unix 2.6.0 Decode and encode tar format files from Unix +tcalc -- Minimal desktop calculator for timestamps +tcpip -- OCaml TCP/IP networking stack, used in MirageOS +tcx -- OCaml library for parsing and formatting Training Center XML files. +tdigest -- OCaml implementation of the T-Digest algorithm +tdk -- The Decision Kit is a collection of data structures that are useful +telegraml -- Telegram Bot API for OCaml +telltime -- Cli tool for interacting with Daypack-lib components +tensorboard -- +termbox -- Bindings for the termbox library, minimalistic API for creating text-based interfaces +terminal 0.2.1 Basic utilities for interacting with terminals +terminal_size -- Get the dimensions of the terminal +terminus -- A generic client to interact with Rest API +terminus-cohttp -- Terminus with the cohttp-lwt-unix request handler +terminus-hlc -- Terminus with the http-lwt-client request handler +testu01 -- OCaml bindings for TestU01 1.2.3 +text -- Library for dealing with "text", i.e. sequence of unicode characters, in a convenient way +text-tags -- A library for rich formatting using semantics tags +textmate-language -- Tokenizing code with TextMate grammars for syntax highlighting +textrazor -- An OCaml wrapper for the TextRazor API +textutils v0.16.0 Text output utilities +textutils_kernel v0.16.0 Text output utilities +textwrap -- Text wrapping and filling for OCaml +tezos -- Tezos meta package installing all active binaries +tezos-012-Psithaca-test-helpers -- Tezos/Protocol: protocol testing framework +tezos-013-PtJakart-test-helpers -- Tezos/Protocol: protocol testing framework +tezos-014-PtKathma-test-helpers -- Tezos/Protocol: protocol testing framework +tezos-accuser-012-Psithaca -- Tezos/Protocol: accuser binary +tezos-accuser-013-PtJakart -- Tezos/Protocol: accuser binary +tezos-accuser-014-PtKathma -- Tezos/Protocol: accuser binary +tezos-accuser-alpha -- Tezos/Protocol: accuser binary +tezos-alpha-test-helpers -- Tezos/Protocol: protocol testing framework +tezos-baker-012-Psithaca -- Tezos/Protocol: baker binary +tezos-baker-013-PtJakart -- Tezos/Protocol: baker binary +tezos-baker-014-PtKathma -- Tezos/Protocol: baker binary +tezos-baker-alpha -- Tezos/Protocol: baker binary +tezos-baking-012-Psithaca -- Tezos/Protocol: base library for `tezos-baker/accuser` +tezos-baking-012-Psithaca-commands -- Tezos/Protocol: protocol-specific commands for baking +tezos-baking-013-PtJakart -- Tezos/Protocol: base library for `tezos-baker/accuser` +tezos-baking-013-PtJakart-commands -- Tezos/Protocol: protocol-specific commands for baking +tezos-baking-014-PtKathma -- Tezos/Protocol: base library for `tezos-baker/accuser` +tezos-baking-014-PtKathma-commands -- Tezos/Protocol: protocol-specific commands for baking +tezos-baking-015-PtLimaPt -- Tezos/Protocol: base library for `tezos-baker/accuser` +tezos-baking-015-PtLimaPt-commands -- Tezos/Protocol: protocol-specific commands for baking +tezos-baking-016-PtMumbai -- Tezos/Protocol: base library for `tezos-baker/accuser` +tezos-baking-016-PtMumbai-commands -- Tezos/Protocol: protocol-specific commands for baking +tezos-baking-017-PtNairob -- Tezos/Protocol: base library for `tezos-baker/accuser` +tezos-baking-017-PtNairob-commands -- Tezos/Protocol: protocol-specific commands for baking +tezos-baking-alpha -- Tezos/Protocol: base library for `tezos-baker/accuser` +tezos-baking-alpha-commands -- Tezos/Protocol: protocol-specific commands for baking +tezos-base -- Tezos: meta-package and pervasive type definitions for Tezos +tezos-base-test-helpers -- Tezos: Tezos base test helpers +tezos-base58 -- Base58 encoding for Tezos +tezos-benchmark 18.0 Tezos: library for writing benchmarks and performing simple parameter inference +tezos-bls12-381-polynomial -- Polynomials over BLS12-381 finite field +tezos-clic -- Tezos: library of auto-documented command-line-parsing combinators +tezos-client -- Tezos: `tezos-client` binary +tezos-client-000-Ps9mPmXa -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-001-PtCJ7pwo -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-002-PsYLVpVv -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-003-PsddFKi3 -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-004-Pt24m4xi -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-005-PsBabyM1 -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-006-PsCARTHA -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-007-PsDELPH1 -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-008-PtEdo2Zk -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-009-PsFLoren -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-010-PtGRANAD -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-011-PtHangz2 -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-012-Psithaca -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-013-PtJakart -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-014-PtKathma -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-015-PtLimaPt -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-016-PtMumbai -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-017-PtNairob -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-alpha -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-base -- Tezos: common helpers for `tezos-client` +tezos-client-base-unix -- Tezos: common helpers for `tezos-client` (unix-specific fragment) +tezos-client-commands -- Tezos: protocol agnostic commands for `tezos-client` +tezos-client-demo-counter -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-client-genesis -- Tezos/Protocol: protocol specific library for `tezos-client` +tezos-codec -- Tezos: `tezos-codec` binary to encode and decode values +tezos-context -- Tezos: on-disk context abstraction for `octez-node` +tezos-context-hash -- Specification of the Tezos context hash +tezos-context-hash-irmin -- Irmin implementation of the Tezos context hash specification +tezos-context-ops -- Tezos: backend-agnostic operations on contexts +tezos-crypto -- Tezos: library with all the cryptographic primitives used by Tezos +tezos-crypto-dal -- DAL cryptographic primitives +tezos-dac-client-lib 18.0 Tezos: `tezos-dac-client` library +tezos-dac-lib 18.0 Tezos: `tezos-dac` library +tezos-dac-node-lib 18.0 Tezos: `tezos-dac-node` library +tezos-dal-node-lib 18.0 Tezos: `tezos-dal-node` library +tezos-dal-node-services 18.0 Tezos: `tezos-dal-node` RPC services +tezos-embedded-protocol-000-Ps9mPmXa -- Tezos/Protocol: 000-Ps9mPmXa (economic-protocol definition, embedded in `octez-node`) +tezos-embedded-protocol-001-PtCJ7pwo -- Tezos/Protocol: 001_PtCJ7pwo (economic-protocol definition, embedded in `octez-node`) +tezos-embedded-protocol-002-PsYLVpVv -- Tezos/Protocol: 002_PsYLVpVv (economic-protocol definition, embedded in `octez-node`) +tezos-embedded-protocol-003-PsddFKi3 -- Tezos/Protocol: 003_PsddFKi3 (economic-protocol definition, embedded in `octez-node`) +tezos-embedded-protocol-004-Pt24m4xi -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-005-PsBABY5H -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-005-PsBabyM1 -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-006-PsCARTHA -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-007-PsDELPH1 -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-008-PtEdo2Zk -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-008-PtEdoTez -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-009-PsFLoren -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-010-PtGRANAD -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-011-PtHangz2 -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-012-Psithaca -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-013-PtJakart -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-014-PtKathma -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-015-PtLimaPt -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-016-PtMumbai -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-017-PtNairob -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-alpha -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` +tezos-embedded-protocol-demo-counter -- Tezos/Protocol: demo_counter (economic-protocol definition, embedded in `octez-node`) +tezos-embedded-protocol-demo-noops -- Tezos/Protocol: demo_noops (economic-protocol definition, embedded in `octez-node`) +tezos-embedded-protocol-genesis -- Tezos/Protocol: genesis (economic-protocol definition, embedded in `octez-node`) +tezos-error-monad -- Tezos: error monad +tezos-event-logging -- Tezos event logging library +tezos-event-logging-test-helpers -- Tezos: test helpers for the event logging library +tezos-hacl -- Tezos: thin layer around hacl-star +tezos-hacl-glue -- Tezos: thin layer of glue around hacl-star (virtual package) +tezos-hacl-glue-unix -- Tezos: thin layer of glue around hacl-star (unix implementation) +tezos-injector-013-PtJakart -- Tezos/Protocol: protocol specific library building injectors +tezos-injector-014-PtKathma -- Tezos/Protocol: protocol specific library building injectors +tezos-injector-015-PtLimaPt -- Tezos/Protocol: protocol specific library building injectors +tezos-injector-016-PtMumbai -- Tezos/Protocol: protocol specific library building injectors +tezos-injector-alpha -- Tezos/Protocol: protocol specific library building injectors +tezos-layer2-store -- Tezos: layer2 storage utils +tezos-layer2-utils-016-PtMumbai -- Tezos/Protocol: protocol specific library for Layer 2 utils +tezos-layer2-utils-017-PtNairob -- Tezos/Protocol: protocol specific library for Layer 2 utils +tezos-lazy-containers -- A collection of lazy containers whose contents is fetched from arbitrary backend on-demand +tezos-lmdb -- Legacy Tezos OCaml binding to LMDB (Consider ocaml-lmdb instead) +tezos-lwt-result-stdlib 17.3 Tezos: error-aware stdlib replacement +tezos-micheline -- Tezos: internal AST and parser for the Michelson language +tezos-micheline-rewriting -- Tezos: library for rewriting Micheline expressions +tezos-mockup -- Tezos: library of auto-documented RPCs (mockup mode) +tezos-mockup-commands -- Tezos: library of auto-documented RPCs (commands) +tezos-mockup-proxy -- Tezos: local RPCs +tezos-mockup-registration -- Tezos: protocol registration for the mockup mode +tezos-node -- Tezos: `tezos-node` binary +tezos-p2p -- Tezos: library for a pool of P2P connections +tezos-p2p-services -- Tezos: descriptions of RPCs exported by `tezos-p2p` +tezos-plompiler -- Library to write arithmetic circuits for Plonk +tezos-plonk -- Plonk zero-knowledge proving system +tezos-protocol-000-Ps9mPmXa 18.0 Tezos protocol 000-Ps9mPmXa package +tezos-protocol-001-PtCJ7pwo 18.0 Tezos protocol 001-PtCJ7pwo package +tezos-protocol-002-PsYLVpVv 18.0 Tezos protocol 002-PsYLVpVv package +tezos-protocol-003-PsddFKi3 18.0 Tezos protocol 003-PsddFKi3 package +tezos-protocol-004-Pt24m4xi 18.0 Tezos protocol 004-Pt24m4xi package +tezos-protocol-005-PsBABY5H 18.0 Tezos protocol 005-PsBABY5H package +tezos-protocol-005-PsBabyM1 18.0 Tezos protocol 005-PsBabyM1 package +tezos-protocol-006-PsCARTHA 18.0 Tezos protocol 006-PsCARTHA package +tezos-protocol-007-PsDELPH1 18.0 Tezos protocol 007-PsDELPH1 package +tezos-protocol-008-PtEdo2Zk 18.0 Tezos protocol 008-PtEdo2Zk package +tezos-protocol-008-PtEdoTez 18.0 Tezos protocol 008-PtEdoTez package +tezos-protocol-009-PsFLoren 18.0 Tezos protocol 009-PsFLoren package +tezos-protocol-010-PtGRANAD 18.0 Tezos protocol 010-PtGRANAD package +tezos-protocol-011-PtHangz2 18.0 Tezos protocol 011-PtHangz2 package +tezos-protocol-012-Psithaca 18.0 Tezos protocol 012-Psithaca package +tezos-protocol-013-PtJakart 18.0 Tezos protocol 013-PtJakart package +tezos-protocol-014-PtKathma 18.0 Tezos protocol 014-PtKathma package +tezos-protocol-015-PtLimaPt 18.0 Tezos protocol 015-PtLimaPt package +tezos-protocol-016-PtMumbai 18.0 Tezos protocol 016-PtMumbai package +tezos-protocol-017-PtNairob 18.0 Tezos protocol 017-PtNairob package +tezos-protocol-018-Proxford 18.0 Tezos protocol 018-Proxford package +tezos-protocol-alpha 18.0 Tezos protocol alpha package +tezos-protocol-compiler -- Tezos: economic-protocol compiler +tezos-protocol-demo-counter -- Tezos protocol demo-counter package +tezos-protocol-demo-noops -- Tezos protocol demo-noops package +tezos-protocol-environment -- Interface layer between the protocols and the shell +tezos-protocol-environment-packer -- Tezos: sigs/structs packer for economic protocol environment +tezos-protocol-environment-sigs -- Tezos: restricted typing environment for the economic protocols +tezos-protocol-environment-structs -- Tezos: restricted typing environment for the economic protocols +tezos-protocol-genesis -- Tezos protocol genesis package +tezos-protocol-plugin-007-PsDELPH1 -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-007-PsDELPH1-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-008-PtEdo2Zk -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-008-PtEdo2Zk-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-009-PsFLoren -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-009-PsFLoren-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-010-PtGRANAD -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-010-PtGRANAD-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-011-PtHangz2 -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-011-PtHangz2-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-012-Psithaca -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-012-Psithaca-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-012-Psithaca-tests -- Tezos/Protocol: protocol plugin tests +tezos-protocol-plugin-013-PtJakart -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-013-PtJakart-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-013-PtJakart-tests -- Tezos/Protocol: protocol plugin tests +tezos-protocol-plugin-014-PtKathma -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-014-PtKathma-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-015-PtLimaPt -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-015-PtLimaPt-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-016-PtMumbai -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-016-PtMumbai-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-017-PtNairob -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-017-PtNairob-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-alpha -- Tezos/Protocol: protocol plugin +tezos-protocol-plugin-alpha-registerer -- Tezos/Protocol: protocol plugin registerer +tezos-protocol-plugin-alpha-tests -- Tezos/Protocol: protocol plugin tests +tezos-protocol-updater -- Tezos: economic-protocol dynamic loading for `octez-node` +tezos-proxy -- Tezos: proxy +tezos-proxy-server -- Tezos: `tezos-proxy-server` binary +tezos-proxy-server-config 18.0 Tezos: proxy server configuration +tezos-requester -- Tezos: generic resource fetching service +tezos-rpc -- Tezos: library of auto-documented RPCs (service and hierarchy descriptions) +tezos-rpc-http -- Tezos: library of auto-documented RPCs (http server and client) +tezos-rpc-http-client -- Tezos: library of auto-documented RPCs (http client) +tezos-rpc-http-client-unix -- Tezos: unix implementation of the RPC client +tezos-rpc-http-server -- Tezos: library of auto-documented RPCs (http server) +tezos-rust-libs 1.6 Tezos: all rust dependencies and their dependencies +tezos-sapling -- OCaml library for the Sapling protocol, using librustzcash +tezos-sapling-parameters 1.1.0 Sapling parameters used in Tezos +tezos-scoru-wasm -- Protocol environment dependency providing WASM functionality for SCORU +tezos-scoru-wasm-fast -- WASM functionality for SCORU Fast Execution +tezos-scoru-wasm-helpers -- Helpers for the smart rollup wasm functionality and debugger +tezos-shell -- Tezos: core of `octez-node` (gossip, validation scheduling, mempool, ...) +tezos-shell-context -- Tezos: economic-protocols environment implementation for `octez-node` +tezos-shell-context-test -- Testing the Shell Context +tezos-shell-services -- Tezos: descriptions of RPCs exported by `tezos-shell` +tezos-shell-services-test-helpers -- Tezos: Tezos shell_services test helpers +tezos-signer -- Tezos: `tezos-signer` binary +tezos-signer-backends -- Tezos: remote-signature backends for `tezos-client` +tezos-signer-services -- Tezos: descriptions of RPCs exported by `tezos-signer` +tezos-smart-rollup-016-PtMumbai -- Tezos/Protocol: protocol specific library of helpers for `tezos-smart-rollup` +tezos-smart-rollup-017-PtNairob -- Tezos/Protocol: protocol specific library of helpers for `tezos-smart-rollup` +tezos-smart-rollup-alpha -- Tezos/Protocol: protocol specific library of helpers for `tezos-smart-rollup` +tezos-smart-rollup-layer2-016-PtMumbai -- Tezos/Protocol: protocol specific library for `tezos-smart-rollup` +tezos-smart-rollup-layer2-017-PtNairob -- Tezos/Protocol: protocol specific library for `tezos-smart-rollup` +tezos-stdlib -- Tezos: yet-another local-extension of the OCaml standard library +tezos-stdlib-unix -- Tezos: yet-another local-extension of the OCaml standard library (unix-specific fragment) +tezos-store -- Tezos: store for `octez-node` +tezos-test-helpers -- Tezos-agnostic test helpers +tezos-test-helpers-extra -- Test helpers dependent on tezos-base +tezos-test-services -- Tezos: Alcotest-based test services +tezos-tree-encoding -- A general-purpose library to encode arbitrary data in Merkle trees +tezos-tx-rollup-013-PtJakart -- Tezos/Protocol: protocol specific library for `tezos-tx-rollup` +tezos-tx-rollup-014-PtKathma -- Tezos/Protocol: protocol specific library for `tezos-tx-rollup` +tezos-tx-rollup-015-PtLimaPt -- Tezos/Protocol: protocol specific library for `tezos-tx-rollup` +tezos-tx-rollup-alpha -- Tezos/Protocol: protocol specific library for `tezos-tx-rollup` +tezos-tx-rollup-client-013-PtJakart -- Tezos/Protocol: `tezos-tx-rollup-client-alpha` client binary +tezos-tx-rollup-client-014-PtKathma -- Tezos/Protocol: `tezos-tx-rollup-client-alpha` client binary +tezos-tx-rollup-client-alpha -- Tezos/Protocol: `tezos-tx-rollup-client-alpha` client binary +tezos-tx-rollup-node-013-PtJakart -- Tezos/Protocol: Transaction Rollup node binary +tezos-tx-rollup-node-014-PtKathma -- Tezos/Protocol: Transaction Rollup node binary +tezos-tx-rollup-node-alpha -- Tezos/Protocol: Transaction Rollup node binary +tezos-validation -- Tezos: library for block validation +tezos-validator -- Tezos: `tezos-validator` binary for external validation of blocks +tezos-version -- Tezos: version information generated from Git +tezos-wasmer -- Wasmer bindings for SCORU WASM +tezos-webassembly-interpreter -- WebAssembly reference interpreter with tweaks for Tezos +tezos-webassembly-interpreter-extra -- Additional modules from the WebAssembly REPL used in testing +tezos-workers -- Tezos: worker library +tezt 3.1.1 Test framework for unit tests, integration tests, and regression tests +tezt-performance-regression -- Performance regression test framework based on Tezt +tezt-tezos 18.0 Octez test framework based on Tezt +tgls 0.8.6 Thin bindings to OpenGL {3,4} and OpenGL ES {2,3} for OCaml +theora -- Bindings to libtheora +thread-table -- A lock-free thread-safe integer keyed hash table +thrift -- OCaml bindings for the Apache Thrift RPC system +tidy -- Bindings for libtidy5 -- HTML/XML syntax checker and reformatter +tidy_email -- An OCaml library that simplifies connecting to email services +tidy_email_mailgun -- An OCaml library that simplifies connecting to Mailgun's REST API +tidy_email_sendgrid -- An OCaml library that simplifies connecting to Sendgrid's REST API +tidy_email_smtp -- An OCaml library that simplifies connecting to SMTP servers +tilde_f -- Provides a let-syntax for continuation-passing style. +time_now v0.16.0 Reports the current time +timed -- Timed references for imperative state +timedesc -- OCaml date time handling library +timedesc-json -- Timedesc JSON backend +timedesc-sexp -- Timedesc Sexp backend +timedesc-tzdb -- Virtual library for Timedesc time zone database backends +timedesc-tzlocal -- Virtual library for Timedesc local time zone detection backends +timedesc-tzlocal-js -- JS implementation for timedesc-tzlocal +timere -- OCaml date time reasoning library +timere-parse -- OCaml date time and duration natural language parsing library +timezone v0.16.0 Time-zone handling +timmy -- Time and calendar library +timmy-jsoo -- Js_of_ocaml bindings for Timmy +timmy-unix -- Unix clock implementation for Timmy +tiny_httpd -- Minimal HTTP server using good old threads +tiny_httpd_camlzip -- Interface to camlzip for tiny_httpd +tiny_json -- A small Json library from OCAMLTTER +tip-parser -- Parser for https://tip-org.github.io/format.html +tjr_simple_earley -- An implementation of an Earley-like algorithm, designed for simplicity. +tldr -- An ocaml tldr client +tls 0.17.1 Transport Layer Security purely in OCaml +tls-async -- Transport Layer Security purely in OCaml, Async layer +tls-liquidsoap -- Virtual package install liquidosap dependencies for TLS optional features +tls-lwt 0.17.1 Transport Layer Security purely in OCaml, Lwt layer +tls-mirage -- Transport Layer Security purely in OCaml, MirageOS layer +toc -- A generator of table of contents for Github Markdown files +tofn -- Typed ordered fuzzy numbers +togglelog -- A ppx for compile-time-optional logging +toml -- Library for TOML with a parser, a serializer and a printer +toml-cconv -- Interface between cconv and toml +toml_cconv -- Interface between cconv and toml +tophide -- Hides toplevel values whose name starts with an underscore +topiary -- A formatter for OCaml based on the Topiary universal formatting engine +topkg 1.0.7 The transitory OCaml software packager +topkg-care -- The transitory OCaml software packager +topkg-jbuilder -- Helpers for using topkg with jbuilder +toplevel_backend -- Shared backend for setting up toplevels +toplevel_expect_test -- Expectation tests for the OCaml toplevel +topojson -- A pure OCaml library for working with the TopoJSON format +topological_sort -- Topological sort algorithm +torch -- Torch bindings for OCaml +touist -- The solver for the Touist language +tplib -- TPLib: Tropical Polyhedra Library +tptp -- Library for reading and writing FOF and CNF formulas in TPTP format +tqdm -- OCaml library for progress bars +trace -- A stub for tracing/observability, agnostic in how data is collected +trace-tef -- A simple backend for trace, emitting Catapult/TEF JSON into a file +tracing -- Tracing library +tracy-client -- Client bindings to the Tracy profiler (v0.9.1) +traildb -- OCaml bindings for TrailDB. +traits -- Common traits for generic functionality +trampoline -- A trampoline library enabling deep recursions that don't fit into stack memory +transept -- Generalized parser combinator library +traverse -- Traversable data structures with applicative functors +travesty -- Traversable containers, monad extensions, and more +travis-opam -- Scripts for OCaml projects +trax -- Stack-independent exception tracing +tree_layout -- Algorithms to layout trees in a pretty manner +treeprint -- Printing combinator library with automatic parenthese +trexio -- Binding for the TREXIO Input/Output library +trie -- Strict impure trie tree +tsdl 1.0.0 Thin bindings to SDL for OCaml +tsdl-image -- SDL2_Image bindings to go with Tsdl +tsdl-mixer -- SDL2_Mixer bindings to go with Tsdl +tsdl-ttf -- SDL2_Ttf bindings to go with Tsdl +tsort -- Easy to use and user-friendly topological sort +ttweetnacl -- Thin bindings to TweetNaCl cryptography for OCaml +tuareg -- OCaml mode for GNU Emacs +tube -- Typesafe abstraction on top of Lwt_io channels +tuntap -- OCaml library for handling TUN/TAP devices +twostep -- HOTP and TOTP algorithms for 2-step verification (for OCaml) +tyabt -- Strongly typed many-sorted abstract binding trees (ABTs) +type_conv -- Library for building type-driven syntax extensions +typebeat -- Agnostic parser of the `Content-Type` in OCaml +typerep v0.16.0 Typerep is a library for runtime types +typeset -- An embedded DSL for defining source code pretty printers +tyre -- Typed Regular Expressions +tyxml 4.6.0 A library for building correct HTML and SVG documents +tyxml-jsx -- JSX syntax to write TyXML documents +tyxml-lwd -- Make reactive webpages in Js_of_ocaml using Tyxml and Lwd +tyxml-ppx -- PPX to write TyXML documents with the HTML syntax +tyxml-syntax -- Common layer for the JSX and PPX syntaxes for Tyxml +u2f -- Universal Second Factor (U2F) implementation in OCaml +ubase -- Remove diacritics from latin utf8 strings +ubpf -- OCaml bindings for userspace eBPF VM +ucaml -- Translate OCaml code into C code +uchar -- Compatibility library for OCaml's Uchar module +uecc -- Bindings for ECDH and ECDSA for 8-bit, 32-bit, and 64-bit processors +uint -- Deprecated: An unsigned integer library +ulex -- lexer generator for Unicode and OCaml +ulex-camlp5 -- A lexer generator for Unicode (backported to camlp5) +ulid -- ULIDs for OCaml +um-abt -- An OCaml library implementing unifiable abstract binding trees (UABTs) +unidecode -- Convert unicode strings into its ASCII representation +unionFind -- Implementations of the union-find data structure +unisim_archisec -- UNISIM-VP DBA decoder +unison -- File-synchronization tool for Unix and Windows +universo -- A tool for Dedukti to play with universes +unix-dirent -- ocaml-unix-dirent provides access to the features exposed in dirent.h +unix-errno -- Unix errno types, maps, and support +unix-sys-resource -- Unix sys/resource.h types and bindings (getrlimit, setrlimit, and friends) +unix-sys-stat -- ocaml-unix-sys-stat provides access to the features exposed in sys/stat.h +unix-time -- Unix time.h types, maps, and support +unix-type-representations -- Functions that expose the underlying types of some abstract types in the Unix module +unix-unistd -- Host-independent unistd.h bindings +unstrctrd 0.3 Unstructured parser +uri 4.4.0 An RFC3986 URI/URL parsing library +uri-bench -- Benchmarking package for ocaml-uri +uri-re -- An RFC3986 URI/URL parsing library +uri-sexp 4.4.0 An RFC3986 URI/URL parsing library +uring -- OCaml bindings for Linux io_uring +uritemplate -- OCaml implementation of URI templates (RFC6570) +usb -- OCaml bindings for libusb-1.0 +user-agent-parser -- OCaml implementation of the user agent parse rules of uap-core +user-setup -- Helper for the configuration of editors for the use of OCaml tools +username_kernel -- An identifier for a user +uspf -- SPF implementation in OCaml +uspf-lwt -- SPF implementation in OCaml (with LWT) +uspf-unix -- SPF implementation in OCaml +utop -- Universal toplevel for OCaml +uucd 15.1.0 Unicode character database decoder for OCaml +uucp 15.1.0 Unicode character properties for OCaml +uuidm 0.9.8 Universally unique identifiers (UUIDs) for OCaml +uunf 15.1.0 Unicode text normalization for OCaml +uuseg 15.1.0 Unicode text segmentation for OCaml +uutf 1.0.3 Non-blocking streaming Unicode codec for OCaml +uuuu -- Mapper of ISO-8859-* to Unicode +valentine -- Validate HTML from command line +validator -- Create a record validator via composable sub-validators +variantslib v0.16.0 Part of Jane Street's Core library +varint -- A simple varint implementation modeled after the one found in Go's standard library. +varray -- Resizable arrays with fast insertion/deletion +vcaml -- OCaml bindings for the Neovim API +vcardgen -- Simple OCaml library for generating VCards per RFC-6350 +vchan -- Xen Vchan implementation +vchan-unix -- Xen Vchan implementation +vchan-xen -- Xen Vchan implementation +vdom -- DOM and VDOM for OCaml +vec -- Fast, safe mutable dynamic arrays +vecosek -- +vecosek-engine -- +vecosek-scene -- +vector 1.0.0 Resizable Arrays +vector3 1.0.0 Module for 3D vectors (implemented as records of x, y and z floats) +vendredi -- Tool for generating dune projects which vendor given packages for the purpose of testing that their dependencies are vendor-friendly +vercel -- A custom runtime for Vercel.com (Now v2) written in OCaml +vg 0.9.4 Declarative 2D vector graphics for OCaml +vhd-format -- Pure OCaml library to read/write VHD format data +vhd-format-lwt -- Lwt interface to read/write VHD format data +vhdlib -- Bindings to libvhd +virtual_dom -- OCaml bindings for the virtual-dom library +visitors -- An OCaml syntax extension for generating visitor classes +vlq -- A simple library for encoding variable-length quantities +vlt -- A variant of Bolt logging tool +voaacenc -- Bindings for the voaacenc library to encode audio files in AAC format +vocal -- VOCaL -- The Verified OCaml Library +volt -- Volt is a variant of Bolt OCaml Logging Tool +voqc -- A verified optimizer for quantum circuits (VOQC) +vorbis -- Bindings to libvorbis +vpt -- Vantage point tree implementation in OCaml +vscoq-language-server -- VSCoq language server +vue-jsoo -- Binding of Vue_js +vue-ppx -- Ppx to make Vue.js application +wall -- Realtime Vector Graphics with OpenGL +wamp -- Web Application Messaging Protocol (WAMP) library — Core library +wamp-msgpck -- Web Application Messaging Protocol (WAMP) library — Msgpck support +wamp-yojson -- Web Application Messaging Protocol (WAMP) library — Yojson support +wasm -- Library to read and write WebAssembly (Wasm) files and manipulate their AST +wasmer -- OCaml bindings for Wasmer +wasmtime -- Wasmtime bindings for OCaml +wayland -- Pure OCaml Wayland protocol library +waylaunch -- Waylaunch is a program launcher for Wayland +wcs-lib -- SDK for Watson Conversation Service +webauthn -- WebAuthn - authenticating users to services using public key cryptography +webbrowser 0.6.1 Open and reload URIs in browsers from OCaml +weberizer -- Compile HTML templates into OCaml modules +webidl -- Web IDL parser +webmachine -- A REST toolkit for OCaml +websocket -- Websocket library +websocket-async -- Websocket library (Async) +websocket-lwt -- Websocket library (Lwt) +websocket-lwt-unix -- Websocket library (Lwt) +websocketaf -- Websocket implementation for use with http/af +websocketml -- A simple websocket library for OCaml with no dependency +webtest -- An in-browser js_of_ocaml testing framework - core library +webtest-js -- An in-browser js_of_ocaml testing framework - js_of_ocaml integration +weevil -- Tezos: `weevil` binary - a tool for debugging Michelson code +why3 -- Why3 environment for deductive program verification +why3-coq -- Why3 environment for deductive program verification +why3-ide -- Why3 environment for deductive program verification +wikitext -- Wikitext parser +win-error -- Manipulate Windows system errors +win-eventlog -- Log via the Windows event log from OCaml programs +wiringpi -- WiringPi for OCaml, low level Raspberry Pi hardware access +ws-server -- WebSocket server +wseg -- A word identification system +wtf8 -- Encoder and decoder for WTF-8 +wtr -- Well Typed Router +wtr-ppx -- Ppx to create routers +wu-manber-fuzzy-search -- Wu-Manber approximate string matching +wyrd -- Text-based front-end to Remind, a sophisticated calendar and alarm program +x509 0.16.5 Public Key Infrastructure (RFC 5280, PKCS) purely in OCaml +xapi-backtrace -- A simple library for recording and managing backtraces +xapi-inventory -- Library for accessing the xapi toolstack inventory file +xapi-rrd -- RRD library for use with xapi +xapi-stdext-date -- Xapi's standard library extension, Dates +xapi-stdext-encodings -- Xapi's standard library extension, Encodings +xapi-stdext-pervasives -- Xapi's standard library extension, Pervasives +xapi-stdext-std -- Xapi's standard library extension, Stdlib +xapi-stdext-threads -- Xapi's standard library extension, Threads +xapi-stdext-unix -- Xapi's standard library extension, Unix +xapi-stdext-zerocheck -- Xapi's standard library extension, Zerocheck +xcursor -- A pure implementation of Xcursor in OCaml +xdg 3.11.1 XDG Base Directory Specification +xdg-basedir -- XDG basedir location for data/cache/configuration files +xen-evtchn -- Xen event channel interface for MirageOS +xen-evtchn-unix -- Xen event channel interface for Linux +xen-gnt -- Xen grant table bindings for OCaml +xen-gnt-unix -- Xen grant table bindings for OCaml +xenstore -- Xenstore protocol in pure OCaml +xenstore_transport -- Low-level libraries for connecting to a xenstore service on a xen host +xmelly -- Simplest way to do simple parsing of simple XML files in OCaml +xml-light -- Xml-Light is a minimal XML parser & printer for OCaml +xmldiff -- Computing and applying diffs on XML trees +xmldiff_js -- Using Xmldiff on DOM +xmlm 1.4.0 Streaming XML codec for OCaml +xmlplaylist -- Library to parse various file playlists in XML format +xoshiro -- Xoshiro PRNGs as drop-in replacements for Stdlib.Random +xtmpl -- Xml templating library +xtmpl_js -- Xml templating library, javascript library +xtmpl_ppx -- Xml templating library, ppx extension +xxhash -- Bindings for xxHash, an extremely fast hash algorithm +yajl -- Bindings to the YAJL streaming JSON library +yaml 3.1.0 Parse and generate YAML 1.1/1.2 files +yaml-sexp -- Parse and generate YAML 1.1 files +yices2 -- Yices2 SMT solver binding +yices2_bindings -- Ocaml bindings for yices2 +yojson 2.1.1 Yojson is an optimized parsing and printing library for the JSON format +yojson-bench -- Run Yojson benchmarks +yurt -- An HTTP framework for OCaml +yuscii -- Mapper of UTF-7 to Unicode +yuujinchou -- Name pattern combinators +z3 -- Z3 solver +z3_tptp -- TPTP front end for Z3 solver +zanuda -- OCaml linter experiment +zar -- Formally verified sampling from discrete probability distributions +zarith 1.12 Implements arithmetic and logical operations over arbitrary-precision integers +zarith-freestanding -- Implements arithmetic and logical operations over arbitrary-precision integers +zarith-xen -- Implements arithmetic and logical operations over arbitrary-precision integers +zarith_stubs_js v0.16.0 Javascripts stubs for the Zarith library +zed -- Abstract engine for text edition in OCaml +zeit -- +zelus -- A synchronous language with ODEs +zelus-gtk -- Zelus GTK library +zenon -- An Extensible Automated Theorem Prover Producing Checkable Proofs +zipperposition -- A fully automatic theorem prover for typed higher-order and beyond +zipperposition-tools -- Support tools for Zipperposition +zlib -- Bindings to the zlib compression library +zlist -- Lazy lists for OCaml +zmq -- OCaml bindings for ZeroMQ 4.x +zmq-async -- Async-aware bindings to ZMQ +zmq-lwt -- Lwt-aware bindings to ZMQ +zstandard -- OCaml bindings to Zstandard +zstd -- Bindings to zstd compression library +zxcvbn -- Bindings for the zxcvbn password strength estimation library diff --git a/sherlodoc-www.opam b/sherlodoc-www.opam index 2075e9e081..e374d66659 100644 --- a/sherlodoc-www.opam +++ b/sherlodoc-www.opam @@ -9,13 +9,11 @@ bug-reports: "https://github.com/art-w/sherlodoc/issues" depends: [ "ocaml" {>= "4.14.0"} "dune" {>= "2.9"} + "sherlodoc" "ancient" "dream" - "fpath" - "odoc" - "opam-core" - "tyxml" "alcotest" {with-test} + "odoc" {with-doc} ] build: [ ["dune" "subst"] {dev} diff --git a/sherlodoc.opam b/sherlodoc.opam index 5237687f96..9d39533b74 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -9,11 +9,14 @@ bug-reports: "https://github.com/art-w/sherlodoc/issues" depends: [ "ocaml" {>= "4.14.0"} "dune" {>= "2.9"} - "dream" + "decompress" + "bigstringaf" + "base64" + "lwt" "fpath" "odoc" "opam-core" - "tyxml" + "tyxml" {>= "4.6.0"} "brr" "alcotest" {with-test} ] From c8aeb6b241a9026d7edc57dba2837829b5595c46 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 4 Dec 2023 14:28:41 +0100 Subject: [PATCH 151/285] add dependency bounds to opam file --- dune-project | 29 ++++++++++++++++++++--------- sherlodoc-www.opam | 4 ++-- sherlodoc.opam | 14 +++++++------- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/dune-project b/dune-project index 499e55ecd5..e9eaf30f26 100644 --- a/dune-project +++ b/dune-project @@ -24,14 +24,23 @@ (ocaml (>= 4.14.0)) dune - decompress - bigstringaf - base64 - fpath + (decompress + (>= 1.5.3)) + (bigstringaf + (>= 0.9.1)) + (base64 + (>= 3.5.1)) + (lwt + (>= 5.7.0)) + (fpath + (>= 0.7.3)) odoc - opam-core - (tyxml (>= 4.6.0)) - brr + (opam-core + (>= 2.1.5)) + (tyxml + (>= 4.6.0)) + (brr + (>= 0.0.6)) (alcotest :with-test))) (package @@ -42,6 +51,8 @@ (>= 4.14.0)) dune sherlodoc - ancient - dream + (ancient + (>= 0.9.1)) + (dream + (>= 1.0.0~alpha5)) (alcotest :with-test))) diff --git a/sherlodoc-www.opam b/sherlodoc-www.opam index e374d66659..9894aab933 100644 --- a/sherlodoc-www.opam +++ b/sherlodoc-www.opam @@ -10,8 +10,8 @@ depends: [ "ocaml" {>= "4.14.0"} "dune" {>= "2.9"} "sherlodoc" - "ancient" - "dream" + "ancient" {>= "0.9.1"} + "dream" {>= "1.0.0~alpha5"} "alcotest" {with-test} "odoc" {with-doc} ] diff --git a/sherlodoc.opam b/sherlodoc.opam index 9d39533b74..a5277d2f4d 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -9,15 +9,15 @@ bug-reports: "https://github.com/art-w/sherlodoc/issues" depends: [ "ocaml" {>= "4.14.0"} "dune" {>= "2.9"} - "decompress" - "bigstringaf" - "base64" - "lwt" - "fpath" + "decompress" {>= "1.5.3"} + "bigstringaf" {>= "0.9.1"} + "base64" {>= "3.5.1"} + "lwt" {>= "5.7.0"} + "fpath" {>= "0.7.3"} "odoc" - "opam-core" + "opam-core" {>= "2.1.5"} "tyxml" {>= "4.6.0"} - "brr" + "brr" {>= "0.0.6"} "alcotest" {with-test} ] build: [ From 6c6dda7bed158ad50d17b5586e403565b9232bc3 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 4 Dec 2023 14:37:27 +0100 Subject: [PATCH 152/285] fix extensiondecl case in pretty --- index/pretty.ml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index/pretty.ml b/index/pretty.ml index 44ed4c5d3c..14c6ed81a8 100644 --- a/index/pretty.ml +++ b/index/pretty.ml @@ -1,4 +1,4 @@ -(** This file contains useful printer, that are however of dubious +(** This file contains useful printer, that are however of dubious maintainability. Their result is used to be parsed afteward, it is not printed but consumed as the basis for type-search. Because of this it is sensitive code. *) @@ -118,7 +118,8 @@ let rec full_name_aux : Paths.Identifier.t -> string list = | `SourceLocationMod id -> full_name_aux (id :> t) | `SourceLocationInternal (parent, name) -> LocalName.to_string name :: full_name_aux (parent :> t) - | `ExtensionDecl _ -> failwith "todo" + | `ExtensionDecl (parent, name, _) -> + ExtensionName.to_string name :: full_name_aux (parent :> t) let fullname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string list = fun n -> List.rev @@ full_name_aux (n :> Paths.Identifier.t) From 4ad17fad3029dc37f98a5f2e6f1db0c676fc6e93 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 4 Dec 2023 14:37:44 +0100 Subject: [PATCH 153/285] fmt --- query/dune | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/query/dune b/query/dune index 863f1b1a6e..272e4e5a00 100644 --- a/query/dune +++ b/query/dune @@ -2,6 +2,7 @@ (name query) (libraries lwt re db)) -(menhir (modules parser)) +(menhir + (modules parser)) (ocamllex lexer) From 762cd32f2f4128453b6c62154fe7dd911057fcb7 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 4 Dec 2023 15:06:06 +0100 Subject: [PATCH 154/285] test on switch --- test/whole_switch/.gitignore | 1 + test/whole_switch/readme.md | 11 + test/whole_switch/setup_big_switch.sh | 436 ++++++++++++++++++++++++++ test/whole_switch/test.sh | 8 + 4 files changed, 456 insertions(+) create mode 100644 test/whole_switch/.gitignore create mode 100644 test/whole_switch/readme.md create mode 100644 test/whole_switch/setup_big_switch.sh create mode 100644 test/whole_switch/test.sh diff --git a/test/whole_switch/.gitignore b/test/whole_switch/.gitignore new file mode 100644 index 0000000000..f9ced93c2f --- /dev/null +++ b/test/whole_switch/.gitignore @@ -0,0 +1 @@ +packages diff --git a/test/whole_switch/readme.md b/test/whole_switch/readme.md new file mode 100644 index 0000000000..aa43e6e575 --- /dev/null +++ b/test/whole_switch/readme.md @@ -0,0 +1,11 @@ +This is directory meants for test on a whole switch. We only test that we can +actually build a documentation database in for every package. We do not check +that the results of search are good, because we do not have a definition of that +for any package. + +It has two scripts : + +- `set_big_switch.sh` installs a lot of compatible packages in the current + switch. +- `test.sh` generates the search database of every installed package. Its output + is in the `packages` folder. \ No newline at end of file diff --git a/test/whole_switch/setup_big_switch.sh b/test/whole_switch/setup_big_switch.sh new file mode 100644 index 0000000000..5411f1553d --- /dev/null +++ b/test/whole_switch/setup_big_switch.sh @@ -0,0 +1,436 @@ +opam install +absolute.0.3 +accessor.v0.16.0 +aches.1.0.0 +aches-lwt.1.0.0 +acp4.1.0.1 +alcotest.1.7.0 +alsa.0.3.0 +alt-ergo.2.5.2 +alt-ergo-lib.2.5.2 +alt-ergo-parsers.2.5.2 +ancient.0.9.1 +angstrom.0.15.0 +apron.v0.9.14 +apronext.1.0.4 +arrakis.1.0.0 +art.0.2.0 +asetmap.0.8.1 +asn1-combinators.0.2.6 +astring.0.8.5 +async.v0.16.0 +async_kernel.v0.16.0 +async_rpc_kernel.v0.16.0 +async_unix.v0.16.0 +async_websocket.v0.16.0 +b0.0.0.5 +base.v0.16.3 +base-bigarray.base +base-bytes.base +base-threads.base +base-unix.base +base64.3.5.1 +base_bigstring.v0.16.0 +base_quickcheck.v0.16.0 +batteries.3.7.1 +bheap.2.0.0 +bigarray-compat.1.1.0 +bigarray-overlap.0.2.1 +bigstring.0.3 +bigstringaf.0.9.1 +bin_prot.v0.16.0 +bls12-381.18.0 +bos.0.2.1 +brr.0.0.6 +bst.7.0.1 +ca-certs.0.2.3 +camlidl.1.11 +camlp-streams.5.0.1 +camlzip.1.11 +caqti.1.9.0 +caqti-lwt.1.9.0 +checkseum.0.5.2 +chrome-trace.3.11.1 +class_group_vdf.0.0.4 +cmdliner.1.2.0 +cohttp.5.3.0 +cohttp-lwt.5.3.0 +cohttp-lwt-unix.5.3.0 +conduit.6.2.0 +conduit-lwt.6.2.0 +conduit-lwt-unix.6.2.0 +conf-alsa.1 +conf-autoconf.0.1 +conf-cmake.1 +conf-g++.1.0 +conf-gmp.4 +conf-gmp-powm-sec.3 +conf-hidapi.0 +conf-libev.4-12 +conf-libffi.2.0.0 +conf-libssl.4 +conf-mpfr.3 +conf-perl.2 +conf-pkg-config.3 +conf-rust.0.1 +conf-rust-2021.1 +conf-sdl2.1 +conf-which.1 +conf-zlib.1 +core.v0.16.2 +core_kernel.v0.16.0 +core_unix.v0.16.0 +cpm.12.2.0 +cppo.1.6.9 +cpu.2.0.0 +cryptokit.1.16.1 +csexp.1.5.2 +cstruct.6.2.0 +cstruct-lwt.6.2.0 +ctypes.0.20.2 +ctypes-foreign.0.18.0 +ctypes_stubs_js.0.1 +data-encoding.0.7.1 +decompress.1.5.3 +digestif.1.1.4 +dolmen.0.9 +dolmen_loop.0.9 +dolmen_type.0.9 +dolog.6.0.0 +domain-name.0.4.0 +dream.1.0.0~alpha5 +dream-httpaf.1.0.0~alpha2 +dream-pure.1.0.0~alpha2 +dune.3.10.0 +dune-build-info.3.11.1 +dune-configurator.3.11.1 +dune-private-libs.3.11.1 +dune-rpc.3.11.1 +dune-site.3.11.1 +duration.0.2.1 +dyn.3.11.1 +either.1.0.0 +eqaf.0.9 +expect_test_helpers_core.v0.16.0 +ezjsonm.1.3.0 +faraday.0.8.2 +faraday-lwt.0.8.2 +faraday-lwt-unix.0.8.2 +fiber.3.7.0 +fieldslib.v0.16.0 +fix.20230505 +fmlib.0.5.6 +fmlib_browser.0.5.6 +fmlib_js.0.5.6 +fmlib_parse.0.5.6 +fmlib_pretty.0.5.6 +fmlib_std.0.5.6 +fmt.0.9.0 +fpath.0.7.3 +gen.1.1 +gg.1.0.0 +gmap.0.3.0 +graphql.0.14.0 +graphql-lwt.0.14.0 +graphql_parser.0.14.0 +hacl-star.0.7.1 +hacl-star-raw.0.7.1 +hashcons.1.3 +hex.1.5.0 +hidapi.1.1.2 +higher_kinded.v0.16.0 +hkdf.1.0.4 +hmap.0.8.1 +htmlit.0.1.0 +index.1.6.1 +int_repr.v0.16.0 +integers.0.7.0 +integers_stubs_js.1.0 +ipaddr.5.5.0 +ipaddr-sexp.5.5.0 +irmin.3.7.2 +irmin-pack.3.7.2 +jane-street-headers.v0.16.0 +js_of_ocaml.5.4.0 +js_of_ocaml-compiler.5.4.0 +js_of_ocaml-ppx.5.4.0 +js_of_ocaml-toplevel.5.4.0 +json-data-encoding.0.12.1 +json-data-encoding-bson.0.12.1 +jsonm.1.0.2 +jst-config.v0.16.0 +ke.0.6 +ledgerwallet.0.3.0 +ledgerwallet-tezos.0.3.0 +libabsolute.0.1 +line_oriented.1.3.0 +logs.0.7.0 +lru.0.3.1 +lwt.5.7.0 +lwt-canceler.0.3 +lwt-exit.1.0 +lwt-watcher.0.2 +lwt_ppx.2.1.0 +lwt_ssl.1.2.0 +macaddr.5.5.0 +magic-mime.1.3.1 +matplotlib.0.2 +mdx.2.3.1 +menhir.20230608 +menhirLib.20230608 +menhirSdk.20230608 +merlin-lib.4.12-414 +minicli.5.0.2 +mirage-clock.4.2.0 +mirage-crypto.0.11.2 +mirage-crypto-ec.0.11.2 +mirage-crypto-pk.0.11.2 +mirage-crypto-rng.0.11.2 +mirage-crypto-rng-lwt.0.11.2 +mlgmpidl.1.2.15 +mtime.1.4.0 +multipart_form.0.5.0 +multipart_form-lwt.0.5.0 +num.1.4 +ocaml.4.14.1 +ocaml-base-compiler.4.14.1 +ocaml-compiler-libs.v0.12.4 +ocaml-config.2 +ocaml-migrate-parsetree.2.4.0 +ocaml-options-vanilla.1 +ocaml-syntax-shims.1.0.0 +ocaml-version.3.6.2 +ocaml_intrinsics.v0.16.0 +ocamlbuild.0.14.2 +ocamlc-loc.3.11.1 +ocamlfind.1.9.6 +ocamlformat.0.26.1 +ocamlformat-lib.0.26.1 +ocamlformat-rpc-lib.0.26.1 +ocamlgraph.2.1.0 +ocp-indent.1.8.1 +ocp-ocamlres.0.4 +ocplib-endian.1.2 +ocplib-simplex.0.5 +octez.18.0 +octez-accuser-Proxford.18.0 +octez-accuser-PtNairob.18.0 +octez-alcotezt.18.0 +octez-baker-Proxford.18.0 +octez-baker-PtNairob.18.0 +octez-client.18.0 +octez-codec.18.0 +octez-crawler.18.0 +octez-dac-client.18.0 +octez-dac-node.18.0 +octez-distributed-internal.18.0 +octez-distributed-lwt-internal.18.0 +octez-injector.18.0 +octez-l2-libs.18.0 +octez-libs.18.0 +octez-node.18.0 +octez-node-config.18.0 +octez-proto-libs.18.0 +octez-protocol-000-Ps9mPmXa-libs.18.0 +octez-protocol-001-PtCJ7pwo-libs.18.0 +octez-protocol-002-PsYLVpVv-libs.18.0 +octez-protocol-003-PsddFKi3-libs.18.0 +octez-protocol-004-Pt24m4xi-libs.18.0 +octez-protocol-005-PsBabyM1-libs.18.0 +octez-protocol-006-PsCARTHA-libs.18.0 +octez-protocol-007-PsDELPH1-libs.18.0 +octez-protocol-008-PtEdo2Zk-libs.18.0 +octez-protocol-009-PsFLoren-libs.18.0 +octez-protocol-010-PtGRANAD-libs.18.0 +octez-protocol-011-PtHangz2-libs.18.0 +octez-protocol-012-Psithaca-libs.18.0 +octez-protocol-013-PtJakart-libs.18.0 +octez-protocol-014-PtKathma-libs.18.0 +octez-protocol-015-PtLimaPt-libs.18.0 +octez-protocol-016-PtMumbai-libs.18.0 +octez-protocol-017-PtNairob-libs.18.0 +octez-protocol-018-Proxford-libs.18.0 +octez-protocol-alpha-libs.18.0 +octez-protocol-compiler.18.0 +octez-proxy-server.18.0 +octez-shell-libs.18.0 +octez-signer.18.0 +octez-smart-rollup-client-Proxford.18.0 +octez-smart-rollup-client-PtNairob.18.0 +octez-smart-rollup-node-lib.18.0 +octez-smart-rollup-node-Proxford.18.0 +octez-smart-rollup-node-PtNairob.18.0 +octez-smart-rollup-wasm-debugger.18.0 +octez-version.18.0 +odig.0.0.9 +odoc.2.3.0 +odoc-parser.2.3.0 +opam-core.2.1.5 +optint.0.3.0 +ordering.3.11.1 +parany.14.0.1 +parsexp.v0.16.0 +pbkdf.1.2.0 +pecu.0.6 +picasso.0.4.0 +pp.1.2.0 +pp_loc.2.1.0 +pprint.20230830 +ppx_assert.v0.16.0 +ppx_base.v0.16.0 +ppx_bench.v0.16.0 +ppx_bin_prot.v0.16.0 +ppx_blob.0.7.2 +ppx_cold.v0.16.0 +ppx_compare.v0.16.0 +ppx_custom_printf.v0.16.0 +ppx_derivers.1.2.1 +ppx_deriving.5.2.1 +ppx_disable_unused_warnings.v0.16.0 +ppx_enumerate.v0.16.0 +ppx_expect.v0.16.0 +ppx_fields_conv.v0.16.0 +ppx_fixed_literal.v0.16.0 +ppx_globalize.v0.16.0 +ppx_hash.v0.16.0 +ppx_here.v0.16.0 +ppx_ignore_instrumentation.v0.16.0 +ppx_import.1.10.0 +ppx_inline_test.v0.16.0 +ppx_irmin.3.7.2 +ppx_jane.v0.16.0 +ppx_let.v0.16.0 +ppx_log.v0.16.0 +ppx_module_timer.v0.16.0 +ppx_optcomp.v0.16.0 +ppx_optional.v0.16.0 +ppx_pipebang.v0.16.0 +ppx_repr.0.7.0 +ppx_sexp_conv.v0.16.0 +ppx_sexp_message.v0.16.0 +ppx_sexp_value.v0.16.0 +ppx_stable.v0.16.0 +ppx_stable_witness.v0.16.0 +ppx_string.v0.16.0 +ppx_tydi.v0.16.0 +ppx_typerep_conv.v0.16.0 +ppx_variants_conv.v0.16.0 +ppx_yojson_conv_lib.v0.16.0 +ppxlib.0.31.0 +prbnmcn-basic-structures.0.0.1 +prbnmcn-linalg.0.0.1 +prbnmcn-stats.0.0.6 +prettym.0.0.3 +pringo.1.3 +progress.0.2.1 +prometheus.1.2 +prometheus-app.1.2 +protocol_version_header.v0.16.0 +psmt2-frontend.0.4.0 +psq.0.2.1 +ptime.1.1.0 +pure-splitmix.0.3 +pyml.20220905 +qcheck-alcotest.0.21.2 +qcheck-core.0.21.2 +re.1.11.0 +redis.0.7.1 +repr.0.7.0 +resto.1.2 +resto-acl.1.2 +resto-cohttp.1.2 +resto-cohttp-client.1.2 +resto-cohttp-self-serving-client.1.2 +resto-cohttp-server.1.2 +resto-directory.1.2 +result.1.5 +ringo.1.0.0 +rresult.0.7.0 +rusage.1.0.0 +secp256k1-internal.0.4.0 +sedlex.3.2 +semaphore-compat.1.0.1 +seq.base +seqes.0.2 +sexp_pretty.v0.16.0 +sexplib.v0.16.0 +sexplib0.v0.16.0 +spawn.v0.15.1 +spelll.0.4 +splittable_random.v0.16.0 +ssl.0.7.0 +stdcompat.19 +stdint.0.7.2 +stdio.v0.16.0 +stdlib-shims.0.3.0 +stdune.3.11.1 +stringext.1.6.0 +tar.2.6.0 +tar-unix.2.6.0 +terminal.0.2.1 +textutils.v0.16.0 +textutils_kernel.v0.16.0 +tezos-benchmark.18.0 +tezos-dac-client-lib.18.0 +tezos-dac-lib.18.0 +tezos-dac-node-lib.18.0 +tezos-dal-node-lib.18.0 +tezos-dal-node-services.18.0 +tezos-lwt-result-stdlib.17.3 +tezos-protocol-000-Ps9mPmXa.18.0 +tezos-protocol-001-PtCJ7pwo.18.0 +tezos-protocol-002-PsYLVpVv.18.0 +tezos-protocol-003-PsddFKi3.18.0 +tezos-protocol-004-Pt24m4xi.18.0 +tezos-protocol-005-PsBABY5H.18.0 +tezos-protocol-005-PsBabyM1.18.0 +tezos-protocol-006-PsCARTHA.18.0 +tezos-protocol-007-PsDELPH1.18.0 +tezos-protocol-008-PtEdo2Zk.18.0 +tezos-protocol-008-PtEdoTez.18.0 +tezos-protocol-009-PsFLoren.18.0 +tezos-protocol-010-PtGRANAD.18.0 +tezos-protocol-011-PtHangz2.18.0 +tezos-protocol-012-Psithaca.18.0 +tezos-protocol-013-PtJakart.18.0 +tezos-protocol-014-PtKathma.18.0 +tezos-protocol-015-PtLimaPt.18.0 +tezos-protocol-016-PtMumbai.18.0 +tezos-protocol-017-PtNairob.18.0 +tezos-protocol-018-Proxford.18.0 +tezos-protocol-alpha.18.0 +tezos-proxy-server-config.18.0 +tezos-rust-libs.1.6 +tezos-sapling-parameters.1.1.0 +tezt.3.1.1 +tezt-tezos.18.0 +tgls.0.8.6 +time_now.v0.16.0 +timezone.v0.16.0 +tls.0.17.1 +tls-lwt.0.17.1 +topkg.1.0.7 +tsdl.1.0.0 +typerep.v0.16.0 +tyxml.4.6.0 +unstrctrd.0.3 +uri.4.4.0 +uri-sexp.4.4.0 +uucd.15.1.0 +uucp.15.1.0 +uuidm.0.9.8 +uunf.15.1.0 +uuseg.15.1.0 +uutf.1.0.3 +variantslib.v0.16.0 +vector.1.0.0 +vector3.1.0.0 +vg.0.9.4 +webbrowser.0.6.1 +x509.0.16.5 +xdg.3.11.1 +xmlm.1.4.0 +yaml.3.1.0 +yojson.2.1.1 +zarith.1.12 +zarith_stubs_js.v0.16.0 diff --git a/test/whole_switch/test.sh b/test/whole_switch/test.sh new file mode 100644 index 0000000000..d67f770349 --- /dev/null +++ b/test/whole_switch/test.sh @@ -0,0 +1,8 @@ +odig odoc +mkdir -p packages +cd packages +for PKG in $(ls $OPAM_SWITCH_PREFIX/var/cache/odig/odoc) +do + echo $PKG + dune exec sherlodoc_index -- --format=marshal --db=$PKG.db $(find /home/emile/.opam/sherlodoc-test2/var/cache/odig/odoc/$PKG -name "*.odocl") 2> $PKG.stderr > $PKG.stdout +done \ No newline at end of file From b6849e8d1c7994296c50947b6cc65f2972669471 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 4 Dec 2023 16:42:39 +0100 Subject: [PATCH 155/285] update readme --- README.md | 127 +++++++++++++++++++++++++++++++++++++++++++++++----- cli/main.ml | 6 +-- 2 files changed, 118 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 54c966b354..5f1be4e397 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,122 @@ **Try it online at [doc.sherlocode.com](https://doc.sherlocode.com) !** -A rough prototype of a Hoogle-like search engine for OCaml documentation. It's full of bugs and todos, but works well enough for my purpose: Perhaps it will be useful to you too. -- The fuzzy type search is supported by a polarity search. As an example, the type `string -> int -> char` gets simplified to `{ -string, -int, +char }` which means that it consumes a `string` and an `int` and produces a `char` (irrespective of the order of the arguments). This yields good candidates which are then sorted by similarity with the query. -- The real magic is all the package documentation generated for [`ocaml.org/packages`](https://ocaml.org/packages), which I got my hands on thanks to insider trading (but don't have the bandwidth to share back... sorry!) +A Hoogle-like search engine for OCaml documentation. It can be used in +differents ways, [online](https://doc.sherlocode.com), or offline with +the dev version of odoc. +It has fuzzy type search supported by a polarity search. As an example, the type +`string -> int -> char` gets simplified to `{ -string, -int, +char }` which +means that it consumes a `string` and an `int` and produces a `char` +(irrespective of the order of the arguments). This polarity search is fast +enough and yields good candidates which are then sorted by similarity with the +query. The sort is slower but the number of candidates is small. + +You can search for anything that can exists in an MLI files : values, types, +modules, exceptions, constructors etc... + +Fuzzy type search is available for values, sum-types constructors, exceptions, +and record fields. + +# Usage + +## Generating a search-database + +The first step to using sherlodoc is generating a search-database. You do this +with the command `sherlodoc_index` : + +```bash +sherlodoc_index --format=marshal --db=db.bin a.odocl b.odocl ``` -$ opam install --deps-only ./sherlodoc.opam - # Note: your odoc version must match your odocl files -# To index all the odocl files in `/path/to/doc`: -$ dune exec -- ./index/index.exe /path/to/doc /path/to/result.db - # `/path/to/doc` should contain a hierarchy of subfolders `libname/1.2.3/**/*.odocl` - # `result.db` will be created or replaced +The `--format` option determines in which format the database is outputted. The +available format are `marshal`, `js` and `ancient`. The `js` format, for +javascript, is the one compatible with odoc, and the `marshal` for most other +uses. `ancient` uses `` and you should use it if you know +what you are doing. It is used for the [online](https://doc.sherlocode.com) +version of sherlodoc. + +The `--db` option is the filename of the output. + +Then you need to provide a list of .odocl files that contains the signatures +items that are going to be searchable. They are build artifacts of odoc. + +There are others options that are documented by `sherlodoc_index --help`. + +## Searching on the command line -# To run the website: -$ dune exec -- ./www/www.exe /path/to/result.db -22.10.22 17:17:33.102 Running at http://localhost:1234 +If you have a search database in `marshal` format, you can search on the command +line : + +```bash +sherlodoc --db=db.bin "blabla : int -> string" ``` + +`--db` is the filename of the search database. If absent, the environment +variable `SHERLODOC_DB` will be used instead. + +In my example, I gave a query, but if you give none, sherlodoc enter an +interactive mode where you can enter queries until you decide to quit. + +### Search your switch + +A reasonable use of sherlodoc on the cli is to search for signatures items from +your whole switch. Since odig can generate the documentation of the switch, we +can get the .odocl files with it : + +Generate the documentation of your switch : + +```bash +odig odoc +``` + +Generate the search database : + +```bash +sherlodoc_index --format=marshal --db=db.bin $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc -name "*.odocl") +``` + +Enjoy searching : + +```bash +sherlodoc --db-db.bin +``` + +## Searching from an odoc search bar + +The latest unreleased version of odoc is compatible with sherlodoc. This allows +you to upload the documentation of a package with a search for this package +embedded. + +For this to work, you need to generate a search database with format `js`, and +then add to every call of `odoc html-generate` the flags `--search-uri +sherlodoc.js --search-uri db.js`. `sherlodoc.js` is installed in your path by +opam, but `db.js` is the search database you generate and can be renamed as you +wish. + +Obviously, most people use dune, and do not call `odoc html-generate`. A patch +for dune is being [worked +on](https://github.com/emileTrotignon/dune/tree/sherlodune). If you want to, you +can test it, it should work. It is still work in progress. + +## Sherlodoc online + +If you want to use sherlodoc as a server, like on +[doc.sherlocode.com](https://doc.sherlocode.com), you can. This is packaged +separately in `sherlodoc-www`, but also live in this repo. + +Once you have installed `shelodoc-www`, you need to generate your search database : + +```bash +sherlodoc_index --format=ancient --db=db.bin $(find /path/to/doc -name "*.odocl") +``` + +Then you can run the website : + +```bash +sherlodoc-www db.bin +``` + +The real magic for [doc.sherlocode.com](https://doc.sherlocode.com) is all the +.odocl artifacts of the package documentation generated for +[`ocaml.org/packages`](https://ocaml.org/packages), which I got my hands on +thanks to insider trading (but don't have the bandwidth to share back... sorry!) diff --git a/cli/main.ml b/cli/main.ml index 10973b37ce..4f361c3676 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -70,15 +70,15 @@ let db_filename = Arg.(value & opt (some file) None & info [ "db" ] ~docv:"DB" ~env) let limit = - let doc = "The maximum number of results" in + let doc = "The maximum number of results per query" in Arg.(value & opt int 50 & info [ "limit"; "n" ] ~docv:"N" ~doc) let query = - let doc = "The query" in + let doc = "The query. If absent, sherlodoc will read queries in the standard input." in Arg.(value & pos 0 (some string) None & info [] ~docv:"QUERY" ~doc) let print_cost = - let doc = "Prints cost of each result" in + let doc = "For debugging purposes : prints the cost of each result" in Arg.(value & flag & info [ "print-cost" ] ~doc) let dynamic_sort = From cafb6134975cd855e099950c327f5f730c028068 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 4 Dec 2023 16:42:50 +0100 Subject: [PATCH 156/285] whole switch test fix --- test/whole_switch/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/whole_switch/test.sh b/test/whole_switch/test.sh index d67f770349..3a310562a4 100644 --- a/test/whole_switch/test.sh +++ b/test/whole_switch/test.sh @@ -4,5 +4,5 @@ cd packages for PKG in $(ls $OPAM_SWITCH_PREFIX/var/cache/odig/odoc) do echo $PKG - dune exec sherlodoc_index -- --format=marshal --db=$PKG.db $(find /home/emile/.opam/sherlodoc-test2/var/cache/odig/odoc/$PKG -name "*.odocl") 2> $PKG.stderr > $PKG.stdout + dune exec sherlodoc_index -- --format=marshal --db=$PKG.db $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc/$PKG -name "*.odocl") 2> $PKG.stderr > $PKG.stdout done \ No newline at end of file From 366ea17511778bc448cbfb469057f685a75076ef Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 4 Dec 2023 16:45:10 +0100 Subject: [PATCH 157/285] readme improvement --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5f1be4e397..a4f0bdf9be 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,8 @@ variable `SHERLODOC_DB` will be used instead. In my example, I gave a query, but if you give none, sherlodoc enter an interactive mode where you can enter queries until you decide to quit. +There are more option documented by `sherlodoc --help`. + ### Search your switch A reasonable use of sherlodoc on the cli is to search for signatures items from From d742a1ebd7f21a4cd9d7d6f3c7d292bd3f9ee46a Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 7 Dec 2023 14:26:29 +0100 Subject: [PATCH 158/285] module type entrie have less priority --- cli/main.ml | 55 +++-- db/elt.ml | 14 +- index/index.ml | 3 +- index/load_doc.ml | 27 ++- query/dynamic_cost.ml | 8 +- test/cram/base.t/run.t | 290 ++++++++++++++------------ test/cram/cli.t/run.t | 46 ++-- test/cram/cli_small.t/run.t | 8 +- test/cram/module_type_cost.t/main.mli | 11 + test/cram/module_type_cost.t/run.t | 17 ++ www/ui.ml | 3 +- 11 files changed, 295 insertions(+), 187 deletions(-) create mode 100644 test/cram/module_type_cost.t/main.mli create mode 100644 test/cram/module_type_cost.t/run.t diff --git a/cli/main.ml b/cli/main.ml index 4f361c3676..507d86549f 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -20,34 +20,46 @@ let string_of_kind = | Field _ -> "field" | Val _ -> "val" -let print_result ~print_cost - Db.Elt.{ name; rhs; url = _; kind; score; doc_html = _; pkg = _ } = +let print_result ~print_cost ~no_rhs + Db.Elt. + { name + ; rhs + ; url = _ + ; kind + ; score + ; doc_html = _ + ; pkg = _ + ; is_from_module_type = _ + } = let score = if print_cost then string_of_int score ^ " " else "" in let kind = kind |> string_of_kind |> Unescape.string in let name = Unescape.string name in let pp_rhs h = function | None -> () + | Some _ when no_rhs -> () | Some rhs -> Format.fprintf h "%s" (Unescape.string rhs) in Format.printf "%s%s %s%a\n" score kind name pp_rhs rhs -let search ~print_cost ~dynamic_sort ~limit ~db query = +let search ~print_cost ~static_sort ~limit ~db ~no_rhs query = match - Query.(api ~shards:db ~dynamic_sort { query; packages = []; limit }) + Query.( + api ~shards:db ~dynamic_sort:(not static_sort) + { query; packages = []; limit }) with | _, [] -> print_endline "[No results]" | _, (_ :: _ as results) -> - List.iter (print_result ~print_cost) results ; + List.iter (print_result ~print_cost ~no_rhs) results ; flush stdout -let rec search_loop ~print_cost ~dynamic_sort ~limit ~db = +let rec search_loop ~print_cost ~no_rhs ~static_sort ~limit ~db = match In_channel.input_line stdin with | Some query -> - search ~print_cost ~dynamic_sort ~limit ~db query ; - search_loop ~print_cost ~dynamic_sort ~limit ~db + search ~print_cost ~static_sort ~limit ~db ~no_rhs query ; + search_loop ~print_cost ~no_rhs ~static_sort ~limit ~db | None -> print_endline "[Search session ended]" -let main db query print_cost dynamic_sort limit = +let main db query print_cost no_rhs static_sort limit = match db with | None -> output_string stderr @@ -57,8 +69,8 @@ let main db query print_cost dynamic_sort limit = | Some db -> ( let db = Storage_marshal.load db in match query with - | None -> search_loop ~print_cost ~dynamic_sort ~limit ~db - | Some query -> search ~print_cost ~dynamic_sort ~limit ~db query) + | None -> search_loop ~print_cost ~no_rhs ~static_sort ~limit ~db + | Some query -> search ~print_cost ~no_rhs ~static_sort ~limit ~db query) open Cmdliner @@ -74,21 +86,30 @@ let limit = Arg.(value & opt int 50 & info [ "limit"; "n" ] ~docv:"N" ~doc) let query = - let doc = "The query. If absent, sherlodoc will read queries in the standard input." in + let doc = + "The query. If absent, sherlodoc will read queries in the standard input." + in Arg.(value & pos 0 (some string) None & info [] ~docv:"QUERY" ~doc) let print_cost = let doc = "For debugging purposes : prints the cost of each result" in Arg.(value & flag & info [ "print-cost" ] ~doc) -let dynamic_sort = +let static_sort = let doc = - "Sort the results by looking at the query.\n\ - Disabling it allows to look at the static costs of elements." + "Sort the results without looking at the query.\n\ + Enabling it allows to look at the static costs of elements.\n\ + Mainly for testing purposes." in - Arg.(value & flag & info [ "dynamic-sort" ] ~doc) + Arg.(value & flag & info [ "static-sort" ] ~doc) + +let no_rhs = + let doc = "Do not print the right-hand side of results." in + Arg.(value & flag & info [ "no-rhs"; "no-right-hand-side" ] ~doc) -let main = Term.(const main $ db_filename $ query $ print_cost $ dynamic_sort $ limit) +let main = + Term.( + const main $ db_filename $ query $ print_cost $ no_rhs $ static_sort $ limit) let cmd = let doc = "CLI interface to query sherlodoc" in diff --git a/db/elt.ml b/db/elt.ml index e5684e2d5d..29a67f465d 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -8,13 +8,13 @@ type type_path = string list list |- b |- * |- c - |- d - ]} - {!type_paths} is the list of paths from root to leaf in the tree of + |- d + ]} + {!type_paths} is the list of paths from root to leaf in the tree of the type. There is an annotation to indicate the child's position. Here it would be : [ [["->";"0"; "a"];["->"; "1"; "->"; "0"; "b"]; ...] ] - + It is used to sort results. *) module Kind = struct @@ -76,6 +76,7 @@ module T = struct ; score : int ; doc_html : string ; pkg : Package.t option + ; is_from_module_type : bool } let compare_pkg { name; version = _ } (b : package) = @@ -142,5 +143,6 @@ let link t = in Some (pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name) -let v ~name ~kind ~score ~rhs ~doc_html ~url ?(pkg = None) () = - { name; kind; url; score; doc_html; pkg; rhs } +let v ~name ~kind ~score ~rhs ~doc_html ~url ~is_from_module_type ?(pkg = None) + () = + { name; kind; url; score; doc_html; pkg; rhs; is_from_module_type } diff --git a/index/index.ml b/index/index.ml index 0aecfa1838..9af1beb616 100644 --- a/index/index.ml +++ b/index/index.ml @@ -13,7 +13,8 @@ let index_file register filename = in match Odoc_odoc.Indexing.handle_file ~page ~unit 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 %s: %s@." filename msg) let storage_module = function | `ancient -> diff --git a/index/load_doc.ml b/index/load_doc.ml index fbc55e9986..7e4061a400 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -7,9 +7,9 @@ let generic_cost ~ignore_no_doc name has_doc = (* name length is important not because short identifier are better in the abstract, but because the shortest result will be close to the query, as the suffix tree does not return results shorter than the query*) - (String.length name * 4) + (String.length name * 6) (* + (5 * List.length path) TODO : restore depth based ordering *) - + (if ignore_no_doc || has_doc then 0 else 100) + + (if ignore_no_doc || has_doc then 0 else 30) + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 let type_cost paths = @@ -264,6 +264,24 @@ let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.kind) = let type_ = TypeExpr.Arrow (None, parent_type, type_) in register_type_expr ~db elt type_ +let rec is_from_module_type (id : Odoc_model.Paths.Identifier.Any.t) = + let open Odoc_model.Paths in + match id.iv with + | `CoreType _ | `CoreException _ | `Root _ | `Page _ | `LeafPage _ -> false + | `ModuleType _ -> true + | #Identifier.NonSrc.t_pv as x -> + let parent = Identifier.label_parent { id with iv = x } in + is_from_module_type (parent :> Identifier.Any.t) + | _ -> false + +let is_from_module_type Odoc_search.Entry.{ id; _ } = + match id.iv with + | `ModuleType (parent, _) -> + (* A module type itself is not *from* a module type, but it might be if one + of its parents is a module type. *) + is_from_module_type (parent :> Odoc_model.Paths.Identifier.Any.t) + | _ -> is_from_module_type id + let register_entry ~db ~index_name ~type_search ~index_docstring (Odoc_search.Entry.{ id; doc; kind } as entry) = let open Odoc_search in @@ -293,7 +311,10 @@ let register_entry ~db ~index_name ~type_search ~index_docstring let rhs = Html.rhs_of_kind kind in let url = Html.url id in let url = Result.get_ok url in - let elt = Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url () in + let is_from_module_type = is_from_module_type entry in + let elt = + Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url ~is_from_module_type () + in if index_docstring then register_doc ~db elt doc_txt ; (if index_name then diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 8f6265ff9b..bae56a894e 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -192,6 +192,7 @@ module Reasoning = struct ; type_in_query : bool ; type_in_elt : bool ; kind : kind + ; is_from_module_type : bool } let type_distance query_type elt = @@ -237,6 +238,7 @@ module Reasoning = struct | Elt.Kind.Val _ -> Val let name_length elt = String.length elt.Elt.name + let is_from_module_type elt = elt.Elt.is_from_module_type let v query_words query_type elt = let is_stdlib = is_stdlib elt in @@ -247,6 +249,7 @@ module Reasoning = struct let type_in_elt = type_in_elt elt in let type_in_query = type_in_query query_type in let name_length = name_length elt in + let is_from_module_type = is_from_module_type elt in { is_stdlib ; has_doc ; name_matches @@ -255,6 +258,7 @@ module Reasoning = struct ; type_in_query ; kind ; name_length + ; is_from_module_type } let compare_kind k k' = @@ -284,6 +288,7 @@ module Reasoning = struct ; type_in_query ; kind ; name_length + ; is_from_module_type } = let ignore_no_doc = match kind with @@ -323,9 +328,10 @@ module Reasoning = struct assert false else 0 in + let is_from_module_type_cost = if is_from_module_type then 400 else 0 in (if is_stdlib then 0 else 100) + (if has_doc || ignore_no_doc then 0 else 100) - + name_matches + type_cost + kind + name_length + + name_matches + type_cost + kind + name_length + is_from_module_type_cost let score ~query_name ~query_type elt = score (v query_name query_type elt) end diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 91450dc472..42c1175166 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -9,10 +9,24 @@ $ du -sh megaodocl 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + + real 0m1.165s + user 0m1.099s + sys 0m0.063s + + + + + + + + + + + + + - real 0m3.077s - user 0m2.886s - sys 0m0.122s $ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null $ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null @@ -25,8 +39,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2700 db.js - 2036 db.js.gz + 2736 db.js + 2064 db.js.gz 1544 megaodocl.gz @@ -52,134 +66,146 @@ indent to see results $ cp -r html /tmp $ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - $ sherlodoc --db=db_marshal.bin "group b" - val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t - val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t - val Base.List.groupi : 'a t -> break:(int -> 'a -> 'a -> bool) -> 'a t t - val Base.List.sort_and_group : 'a t -> compare:('a -> 'a -> int) -> 'a t t - val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t - val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t - val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Hashtbl.group : ?growth_allowed:bool -> - ?size:int -> - 'a Key.t -> - get_key:('r -> 'a) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t - val Base.Hashtbl.Creators.group : ?growth_allowed:bool -> - ?size:int -> - 'a Key.t -> - get_key:('r -> 'a) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t - val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list - val Base.Hashtbl.S_poly.group : ?growth_allowed:bool -> - ?size:int -> - get_key:('r -> 'a key) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t - val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.Hashtbl.Poly.group : ?growth_allowed:bool -> - ?size:int -> - get_key:('r -> 'a key) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t - val Base.Hashtbl.Creators.group : ?growth_allowed:bool -> - ?size:int -> - get_key:('r -> 'a Key.t) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t_ - val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> - ?size:int -> - 'a Key.t -> - get_key:('r -> 'a) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t - val Base.Set.Creators_and_accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list - $ sherlodoc --db=db_marshal.bin "group by" - val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.Set.S_poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.Poly.group_by : 'a t -> equiv:('a -> 'a -> bool) -> 'a t list - val Base.Set.Using_comparator.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.Set.Accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list - val Base.Set.Using_comparator.Tree.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - val Base.Set.Creators_and_accessors_generic.group_by : ('a, 'cmp) t -> equiv:('a elt -> 'a elt -> bool) -> ('a, 'cmp) t list - $ sherlodoc --db=db_marshal.bin "map2" - mod Base.Applicative.Make_using_map2 - mod Base.Applicative.Make2_using_map2 - mod Base.Applicative.Make3_using_map2 - sig Base.Applicative.Basic_using_map2 - sig Base.Applicative.Basic2_using_map2 - sig Base.Applicative.Basic3_using_map2 - mod Base.Applicative.Make_using_map2_local - mod Base.Applicative.Make2_using_map2_local - mod Base.Applicative.Make3_using_map2_local - sig Base.Applicative.Basic_using_map2_local - sig Base.Applicative.Basic2_using_map2_local - sig Base.Applicative.Basic3_using_map2_local - mod Base.Applicative.Make_using_map2.Applicative_infix - mod Base.Applicative.Make2_using_map2.Applicative_infix - mod Base.Applicative.Make3_using_map2.Applicative_infix - val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - mod Base.Applicative.Make_using_map2_local.Applicative_infix - mod Base.Applicative.Make2_using_map2_local.Applicative_infix - mod Base.Applicative.Make3_using_map2_local.Applicative_infix - type Base.Applicative.Basic_using_map2.t - val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - type Base.Applicative.Basic2_using_map2.t - type Base.Applicative.Basic3_using_map2.t - type Base.Applicative.Make_using_map2.X.t - val Base.Applicative.Basic_using_map2.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] - type Base.Applicative.Make2_using_map2.X.t - type Base.Applicative.Make3_using_map2.X.t - val Base.Applicative.Basic2_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] - val Base.Applicative.Basic3_using_map2.map : [ `Define_using_map2 + $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin "S_poly" + 115 sig Base.Map.S_poly + 115 sig Base.Set.S_poly + 119 sig Base.Hashtbl.S_poly + 623 val Base.Set.S_poly.map + 623 val Base.Set.S_poly.mem + 625 mod Base.Set.S_poly.Named + 627 val Base.Hashtbl.S_poly.add + 628 val Base.Hashtbl.S_poly.data + 628 val Base.Hashtbl.S_poly.keys + 721 type Base.Map.S_poly.t + 721 type Base.Set.S_poly.t + 723 val Base.Map.S_poly.add + 723 val Base.Map.S_poly.mem + 723 val Base.Set.S_poly.add + 723 val Base.Set.S_poly.nth + 723 type Base.Set.S_poly.set + 723 val Base.Set.S_poly.sum + 724 val Base.Map.S_poly.data + 724 val Base.Map.S_poly.keys + 724 type Base.Map.S_poly.tree + 724 val Base.Set.S_poly.diff + 724 type Base.Set.S_poly.tree + 725 type Base.Hashtbl.S_poly.t + 725 val Base.Map.S_poly.empty + 725 val Base.Set.S_poly.empty + 725 val Base.Set.S_poly.equal + 725 val Base.Set.S_poly.inter + 725 val Base.Set.S_poly.union + 726 val Base.Map.S_poly.length + 726 val Base.Set.S_poly.choose + 726 val Base.Set.S_poly.length + 726 val Base.Set.S_poly.remove + 727 type Base.Hashtbl.S_poly.key + 727 val Base.Set.S_poly.max_elt + 727 val Base.Set.S_poly.min_elt + 727 val Base.Set.S_poly.of_list + 727 val Base.Set.S_poly.of_tree + 727 val Base.Set.S_poly.to_list + 727 val Base.Set.S_poly.to_tree + 728 val Base.Map.S_poly.of_alist + 728 val Base.Set.S_poly.elements + 728 val Base.Set.S_poly.is_empty + 728 val Base.Set.S_poly.of_array + 728 val Base.Set.S_poly.to_array + 729 val Base.Set.S_poly.singleton + 730 val Base.Set.S_poly.choose_exn + 730 val Base.Set.S_poly.invariants + 731 val Base.Set.S_poly.max_elt_exn + 731 val Base.Set.S_poly.min_elt_exn + 732 val Base.Hashtbl.S_poly.hashable + $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin "group b" + 218 val Base.List.group + 221 val Base.Hashtbl.group + 222 val Base.Sequence.group + 224 val Base.List.Assoc.group + 323 val Base.List.groupi + 324 val Base.Set.group_by + 326 val Base.Hashtbl.Poly.group + 330 val Base.Hashtbl.Creators.group + 330 val Base.List.sort_and_group + 336 val Base.List.Assoc.sort_and_group + 429 val Base.Set.Poly.group_by + 441 val Base.Set.Using_comparator.group_by + 446 val Base.Set.Using_comparator.Tree.group_by + 630 val Base.Hashtbl.Creators.group + 642 val Base.Hashtbl.S_without_submodules.group + 728 val Base.Hashtbl.S_poly.group + 831 val Base.Set.S_poly.group_by + 842 val Base.Set.Accessors_generic.group_by + 855 val Base.Set.Creators_and_accessors_generic.group_by + $ sherlodoc --no-rhs --db=db_marshal.bin "group by" + val Base.Set.group_by + val Base.Set.Poly.group_by + val Base.Set.Using_comparator.group_by + val Base.Set.Using_comparator.Tree.group_by + val Base.Set.S_poly.group_by + val Base.Set.Accessors_generic.group_by + val Base.Set.Creators_and_accessors_generic.group_by + $ sherlodoc --print-cost --db=db_marshal.bin "map2" + 214 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 216 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 218 val Base.Or_error.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 226 val Base.Applicative.Make.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t + 227 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 235 mod Base.Applicative.Make_using_map2 + 236 sig Base.Applicative.Basic_using_map2 + 236 mod Base.Applicative.Make2_using_map2 + 236 mod Base.Applicative.Make3_using_map2 + 237 sig Base.Applicative.Basic2_using_map2 + 237 sig Base.Applicative.Basic3_using_map2 + 242 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 243 mod Base.Applicative.Make_using_map2_local + 244 sig Base.Applicative.Basic_using_map2_local + 244 mod Base.Applicative.Make2_using_map2_local + 244 mod Base.Applicative.Make3_using_map2_local + 245 sig Base.Applicative.Basic2_using_map2_local + 245 sig Base.Applicative.Basic3_using_map2_local + 254 mod Base.Applicative.Make_using_map2.Applicative_infix + 321 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 322 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 323 val Base.Array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 340 type Base.Applicative.Make_using_map2.X.t + 340 val Base.Applicative.Make_using_map2.all : 'a X.t list -> 'a list X.t + 341 type Base.Applicative.Make2_using_map2.X.t + 341 type Base.Applicative.Make3_using_map2.X.t + 342 val Base.Applicative.Make_using_map2.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] + 343 val Base.Applicative.Make2_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] + 343 val Base.Applicative.Make3_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - val Base.Applicative.Make_using_map2.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] - val Base.Applicative.Make2_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] - val Base.Applicative.Make3_using_map2.X.map : [ `Define_using_map2 + 343 val Base.Applicative.Make_using_map2.return : 'a -> 'a X.t + 345 val Base.Applicative.Make_using_map2.X.return : 'a -> 'a t + 347 type Base.Applicative.Make_using_map2_local.X.t + 348 type Base.Applicative.Make2_using_map2_local.X.t + 348 type Base.Applicative.Make3_using_map2_local.X.t + 349 val Base.Applicative.Make_using_map2_local.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] + 350 val Base.Applicative.Make2_using_map2_local.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] + 350 val Base.Applicative.Make3_using_map2_local.X.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - type Base.Applicative.Basic_using_map2_local.t - val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - type Base.Applicative.Basic2_using_map2_local.t - type Base.Applicative.Basic3_using_map2_local.t - type Base.Applicative.Make_using_map2_local.X.t - val Base.Applicative.Basic_using_map2_local.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] - type Base.Applicative.Make2_using_map2_local.X.t - type Base.Applicative.Make3_using_map2_local.X.t - val Base.Applicative.Basic2_using_map2_local.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] - val Base.Applicative.Basic3_using_map2_local.map : [ `Define_using_map2 + 623 val Base.Applicative.S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 739 type Base.Applicative.Basic_using_map2.t + 740 type Base.Applicative.Basic2_using_map2.t + 740 type Base.Applicative.Basic3_using_map2.t + 741 val Base.Applicative.Basic_using_map2.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] + 742 val Base.Applicative.Basic2_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] + 742 val Base.Applicative.Basic3_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - val Base.Applicative.Make_using_map2_local.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] - val Base.Applicative.Make_using_map2.return : 'a -> 'a X.t - val Base.Applicative.Make2_using_map2_local.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] - val Base.Applicative.Make3_using_map2_local.X.map : [ `Define_using_map2 + 746 type Base.Applicative.Basic_using_map2_local.t + 747 type Base.Applicative.Basic2_using_map2_local.t + 747 type Base.Applicative.Basic3_using_map2_local.t + 748 val Base.Applicative.Basic_using_map2_local.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] + 749 val Base.Applicative.Basic2_using_map2_local.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] + 749 val Base.Applicative.Basic3_using_map2_local.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - val Base.Applicative.Make_using_map2.X.return : 'a -> 'a t - val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - val Base.Applicative.Make2_using_map2.return : 'a -> ('a, _) X.t - $ sherlodoc --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" - val Base.Hashtbl.S_without_submodules.group : ?growth_allowed:bool -> - ?size:int -> - 'a Key.t -> - get_key:('r -> 'a) -> - get_data:('r -> 'b) -> - combine:('b -> 'b -> 'b) -> - 'r list -> - ('a, 'b) t + $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin --static-sort "List map2" + 261 val Base.List.rev_map2_exn + 267 val Base.List.map2_exn + 275 val Base.List.map2 + 299 val Base.List.rev_map2 + 351 val Base.List.Cartesian_product.map2 + + $ sherlodoc --no-rhs --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" + val Base.Hashtbl.S_without_submodules.group diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 790c59a67f..35c16bee01 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -22,27 +22,27 @@ val Main.Nest.nesting_priority : foo $ sherlodoc "list" mod Main.List - val Main.foo : foo type Main.list type Main.List.t = 'a list - val Main.Map.to_list : foo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.Map.to_list : foo val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + val Main.foo : foo doc $ sherlodoc "map" mod Main.Map - val Main.foo : foo - val Main.Map.to_list : foo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.Map.to_list : foo val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - $ sherlodoc "list map" val Main.foo : foo - val Main.Map.to_list : foo + $ sherlodoc "list map" val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.Map.to_list : foo val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + val Main.foo : foo $ sherlodoc "map2" val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t @@ -51,10 +51,10 @@ val Main.produce : unit -> moo val Main.produce_2' : unit -> unit -> moo $ sherlodoc ":moo -> _" - cons Main.MyExtension : moo -> extensible_type val Main.consume : moo -> unit val Main.consume_2 : moo -> moo -> unit val Main.consume_2_other : moo -> t -> unit + cons Main.MyExtension : moo -> extensible_type $ sherlodoc "modtype" sig Main.Modtype val Main.Modtype.v_modtype : foo @@ -62,21 +62,21 @@ sig Main.S mod Main.List mod Main.Nest - val Main.foo : foo mod Main.S_to_S1 type Main.list type Main.List.t = 'a list - val Main.Map.to_list : foo - cons Main.MyExtension : moo -> extensible_type val Main.consume : moo -> unit - type Main.extensible_type = .. - val Main.nesting_priority : foo - val Main.consume_2 : moo -> moo -> unit - val Main.Nest.nesting_priority : foo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - val Main.consume_2_other : moo -> t -> unit val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.consume_2 : moo -> moo -> unit + val Main.Map.to_list : foo + val Main.consume_2_other : moo -> t -> unit + type Main.extensible_type = .. + val Main.nesting_priority : foo val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + val Main.Nest.nesting_priority : foo + cons Main.MyExtension : moo -> extensible_type + val Main.foo : foo doc $ sherlodoc "qwertyuiopasdfghjklzxcvbnm" [No results] @@ -87,9 +87,9 @@ TODO : get a result for the query bellow [No results] $ sherlodoc ":'a" val Main.poly_1 : 'a -> 'b -> 'c + val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.poly_param : 'a boo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc ": 'a -> 'b -> 'c " @@ -106,10 +106,12 @@ TODO : get a result for the query bellow $ sherlodoc ":extensible_type" cons Main.MyExtension : moo -> extensible_type $ sherlodoc ":exn" - exn Main.Explicit_exn : exn_payload -> exn - exn Main.Implicit_exn : exn_payload -> exn - cons Main.Very_explicit_exn : exn_payload -> exn + sherlodoc: internal error, uncaught exception: + File "query/dynamic_cost.ml", line 328, characters 8-14: Assertion failed + + [125] $ sherlodoc ": exn_payload -> _" - exn Main.Explicit_exn : exn_payload -> exn - exn Main.Implicit_exn : exn_payload -> exn - cons Main.Very_explicit_exn : exn_payload -> exn + sherlodoc: internal error, uncaught exception: + File "query/dynamic_cost.ml", line 328, characters 8-14: Assertion failed + + [125] diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 0412a3c99c..a95eb3e7a4 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -7,7 +7,7 @@ $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') $ export SHERLODOC_DB=db.bin $ sherlodoc --print-cost "list" - 36 mod Main.List - 136 type Main.list - 144 type Main.List.t = 'a list - 222 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 109 mod Main.List + 209 type Main.list + 315 type Main.List.t = 'a list + 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t diff --git a/test/cram/module_type_cost.t/main.mli b/test/cram/module_type_cost.t/main.mli new file mode 100644 index 0000000000..0603d81bfc --- /dev/null +++ b/test/cram/module_type_cost.t/main.mli @@ -0,0 +1,11 @@ +module M : sig + val my_function : int -> int +end + +module type S = sig + val my_function : int -> int +end + +module type Module_type = sig end + +module Module_nype : sig end \ No newline at end of file diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t new file mode 100644 index 0000000000..aca2f746f5 --- /dev/null +++ b/test/cram/module_type_cost.t/run.t @@ -0,0 +1,17 @@ + $ ocamlc -c main.mli -bin-annot -I . + $ odoc compile -I . main.cmti + $ odoc link -I . main.odoc + $ cat $(find . -name '*.odocl') > megaodocl + $ du -sh megaodocl + 4.0K megaodocl + $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') + $ export SHERLODOC_DB=db.bin +Here we expect to have the `my_function` from the module be above the one from +the module type. + $ sherlodoc --print-cost --no-rhs "my_function" + 218 val Main.M.my_function + 618 val Main.S.my_function +Here we expect both the module type and the module to be ranked the same + $ sherlodoc --print-cost "module" + 220 mod Main.Module_nype + 220 sig Main.Module_type diff --git a/www/ui.ml b/www/ui.ml index cb0b7ec94f..d6954e4185 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -108,7 +108,8 @@ let search_form query = ; a_value query ; a_placeholder "Search..." ; a_autofocus () - ; a_autocomplete `Off ] + ; a_autocomplete `Off + ] () ; input ~a:[ a_input_type `Submit; a_value "Search!" ] () ] From 8939f7520cd96788b7c82069742d7a0b60fe76ce Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 7 Dec 2023 14:29:33 +0100 Subject: [PATCH 159/285] functor --- test/cram/base.t/run.t | 6 +++--- test/cram/module_type_cost.t/main.mli | 4 +++- test/cram/module_type_cost.t/run.t | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 42c1175166..9b0bea43d1 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,9 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.165s - user 0m1.099s - sys 0m0.063s + real 0m1.168s + user 0m1.131s + sys 0m0.030s diff --git a/test/cram/module_type_cost.t/main.mli b/test/cram/module_type_cost.t/main.mli index 0603d81bfc..6f95af3239 100644 --- a/test/cram/module_type_cost.t/main.mli +++ b/test/cram/module_type_cost.t/main.mli @@ -8,4 +8,6 @@ end module type Module_type = sig end -module Module_nype : sig end \ No newline at end of file +module Module_nype : sig end + +module Make (M : S) : S \ No newline at end of file diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t index aca2f746f5..5875a365ea 100644 --- a/test/cram/module_type_cost.t/run.t +++ b/test/cram/module_type_cost.t/run.t @@ -10,6 +10,8 @@ Here we expect to have the `my_function` from the module be above the one from the module type. $ sherlodoc --print-cost --no-rhs "my_function" 218 val Main.M.my_function + 221 val Main.Make.my_function + 223 val Main.Make.M.my_function 618 val Main.S.my_function Here we expect both the module type and the module to be ranked the same $ sherlodoc --print-cost "module" From 112d32d2708d5d3497c2e2ed5e6f091d3dad91ac Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 7 Dec 2023 17:20:49 +0100 Subject: [PATCH 160/285] readme update --- README.md | 55 +++++++++++++++++++++++++++++++++++++----- jsoo/dune | 2 +- test/cram/base.t/run.t | 6 ++--- test/cram/cli.t/run.t | 4 +++ 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a4f0bdf9be..77b028cace 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,12 @@ sherlodoc_index --format=marshal --db=db.bin a.odocl b.odocl ``` The `--format` option determines in which format the database is outputted. The -available format are `marshal`, `js` and `ancient`. The `js` format, for -javascript, is the one compatible with odoc, and the `marshal` for most other -uses. `ancient` uses `` and you should use it if you know -what you are doing. It is used for the [online](https://doc.sherlocode.com) -version of sherlodoc. +available format are `marshal`, `js` and `ancient`. `ancient` is not supported +at the moment, but we might bring it back. The `js` format, for javascript, is +the one compatible with odoc, and the `marshal` for most other uses. `ancient` +uses `` and you should use it if you know what you are +doing. It is used for the [online](https://doc.sherlocode.com) version of +sherlodoc. The `--db` option is the filename of the output. @@ -42,6 +43,47 @@ items that are going to be searchable. They are build artifacts of odoc. There are others options that are documented by `sherlodoc_index --help`. +## Queries + +To query sherlodoc, be it on the command-line or in a web interface, you need +to input a string query. A query is a list of words, separated by spaces. +Results will be entries that have every word of the list present in them. + +``` +list map +``` + +The above query will return entries that have both `list` and `map` in them. + +You can also add `: ` at the end of your query, and in that case, results +will only be results whose type match . This can only be a value, an +exception, a constructor or a record field. + +Matching a type is fuzzy, if you do the following query : + +``` +blabla : string +``` + +It could return `val blablabla : int -> string` and `val blabla2 : string`. + +You can have just the type-part of the query : `: string -> int` is a valid +query. + +You can use wildcards : + +``` +: string -> _ +``` + +will only return functions that take a string a argument, no matter what they +return. + +There is limited support for polymorphism : you cannot search for `'a -> 'a` and +get every function `int -> int`, `string -> string` etc. This would be a lot +harder to program, and probably not a good idea, as it would be impossible to +search for polymorphic functions. + ## Searching on the command line If you have a search database in `marshal` format, you can search on the command @@ -57,7 +99,8 @@ variable `SHERLODOC_DB` will be used instead. In my example, I gave a query, but if you give none, sherlodoc enter an interactive mode where you can enter queries until you decide to quit. -There are more option documented by `sherlodoc --help`. +There are more option documented by `sherlodoc --help`, some of them are for +debugging/testing purposes, others might be useful. ### Search your switch diff --git a/jsoo/dune b/jsoo/dune index 7cd0b3e6b6..e771b88e3b 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -10,5 +10,5 @@ (install (files sherlodoc.js) - (section bin) + (section share) (package sherlodoc)) diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 9b0bea43d1..5a9a9cb822 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,9 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.168s - user 0m1.131s - sys 0m0.030s + real 0m1.281s + user 0m1.174s + sys 0m0.090s diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 35c16bee01..63c9390dc9 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -50,6 +50,10 @@ val Main.value : moo val Main.produce : unit -> moo val Main.produce_2' : unit -> unit -> moo + $ sherlodoc ":_ -> moo" + val Main.produce : unit -> moo + val Main.produce_2' : unit -> unit -> moo + val Main.value : moo $ sherlodoc ":moo -> _" val Main.consume : moo -> unit val Main.consume_2 : moo -> moo -> unit From 72d7955a8066d13f1542c37ac06a9ea5c7a36d23 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 7 Dec 2023 17:21:53 +0100 Subject: [PATCH 161/285] readme update --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 77b028cace..2a35863d8a 100644 --- a/README.md +++ b/README.md @@ -80,9 +80,10 @@ will only return functions that take a string a argument, no matter what they return. There is limited support for polymorphism : you cannot search for `'a -> 'a` and -get every function `int -> int`, `string -> string` etc. This would be a lot -harder to program, and probably not a good idea, as it would be impossible to -search for polymorphic functions. +get every function `int -> int`, `string -> string` etc. However it will return +a function whose litteral type is `'a -> 'a`. Having the first behaviour would +be a lot harder to program, and probably not a good idea, as it would be +impossible to search for polymorphic functions. ## Searching on the command line From 8602308628982c62d23b441e6f437713b99f8411 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 12:13:41 +0100 Subject: [PATCH 162/285] readme update --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a35863d8a..801b63fab9 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,9 @@ For this to work, you need to generate a search database with format `js`, and then add to every call of `odoc html-generate` the flags `--search-uri sherlodoc.js --search-uri db.js`. `sherlodoc.js` is installed in your path by opam, but `db.js` is the search database you generate and can be renamed as you -wish. +wish. After than you should copy the js files in the right spot. You do need to +have them in correct spot before calling odoc, it does not check if the files +exist. Obviously, most people use dune, and do not call `odoc html-generate`. A patch for dune is being [worked From 4c86eed191b83a2ac71487d945576b7bbedb3d51 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 12:14:01 +0100 Subject: [PATCH 163/285] better output flag --- index/index.ml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index/index.ml b/index/index.ml index 9af1beb616..57ba0763f7 100644 --- a/index/index.ml +++ b/index/index.ml @@ -59,11 +59,15 @@ let db_format = let db_filename = let doc = "Output filename" in - Arg.(required & opt (some string) None & info [ "db" ] ~docv:"DB" ~doc) + Arg.( + required + & opt (some string) None + & info [ "db"; "output"; "o" ] ~docv:"DB" ~doc) + let odoc_files = let doc = "Path to a binary odoc index" in - Arg.(non_empty & (pos_all file [] @@ info ~doc ~docv:"ODOC_FILE" [])) + Arg.(non_empty & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) let index = Term.( From 34e1964631a8e3a1a15c1c7ac786397bb905383f Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 12:14:11 +0100 Subject: [PATCH 164/285] sort test --- test/cram/base.t/run.t | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 5a9a9cb822..b3940af363 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -1,18 +1,19 @@ - $ find . -name '*.odocl' + $ find . -name '*.odocl' | sort + ./base.odocl + ./base_internalhash_types.odocl ./caml.odocl ./md5_lib.odocl - ./base.odocl - ./shadow_stdlib.odocl ./page-index.odocl - ./base_internalhash_types.odocl + ./shadow_stdlib.odocl $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.281s - user 0m1.174s - sys 0m0.090s + real 0m1.186s + user 0m1.140s + sys 0m0.034s + From 8c17c81c1ff00c9b5b3a4f43e3721f6be9f0cbc7 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 12:15:11 +0100 Subject: [PATCH 165/285] typedecl params in cli --- cli/main.ml | 7 +++++- test/cram/base.t/run.t | 44 ++++++++++++++++++------------------- test/cram/cli.t/run.t | 8 +++---- test/cram/cli_small.t/run.t | 4 ++-- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index 507d86549f..d8ad9fb6b9 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -32,6 +32,11 @@ let print_result ~print_cost ~no_rhs ; is_from_module_type = _ } = let score = if print_cost then string_of_int score ^ " " else "" in + let typedecl_params = + (match kind with + | Db.Elt.Kind.TypeDecl args -> args + | _ -> None) |> Option.map (fun str -> str ^ " ") |> Option.value ~default:"" + in let kind = kind |> string_of_kind |> Unescape.string in let name = Unescape.string name in let pp_rhs h = function @@ -39,7 +44,7 @@ let print_result ~print_cost ~no_rhs | Some _ when no_rhs -> () | Some rhs -> Format.fprintf h "%s" (Unescape.string rhs) in - Format.printf "%s%s %s%a\n" score kind name pp_rhs rhs + Format.printf "%s%s %s%s%a\n" score kind typedecl_params name pp_rhs rhs let search ~print_cost ~static_sort ~limit ~db ~no_rhs query = match diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index b3940af363..b28390b78c 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,9 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.186s - user 0m1.140s - sys 0m0.034s + real 0m1.246s + user 0m1.175s + sys 0m0.060s @@ -77,20 +77,20 @@ $ firefox /tmp/html/base/index.html 627 val Base.Hashtbl.S_poly.add 628 val Base.Hashtbl.S_poly.data 628 val Base.Hashtbl.S_poly.keys - 721 type Base.Map.S_poly.t - 721 type Base.Set.S_poly.t + 721 type ('a, 'b) Base.Map.S_poly.t + 721 type 'elt Base.Set.S_poly.t 723 val Base.Map.S_poly.add 723 val Base.Map.S_poly.mem 723 val Base.Set.S_poly.add 723 val Base.Set.S_poly.nth - 723 type Base.Set.S_poly.set + 723 type ('a, 'cmp) Base.Set.S_poly.set 723 val Base.Set.S_poly.sum 724 val Base.Map.S_poly.data 724 val Base.Map.S_poly.keys - 724 type Base.Map.S_poly.tree + 724 type ('a, 'b) Base.Map.S_poly.tree 724 val Base.Set.S_poly.diff - 724 type Base.Set.S_poly.tree - 725 type Base.Hashtbl.S_poly.t + 724 type 'elt Base.Set.S_poly.tree + 725 type ('a, 'b) Base.Hashtbl.S_poly.t 725 val Base.Map.S_poly.empty 725 val Base.Set.S_poly.empty 725 val Base.Set.S_poly.equal @@ -100,7 +100,7 @@ $ firefox /tmp/html/base/index.html 726 val Base.Set.S_poly.choose 726 val Base.Set.S_poly.length 726 val Base.Set.S_poly.remove - 727 type Base.Hashtbl.S_poly.key + 727 type 'a Base.Hashtbl.S_poly.key 727 val Base.Set.S_poly.max_elt 727 val Base.Set.S_poly.min_elt 727 val Base.Set.S_poly.of_list @@ -169,34 +169,34 @@ $ firefox /tmp/html/base/index.html 321 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t 322 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 323 val Base.Array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 340 type Base.Applicative.Make_using_map2.X.t + 340 type 'a Base.Applicative.Make_using_map2.X.t 340 val Base.Applicative.Make_using_map2.all : 'a X.t list -> 'a list X.t - 341 type Base.Applicative.Make2_using_map2.X.t - 341 type Base.Applicative.Make3_using_map2.X.t + 341 type ('a, 'e) Base.Applicative.Make2_using_map2.X.t + 341 type ('a, 'd, 'e) Base.Applicative.Make3_using_map2.X.t 342 val Base.Applicative.Make_using_map2.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] 343 val Base.Applicative.Make2_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] 343 val Base.Applicative.Make3_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] 343 val Base.Applicative.Make_using_map2.return : 'a -> 'a X.t 345 val Base.Applicative.Make_using_map2.X.return : 'a -> 'a t - 347 type Base.Applicative.Make_using_map2_local.X.t - 348 type Base.Applicative.Make2_using_map2_local.X.t - 348 type Base.Applicative.Make3_using_map2_local.X.t + 347 type 'a Base.Applicative.Make_using_map2_local.X.t + 348 type ('a, 'e) Base.Applicative.Make2_using_map2_local.X.t + 348 type ('a, 'd, 'e) Base.Applicative.Make3_using_map2_local.X.t 349 val Base.Applicative.Make_using_map2_local.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] 350 val Base.Applicative.Make2_using_map2_local.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] 350 val Base.Applicative.Make3_using_map2_local.X.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] 623 val Base.Applicative.S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 739 type Base.Applicative.Basic_using_map2.t - 740 type Base.Applicative.Basic2_using_map2.t - 740 type Base.Applicative.Basic3_using_map2.t + 739 type 'a Base.Applicative.Basic_using_map2.t + 740 type ('a, 'e) Base.Applicative.Basic2_using_map2.t + 740 type ('a, 'd, 'e) Base.Applicative.Basic3_using_map2.t 741 val Base.Applicative.Basic_using_map2.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] 742 val Base.Applicative.Basic2_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] 742 val Base.Applicative.Basic3_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - 746 type Base.Applicative.Basic_using_map2_local.t - 747 type Base.Applicative.Basic2_using_map2_local.t - 747 type Base.Applicative.Basic3_using_map2_local.t + 746 type 'a Base.Applicative.Basic_using_map2_local.t + 747 type ('a, 'e) Base.Applicative.Basic2_using_map2_local.t + 747 type ('a, 'd, 'e) Base.Applicative.Basic3_using_map2_local.t 748 val Base.Applicative.Basic_using_map2_local.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] 749 val Base.Applicative.Basic2_using_map2_local.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] 749 val Base.Applicative.Basic3_using_map2_local.map : [ `Define_using_map2 diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 63c9390dc9..2c09c1f58c 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -22,8 +22,8 @@ val Main.Nest.nesting_priority : foo $ sherlodoc "list" mod Main.List - type Main.list - type Main.List.t = 'a list + type 'a Main.list + type 'a Main.List.t = 'a list val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.Map.to_list : foo @@ -67,8 +67,8 @@ mod Main.List mod Main.Nest mod Main.S_to_S1 - type Main.list - type Main.List.t = 'a list + type 'a Main.list + type 'a Main.List.t = 'a list val Main.consume : moo -> unit val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index a95eb3e7a4..5caf0eccf5 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -8,6 +8,6 @@ $ export SHERLODOC_DB=db.bin $ sherlodoc --print-cost "list" 109 mod Main.List - 209 type Main.list - 315 type Main.List.t = 'a list + 209 type 'a Main.list + 315 type 'a Main.List.t = 'a list 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t From 74c2ed667117fc9542894ebc8d5709a0dc40d5a3 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 13:41:17 +0100 Subject: [PATCH 166/285] simpler interface for succ --- query/query.ml | 1 - query/succ.ml | 36 ++++++++++++++++++------------------ query/succ.mli | 14 ++++++-------- query/test/test.ml | 10 ++++------ 4 files changed, 28 insertions(+), 33 deletions(-) diff --git a/query/query.ml b/query/query.ml index 91b1830758..b54c0cbd18 100644 --- a/query/query.ml +++ b/query/query.ml @@ -96,7 +96,6 @@ let api ~(shards : Db.t list) ?(dynamic_sort = true) params = Parser.of_string params.query in let results = search ~shards query_name query_typ in - let results = Succ.finish results in let results = Succ.to_seq ~compare:Db.Elt.compare results in let results = match_packages ~packages:params.packages results in let results = List.of_seq @@ Seq.take params.limit results in diff --git a/query/succ.ml b/query/succ.ml index 4e9f32c2b9..4cd538301b 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,11 +1,11 @@ -type 'a t = +type 'a node = | All | Empty | Array of 'a array - | Inter of 'a t * 'a t - | Union of 'a t * 'a t + | Inter of 'a node * 'a node + | Union of 'a node * 'a node -let rec print a ~depth s = +let rec print_node a ~depth s = print_string (String.make (depth * 4) ' ') ; let depth = depth + 1 in match s with @@ -13,12 +13,12 @@ let rec print a ~depth s = | Empty -> print_endline "Empty" | Inter (l, r) -> print_endline "Inter" ; - print a ~depth l ; - print a ~depth r + print_node a ~depth l ; + print_node a ~depth r | Union (l, r) -> print_endline "Union" ; - print a ~depth l ; - print a ~depth r + print_node a ~depth l ; + print_node a ~depth r | Array arr -> print_string "{ " ; Array.iter @@ -28,7 +28,7 @@ let rec print a ~depth s = arr ; print_endline "}" -let print a s = print a ~depth:0 s +let print_node a s = print_node a ~depth:0 s let best ~compare x y = match compare x y with @@ -85,13 +85,18 @@ let rec first ~compare t = best_opt ~compare elt_l elt_r end -let to_seq ~compare t = +type 'a t = + { cardinal : int + ; s : 'a node + } + +let to_seq ~compare { s; _ } = let state = ref None in let loop () = let elt = match !state with - | None -> first ~compare t - | Some previous_elt -> succ ~strictness:Gt ~compare t previous_elt + | None -> first ~compare s + | Some previous_elt -> succ ~strictness:Gt ~compare s previous_elt in state := elt ; elt @@ -110,12 +115,6 @@ let to_seq ~compare t = (** Functions to build a succ tree *) -type 'a builder = - { cardinal : int - ; s : 'a t - } - -let finish a = a.s let all = { cardinal = -1; s = All } let empty = { cardinal = 0; s = Empty } @@ -160,3 +159,4 @@ let union_of_array arr = loop 0 (Array.length arr) let union_of_list li = li |> Array.of_list |> union_of_array +let print a { s; _ } = print_node a s diff --git a/query/succ.mli b/query/succ.mli index 4ef264fc9f..29218325a5 100644 --- a/query/succ.mli +++ b/query/succ.mli @@ -8,19 +8,17 @@ val to_seq : compare:('a -> 'a -> int) -> 'a t -> 'a Seq.t (** Functions to build a succ tree *) -type 'a builder -val finish : 'a builder -> 'a t -val all : 'a builder -val empty : 'a builder +val all : 'a t +val empty : 'a t -val of_array : 'a array -> 'a builder +val of_array : 'a array -> 'a t (** Warning : only provide a sorted array, this is not checked ! It has to be sorted according to the [compare] function that you will eventually pass to [to_seq]. *) -val inter : 'a builder -> 'a builder -> 'a builder -val union : 'a builder -> 'a builder -> 'a builder +val inter : 'a t -> 'a t -> 'a t +val union : 'a t -> 'a t -> 'a t -val union_of_list : 'a builder list -> 'a builder +val union_of_list : 'a t list -> 'a t (** [union_of_list] has better performance than [List.fold_left union empty]. *) diff --git a/query/test/test.ml b/query/test/test.ml index ba05cf12b9..b810004a7c 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -65,7 +65,7 @@ module Test_array = struct end module Test_succ = struct - (** This module does the same thing as Succ, but its correctness is obvious + (** This module does the same thing as Succ, but its correctness is obvious and its performance terrible. *) module Reference = struct include Set.Make (Int) @@ -74,22 +74,20 @@ module Test_succ = struct let to_seq ~compare:_ = to_seq end - (** This module is used to construct a pair of a "set array" using [Reference] + (** This module is used to construct a pair of a "set array" using [Reference] and a Succ that are exactly the same. *) module Both = struct let empty = Reference.empty, Succ.empty let union (l, l') (r, r') = Reference.union l r, Succ.union l' r' let inter (l, l') (r, r') = Reference.inter l r, Succ.inter l' r' let of_array arr = Reference.of_array arr, Succ.of_array arr - let finish (arr, succ) = arr, Succ.finish succ end (** This is a problematic exemple that was found randomly. It is saved here to check for regressions. *) let extra_succ = Both.( - finish - @@ union + union (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |]))) @@ -119,7 +117,7 @@ module Test_succ = struct @ List.init 50 (fun i -> let i = i * 7 in let succ = - i |> Both.(random_set ~empty ~union ~inter ~of_array) |> Both.finish + i |> Both.(random_set ~empty ~union ~inter ~of_array) in Alcotest.test_case (Printf.sprintf "Succ.to_seq size %i" i) From 4841740cd4371ef2356183db58f2b9ea8a12f439 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 14:29:02 +0100 Subject: [PATCH 167/285] reafctoring and comments --- cli/main.ml | 4 +++- db/db.mli | 8 +++++++ db/suffix_tree.mli | 8 ++++++- index/index.ml | 1 - index/load_doc.ml | 52 ++++++++++++++++++++++++++-------------------- query/query.mli | 24 +++++++++++++++++++++ query/succ.mli | 1 - query/test/test.ml | 8 +++---- 8 files changed, 75 insertions(+), 31 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index d8ad9fb6b9..ec6cf8bb2b 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -35,7 +35,9 @@ let print_result ~print_cost ~no_rhs let typedecl_params = (match kind with | Db.Elt.Kind.TypeDecl args -> args - | _ -> None) |> Option.map (fun str -> str ^ " ") |> Option.value ~default:"" + | _ -> None) + |> Option.map (fun str -> str ^ " ") + |> Option.value ~default:"" in let kind = kind |> string_of_kind |> Unescape.string in let name = Unescape.string name in diff --git a/db/db.mli b/db/db.mli index 994bcd466a..837c8a0a17 100644 --- a/db/db.mli +++ b/db/db.mli @@ -8,6 +8,14 @@ type t = Types.t = { db_names : Suffix_tree.With_elts.reader ; db_types : Suffix_tree.With_occ.reader } +(** The type of a database. + [db_names] is for text-based part of the query and [db_types] for the + type-based part. + [db_types] has [Elt.t array Int_map.t] ([Occ.t]) as a payload because we want + the query [blabla : int -> int -> _] to return only entries that take at + least two ints as arguments, an entry of type [int -> string] is invalid. + The int_map map a number of occurences to a set of entries. + *) type writer diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index 491d5f9313..fbf48d8279 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -19,7 +19,8 @@ module Make (S : SET) : sig val add_suffixes : writer -> string -> S.elt -> unit type reader - (** A reader is a completed suffix tree. You can make queries on it.*) + (** A reader is a completed suffix tree. You can make queries on it. Its size + is smaller than the equivalent [writer]. *) val export : writer -> reader val find : reader -> string -> reader option @@ -27,4 +28,9 @@ module Make (S : SET) : sig end module With_elts : module type of Make (Elt.Array) +(** [With_elts] is a suffix tree with array of elts at the leafs. It is used for + the text-based part of the database. *) + module With_occ : module type of Make (Occ) +(** [With_occ] is a suffix tree with occurence annotated arrays of elts at the + leafs. It is used for the type-based part of the database. *) diff --git a/index/index.ml b/index/index.ml index 57ba0763f7..ca5207ba2f 100644 --- a/index/index.ml +++ b/index/index.ml @@ -64,7 +64,6 @@ let db_filename = & opt (some string) None & info [ "db"; "output"; "o" ] ~docv:"DB" ~doc) - let odoc_files = let doc = "Path to a binary odoc index" in Arg.(non_empty & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) diff --git a/index/load_doc.ml b/index/load_doc.ml index 7e4061a400..2cf3e501db 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -32,7 +32,6 @@ let cost ~name ~kind ~doc_html = | _ -> false in let has_doc = doc_html <> "" in - (* TODO : use entry cost *) generic_cost ~ignore_no_doc name has_doc + kind_cost kind (* @@ -65,8 +64,7 @@ let all_type_names t = let fullname = fullname t in tails (String.split_on_char '.' fullname) -(** for scoring *) -let rec paths ~prefix ~sgn t = +let rec type_distance_paths ~prefix ~sgn t = match t with | Odoc_model.Lang.TypeExpr.Var _ -> let poly = "POLY" in @@ -78,8 +76,8 @@ let rec paths ~prefix ~sgn t = let prefix_left = "->0" :: prefix in let prefix_right = "->1" :: prefix in List.rev_append - (paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) - (paths ~prefix:prefix_right ~sgn b) + (type_distance_paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) + (type_distance_paths ~prefix:prefix_right ~sgn b) | Constr (name, args) -> let name = fullname name in let prefix = name :: Types.string_of_sgn sgn :: prefix in @@ -91,14 +89,14 @@ let rec paths ~prefix ~sgn t = @@ List.mapi (fun i arg -> let prefix = string_of_int i :: prefix in - paths ~prefix ~sgn arg) + type_distance_paths ~prefix ~sgn arg) args end | Tuple args -> rev_concat @@ List.mapi (fun i arg -> let prefix = (string_of_int i ^ "*") :: prefix in - paths ~prefix ~sgn arg) + type_distance_paths ~prefix ~sgn arg) @@ args | _ -> [] @@ -118,22 +116,24 @@ let rec hcons = function Hashtbl.add hcons_tbl (uid_xs, x) result ; result) -let paths typ = +(** [type_distance_paths ~prefix ~sgn t] is a [string list list] representing + the type [t]. It allows to compute the distance between two types. It is + stored in the database to sort results once they are obtained. *) +let type_distance_paths typ = List.map (fun xs -> let _, xs = hcons xs in xs) - (paths ~prefix:[] ~sgn:Pos typ) + (type_distance_paths ~prefix:[] ~sgn:Pos typ) -(** for indexing *) -let rec type_paths ~prefix ~sgn = function +let rec suffix_tree_type_paths ~prefix ~sgn = function | Odoc_model.Lang.TypeExpr.Var _ -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] | Any -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] | Arrow (_lbl, a, b) -> List.rev_append - (type_paths ~prefix ~sgn:(Types.sgn_not sgn) a) - (type_paths ~prefix ~sgn b) + (suffix_tree_type_paths ~prefix ~sgn:(Types.sgn_not sgn) a) + (suffix_tree_type_paths ~prefix ~sgn b) | Constr (name, args) -> name |> all_type_names |> List.map (fun name -> @@ -147,14 +147,20 @@ let rec type_paths ~prefix ~sgn = function @@ List.mapi (fun i arg -> let prefix = string_of_int i :: prefix in - type_paths ~prefix ~sgn arg) + suffix_tree_type_paths ~prefix ~sgn arg) args end) |> rev_concat - | Tuple args -> rev_concat @@ List.map (type_paths ~prefix ~sgn) @@ args + | Tuple args -> + rev_concat @@ List.map (suffix_tree_type_paths ~prefix ~sgn) @@ args | _ -> [] -let type_paths ~prefix ~sgn t = type_paths ~prefix ~sgn t +(** [suffix_tree_type_paths ~prefix ~sgn t] is a representation of [t] that + encodes the polarity of the elements of the type : in [string -> int] [int] + is positive and [string] negative. + It is registered in the database and search-base type uses this to obtain + results that fit the type asked for by the user. *) +let suffix_tree_type_paths t = suffix_tree_type_paths ~prefix:[] ~sgn:Pos t let with_tokenizer str fn = let str = String.lowercase_ascii str in @@ -212,19 +218,21 @@ let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = Elt.Kind.TypeDecl (Odoc_search.Html.typedecl_params_of_entry entry) | Module -> Elt.Kind.Module | Value { value = _; type_ } -> - let paths = paths type_ in + let paths = type_distance_paths type_ in Elt.Kind.val_ paths | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = paths searchable_type in + let paths = type_distance_paths searchable_type in Elt.Kind.constructor paths | Field { mutable_ = _; parent_type; type_ } -> - let paths = type_ |> searchable_type_of_record parent_type |> paths in + let paths = + type_ |> searchable_type_of_record parent_type |> type_distance_paths + in Elt.Kind.field paths | Doc _ -> Doc | Exception { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = paths searchable_type in + let paths = type_distance_paths searchable_type in Elt.Kind.exception_ paths | Class_type _ -> Class_type | Method _ -> Method @@ -232,12 +240,12 @@ let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = | TypeExtension _ -> TypeExtension | ExtensionConstructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = paths searchable_type in + let paths = type_distance_paths searchable_type in Elt.Kind.extension_constructor paths | ModuleType -> ModuleType let register_type_expr ~db elt type_ = - let type_paths = type_paths ~prefix:[] ~sgn:Pos type_ in + let type_paths = suffix_tree_type_paths type_ in Db.store_type_paths db elt type_paths let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.kind) = diff --git a/query/query.mli b/query/query.mli index ff2acddf2d..268719cd66 100644 --- a/query/query.mli +++ b/query/query.mli @@ -5,6 +5,30 @@ type t = } val api : shards:Db.t list -> ?dynamic_sort:bool -> t -> string * Db.Elt.t list +(** [api ~shard ~dynamic_sort {query; packages; limit}] returns [(pretty_query, + results)] where [pretty_query] is a re-printed version of [query] and + [results] is the list of results corresponding to the query and the + various parameters. + + - [shards] is a list of databases. [results] is the union of the results of + each database of the list [shards]. If [shards] is a very long list, [api] + might be slow to return, but in some cases you do not have a choice. + Currently, [index] generates only one shard, but it used to generate many + to be able to handle the sheer size of the opam repository. + + - [~dynamic_sort] changes the order of [results]. It is [true] by default, + and is only set to [false] for debugging purposes. + + - [query] is the query string whose shape is a list of space-separated + words, followed by an optionnal [: ...] type annotation that filters the + results by type. The type annotation accepts [_] as a wildcard : [: string + -> _] will return entries that take a [string] as argument, but returns + anything. + + - [limit] is the maximum length of [results]. Having a very large number + might be an issue. + + - [packages] is not function, use [[]] for this argument. *) (** For testing *) module Private : sig diff --git a/query/succ.mli b/query/succ.mli index 29218325a5..9ca7a34909 100644 --- a/query/succ.mli +++ b/query/succ.mli @@ -8,7 +8,6 @@ val to_seq : compare:('a -> 'a -> int) -> 'a t -> 'a Seq.t (** Functions to build a succ tree *) - val all : 'a t val empty : 'a t diff --git a/query/test/test.ml b/query/test/test.ml index b810004a7c..500569c7d5 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -88,8 +88,8 @@ module Test_succ = struct let extra_succ = Both.( union - (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) - (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |]))) + (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) + (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |]))) let rec random_set ~empty ~union ~inter ~of_array size = let random_set = random_set ~empty ~union ~inter ~of_array in @@ -116,9 +116,7 @@ module Test_succ = struct [ Alcotest.test_case "Succ.to_seq extra" `Quick (test_to_seq extra_succ) ] @ List.init 50 (fun i -> let i = i * 7 in - let succ = - i |> Both.(random_set ~empty ~union ~inter ~of_array) - in + let succ = i |> Both.(random_set ~empty ~union ~inter ~of_array) in Alcotest.test_case (Printf.sprintf "Succ.to_seq size %i" i) `Quick (test_to_seq succ)) From 1bec9c5aa47a2a05bdbf10892c2b9be3c43e326c Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 14:39:28 +0100 Subject: [PATCH 168/285] document dune files --- cli/dune | 3 +++ db/dune | 2 ++ index/dune | 3 +++ jsoo/dune | 3 +++ query/dune | 3 +++ store/dune | 4 +++- www/dune | 3 +++ 7 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cli/dune b/cli/dune index a6c3a958e0..a7f4ccdbed 100644 --- a/cli/dune +++ b/cli/dune @@ -1,3 +1,6 @@ +; This binary is usef to perform searches on the command line. It needs a +; database and a query as input, and print results on the command line. + (ocamllex unescape) (executable diff --git a/db/dune b/db/dune index aada4a6e19..db9aea5cea 100644 --- a/db/dune +++ b/db/dune @@ -1,3 +1,5 @@ +; [db] is the database data-structure for sherlodoc. + (library (name db) (libraries unix)) diff --git a/index/dune b/index/dune index 8079c7695a..29b91482c9 100644 --- a/index/dune +++ b/index/dune @@ -1,3 +1,6 @@ +; `sherlodoc_index` is an executable that build a database for sherlodoc taking +; odocl files as input. + (executable (public_name sherlodoc_index) (name index) diff --git a/jsoo/dune b/jsoo/dune index e771b88e3b..590da45332 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -1,3 +1,6 @@ +; This provides a javascript file for sherlodoc searches. This is compatible +; with the api decided by odoc. + (executable (name main) (modes js) diff --git a/query/dune b/query/dune index 272e4e5a00..f78522e1df 100644 --- a/query/dune +++ b/query/dune @@ -1,3 +1,6 @@ +; This library give functions to meaningfully query the database datastructure +; defined in `db`. + (library (name query) (libraries lwt re db)) diff --git a/store/dune b/store/dune index 2fe93ddc10..e8d51b8b9c 100644 --- a/store/dune +++ b/store/dune @@ -1,4 +1,6 @@ -; This directory contains modules for storing search databases. +; This directory contains modules for storing search databases. The +; datastructure itself is the same each time, but the serialisation format is +; different. (library (name storage_ancient) diff --git a/www/dune b/www/dune index 30d027709f..e3fa5b90bd 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,6 @@ +; This is a server to answer sherlocode queries. A version of this runs on +; https://doc.sherlocode.com + (executable (public_name sherlodoc-www) (name www) From 7d318c1b9355f2408f4546ac6c8d343bbd594431 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 14:51:18 +0100 Subject: [PATCH 169/285] better readme --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 801b63fab9..85a9fe60c6 100644 --- a/README.md +++ b/README.md @@ -135,11 +135,15 @@ embedded. For this to work, you need to generate a search database with format `js`, and then add to every call of `odoc html-generate` the flags `--search-uri -sherlodoc.js --search-uri db.js`. `sherlodoc.js` is installed in your path by -opam, but `db.js` is the search database you generate and can be renamed as you -wish. After than you should copy the js files in the right spot. You do need to -have them in correct spot before calling odoc, it does not check if the files -exist. +sherlodoc.js --search-uri db.js`. + +Be sure to copy the two js files in the output directory given to the +html-generate command : + +```bash +cp $OPAM_SWITCH_PREFIX/share/sherlodoc/sherlodoc.js html_output/sherlodoc.js ; +cp db.js html_output/db.js ; +``` Obviously, most people use dune, and do not call `odoc html-generate`. A patch for dune is being [worked From 2945002954654102de95b56e9cf478d12e2353f9 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 14:52:32 +0100 Subject: [PATCH 170/285] add temporary review file --- review.md | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 review.md diff --git a/review.md b/review.md new file mode 100644 index 0000000000..afd3b8aedb --- /dev/null +++ b/review.md @@ -0,0 +1,107 @@ +# review sherlodoc + +# To discuss + +- Réfléchir à `ancient`: enlever pour de bon, rétablir le support ? +- Tester de virer la compression? +- Type extensions: we might want to search for all extensions of a given extensible type. + +- pretty-query: vraiment necessaire ? + +# done + +- `sherlodoc_index` `--db` pourrait avoir pour alias `-o` done + +- piper les test avec find dans sort: more robust tests? + +- About search-uri: either remove or precise comment (see "If they are relative, +they are interpreted as relative to the `-o` option") + +- gérer les typedecl_param dans la CLI? + +- Factor or reuse kind to string function in cli to use odoc conversion. Put it in `elt.ml`? + > No because db does not have a dep on odoc, and it arguably does not need one + +- Make it one single type in `succ.mli` (builder vs t) + + +# Commentaires/Action Point/... + +- Option prendre un fichier contenant la liste des `odocl` ? + +- Have something more robust than sizes in tests. Remove them, and use + current-bench or just a manual benchmark. +- `index` supprimer les `.db` + +- la limitation sur le packages de query n'est plus vraiment fonctionelle + +- Documenter parser/lexer de query. + +- `Index.Load_doc.with_tokenizer`: think of which character form a word + +- It would be cool to be able to see the string corresponding to types, and also of the intermediate string list list + +- Maybe store all "arbitrary constants" relative to the cost function somewhere + + + +- `succ.ml` : remove `All` + +- `succ.ml` : soit catcher uniquement StackOverflow, soit catcher tout mais moins profondément !? Dans le jsoo sans doute. + +- `Succ.All` is used in `query.ml` + +# Explications commentée + +## Index + +- shard est la liste des parties éclatée de la bdd, pour des raisons de mémoire + plus que de performcances. Maintenant il n'y en a toujours plus qu'un mais ça + a été gardé. Functionel, mais index n'est plus capable de générer des shards... +- `With_elts` -> pour la partie type-agnostic de la recherche +- `With_occ` -> pour la partie purely type-dependent de la recherche + +## Indexation + +# Notes personnelles/explications/... + +## Index + + + +### Indexation + +Pour les textes, c'est facile : +- On crée le payload à partir de la search entry +- On ajoute ça au writer + +Pour les types, ça marche pareil mais on doit transformer le type en une string. +Cela est fait par les fonctions suivantes: +- `Load_doc.type_paths` qui prend + - en entrée le type vu par odoc, un prefix (?) et un signe + - en sortie, une string list list. Un élément de la liste est une "feuille", l'ordre n'ayant pas d'importance. +- `Db.store_type_path` qui transforme la `string list list` en "concaténant les + path regroupés !" (qui compte les occurrences de chaque type) + +## Hierarchy structure + +Folders: + +- `db/` is for the db datastructure. Two datastructures: one for the type + agnostic part (`db_names`, or `with_elts`) and one for the type-centric part + of the query (`db_types`, or `with_occs`) +- `index/` is for the action of indexing. Includes a binary. +- `jsoo` the js access to perform query. Compile to a js file to run on a webworker. Read the (marhsalled, + compressed) db from a global variable: `sherlodoc_db`. +- `cli/` the `cli` access to perform queries. Load the db from a file. +- `store/` is the access to the database. The two directories above (`jsoo` and + `cli`) use the `storage_js` and `storage_marshal` modules for their purpose. +- `www/` for the webserver running on . +- `static/` static files also for the webserver +- `test/` self-explained +- `query/` defines queries and perform them + + + + + From 919ad336393e557978cefa21e012d0ad82f89821 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 15:11:15 +0100 Subject: [PATCH 171/285] better index cli --- README.md | 21 ++++++++++++--------- index/index.ml | 24 ++++++++++++++++++++---- review.md | 2 +- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 85a9fe60c6..1c3c0abf48 100644 --- a/README.md +++ b/README.md @@ -25,18 +25,21 @@ The first step to using sherlodoc is generating a search-database. You do this with the command `sherlodoc_index` : ```bash -sherlodoc_index --format=marshal --db=db.bin a.odocl b.odocl +sherlodoc_index --format=marshal -o db.bin a.odocl b.odocl ``` The `--format` option determines in which format the database is outputted. The -available format are `marshal`, `js` and `ancient`. `ancient` is not supported -at the moment, but we might bring it back. The `js` format, for javascript, is -the one compatible with odoc, and the `marshal` for most other uses. `ancient` -uses `` and you should use it if you know what you are -doing. It is used for the [online](https://doc.sherlocode.com) version of -sherlodoc. +available format are `marshal`, `js`. The `js` format, for +javascript, is the one compatible with odoc, and the `marshal` for most other +uses. -The `--db` option is the filename of the output. +The used to be a third format : `ancient`. It is more complicated than the other +two, you can read on it [here](https://github.com/UnixJunkie/ocaml-ancient). It +is used for the [online](https://doc.sherlocode.com) version of sherlodoc. We +might bring it back with some dune magic (as some sort of optionnal dependency, +it is not compatible with OCaml 5). + +The `-o` option is the filename of the output. Then you need to provide a list of .odocl files that contains the signatures items that are going to be searchable. They are build artifacts of odoc. @@ -118,7 +121,7 @@ odig odoc Generate the search database : ```bash -sherlodoc_index --format=marshal --db=db.bin $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc -name "*.odocl") +sherlodoc_index --format=marshal -o db.bin $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc -name "*.odocl") ``` Enjoy searching : diff --git a/index/index.ml b/index/index.ml index ca5207ba2f..001fb5d2b5 100644 --- a/index/index.ml +++ b/index/index.ml @@ -23,7 +23,8 @@ let storage_module = function | `marshal -> (module Storage_marshal : Db.Storage.S) | `js -> (module Storage_js : Db.Storage.S) -let main files index_docstring index_name type_search db_filename db_format = +let main files file_list index_docstring index_name type_search db_filename + db_format = let module Storage = (val storage_module db_format) in let db = Db.make () in let register id () item = @@ -32,6 +33,13 @@ let main files index_docstring index_name type_search db_filename db_format = (Odoc_search.Entry.entries_of_item id item) in let h = Storage.open_out db_filename in + let files = + match file_list with + | None -> files + | Some file_list -> + let file_list = open_in file_list in + files @ (file_list |> In_channel.input_all |> String.split_on_char '\n') + in List.iter (index_file register) files ; let t = Db.export db in Storage.save ~db:h t ; @@ -64,14 +72,22 @@ let db_filename = & opt (some string) None & info [ "db"; "output"; "o" ] ~docv:"DB" ~doc) +let file_list = + let doc = + "File containing a list of .odocl files.\n\ + Useful for system where there is a limit on the number of arguments to a \ + command." + in + Arg.(value & opt (some file) None & info [ "file-list" ] ~doc) + let odoc_files = - let doc = "Path to a binary odoc index" in + let doc = "Path to a .odocl file" in Arg.(non_empty & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) let index = Term.( - const main $ odoc_files $ index_docstring $ index_name $ type_search - $ db_filename $ db_format) + const main $ odoc_files $ file_list $ index_docstring $ index_name + $ type_search $ db_filename $ db_format) let cmd = let doc = "Index odocl files" in diff --git a/review.md b/review.md index afd3b8aedb..654e9e32ad 100644 --- a/review.md +++ b/review.md @@ -24,10 +24,10 @@ they are interpreted as relative to the `-o` option") - Make it one single type in `succ.mli` (builder vs t) +- Option prendre un fichier contenant la liste des `odocl` ? # Commentaires/Action Point/... -- Option prendre un fichier contenant la liste des `odocl` ? - Have something more robust than sizes in tests. Remove them, and use current-bench or just a manual benchmark. From 69b863660c79d912b1de1195eecb025862cae9dd Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 17:14:21 +0100 Subject: [PATCH 172/285] review update --- review.md | 50 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/review.md b/review.md index 654e9e32ad..a5f42f1879 100644 --- a/review.md +++ b/review.md @@ -2,12 +2,18 @@ # To discuss -- Réfléchir à `ancient`: enlever pour de bon, rétablir le support ? - Tester de virer la compression? + - Type extensions: we might want to search for all extensions of a given extensible type. +## With Arthur + +- Réfléchir à `ancient`: enlever pour de bon, rétablir le support ? + - pretty-query: vraiment necessaire ? +- ask about `Query.paths_arrow` vs `index/load_doc.type_distance_paths` + # done - `sherlodoc_index` `--db` pourrait avoir pour alias `-o` done @@ -26,12 +32,18 @@ they are interpreted as relative to the `-o` option") - Option prendre un fichier contenant la liste des `odocl` ? +- `index` supprimer les `.db` + # Commentaires/Action Point/... +- refactor `Query.paths_arrow` vs `index/load_doc.type_distance_paths` + `Query.paths_arrow` is the right implementation, load_doc should tranform the + odoc typeexpr into a sherlodoc query ast typeexpr and then only compute the + path. + Be careful about hash consing. - Have something more robust than sizes in tests. Remove them, and use current-bench or just a manual benchmark. -- `index` supprimer les `.db` - la limitation sur le packages de query n'est plus vraiment fonctionelle @@ -63,6 +75,24 @@ they are interpreted as relative to the `-o` option") ## Indexation +## Hierarchy structure + +Folders: + +- `db/` is for the db datastructure. Two datastructures: one for the type + agnostic part (`db_names`, or `with_elts`) and one for the type-centric part + of the query (`db_types`, or `with_occs`) +- `index/` is for the action of indexing. Includes a binary. +- `jsoo` the js access to perform query. Compile to a js file to run on a webworker. Read the (marhsalled, + compressed) db from a global variable: `sherlodoc_db`. +- `cli/` the `cli` access to perform queries. Load the db from a file. +- `store/` is the access to the database. The two directories above (`jsoo` and + `cli`) use the `storage_js` and `storage_marshal` modules for their purpose. +- `www/` for the webserver running on . +- `static/` static files also for the webserver +- `test/` self-explained +- `query/` defines queries and perform them + # Notes personnelles/explications/... ## Index @@ -83,23 +113,7 @@ Cela est fait par les fonctions suivantes: - `Db.store_type_path` qui transforme la `string list list` en "concaténant les path regroupés !" (qui compte les occurrences de chaque type) -## Hierarchy structure -Folders: - -- `db/` is for the db datastructure. Two datastructures: one for the type - agnostic part (`db_names`, or `with_elts`) and one for the type-centric part - of the query (`db_types`, or `with_occs`) -- `index/` is for the action of indexing. Includes a binary. -- `jsoo` the js access to perform query. Compile to a js file to run on a webworker. Read the (marhsalled, - compressed) db from a global variable: `sherlodoc_db`. -- `cli/` the `cli` access to perform queries. Load the db from a file. -- `store/` is the access to the database. The two directories above (`jsoo` and - `cli`) use the `storage_js` and `storage_marshal` modules for their purpose. -- `www/` for the webserver running on . -- `static/` static files also for the webserver -- `test/` self-explained -- `query/` defines queries and perform them From f1cc33261bc1ffb7ce3059edbf9fe96aeddbeb78 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 12 Dec 2023 17:14:52 +0100 Subject: [PATCH 173/285] ancient support ! --- README.md | 10 +++++----- dune-project | 3 ++- index/ancient.available.ml | 6 ++++++ index/ancient.unavailable.ml | 5 +++++ index/dune | 6 +++++- index/index.ml | 9 ++------- review.md | 5 ++++- sherlodoc.opam | 1 + store/dune | 3 ++- 9 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 index/ancient.available.ml create mode 100644 index/ancient.unavailable.ml diff --git a/README.md b/README.md index 1c3c0abf48..543a58aedf 100644 --- a/README.md +++ b/README.md @@ -33,11 +33,11 @@ available format are `marshal`, `js`. The `js` format, for javascript, is the one compatible with odoc, and the `marshal` for most other uses. -The used to be a third format : `ancient`. It is more complicated than the other -two, you can read on it [here](https://github.com/UnixJunkie/ocaml-ancient). It -is used for the [online](https://doc.sherlocode.com) version of sherlodoc. We -might bring it back with some dune magic (as some sort of optionnal dependency, -it is not compatible with OCaml 5). +There is a third format : `ancient`, that is only available if the `ancient` +package is installed. It is more complicated than the other two, you can read on +it [here](https://github.com/UnixJunkie/ocaml-ancient). It is used for the +[online](https://doc.sherlocode.com) version of sherlodoc, and is a mandatory +dependency of the `sherlodoc-www` package. The `-o` option is the filename of the output. diff --git a/dune-project b/dune-project index e9eaf30f26..1598be2f51 100644 --- a/dune-project +++ b/dune-project @@ -41,7 +41,8 @@ (>= 4.6.0)) (brr (>= 0.0.6)) - (alcotest :with-test))) + (alcotest :with-test)) + (depopts ancient)) (package (name sherlodoc-www) diff --git a/index/ancient.available.ml b/index/ancient.available.ml new file mode 100644 index 0000000000..b5a09fc550 --- /dev/null +++ b/index/ancient.available.ml @@ -0,0 +1,6 @@ +let arg_enum = [ "ancient", `ancient ] + +let storage_module = function + | `ancient -> (module Storage_ancient : Db.Storage.S) + | `marshal -> (module Storage_marshal : Db.Storage.S) + | `js -> (module Storage_js : Db.Storage.S) diff --git a/index/ancient.unavailable.ml b/index/ancient.unavailable.ml new file mode 100644 index 0000000000..403368f8d0 --- /dev/null +++ b/index/ancient.unavailable.ml @@ -0,0 +1,5 @@ +let arg_enum = [] + +let storage_module = function + | `marshal -> (module Storage_marshal : Db.Storage.S) + | `js -> (module Storage_js : Db.Storage.S) diff --git a/index/dune b/index/dune index 29b91482c9..77378ac342 100644 --- a/index/dune +++ b/index/dune @@ -6,6 +6,11 @@ (name index) (package sherlodoc) (libraries + (select + ancient.ml + from + (storage_ancient -> ancient.available.ml) + (!storage_ancient -> ancient.unavailable.ml)) db fpath tyxml @@ -16,6 +21,5 @@ odoc.xref2 odoc.odoc cmdliner - ; storage_ancient storage_marshal storage_js)) diff --git a/index/index.ml b/index/index.ml index 001fb5d2b5..d1e6b28169 100644 --- a/index/index.ml +++ b/index/index.ml @@ -16,12 +16,7 @@ let index_file register filename = | Error (`Msg msg) -> Format.printf "Odoc warning or error %s: %s@." filename msg) -let storage_module = function - | `ancient -> - (* (module Storage_ancient : Db.Storage.S) *) - failwith "TODO" - | `marshal -> (module Storage_marshal : Db.Storage.S) - | `js -> (module Storage_js : Db.Storage.S) +let storage_module = Ancient.storage_module let main files file_list index_docstring index_name type_search db_filename db_format = @@ -61,7 +56,7 @@ let type_search = let db_format = let doc = "Database format" in - let kind = Arg.enum [ "ancient", `ancient; "marshal", `marshal; "js", `js ] in + let kind = Arg.enum (Ancient.arg_enum @ [ "marshal", `marshal; "js", `js ]) in Arg.( required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) diff --git a/review.md b/review.md index a5f42f1879..6ad12bd22e 100644 --- a/review.md +++ b/review.md @@ -8,7 +8,7 @@ ## With Arthur -- Réfléchir à `ancient`: enlever pour de bon, rétablir le support ? + - pretty-query: vraiment necessaire ? @@ -16,6 +16,9 @@ # done +- Réfléchir à `ancient`: enlever pour de bon, rétablir le support ? +Support is reestablished + - `sherlodoc_index` `--db` pourrait avoir pour alias `-o` done - piper les test avec find dans sort: more robust tests? diff --git a/sherlodoc.opam b/sherlodoc.opam index a5277d2f4d..249e756518 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -20,6 +20,7 @@ depends: [ "brr" {>= "0.0.6"} "alcotest" {with-test} ] +depopts: ["ancient"] build: [ ["dune" "subst"] {dev} [ diff --git a/store/dune b/store/dune index e8d51b8b9c..e163916e18 100644 --- a/store/dune +++ b/store/dune @@ -5,7 +5,8 @@ (library (name storage_ancient) (modules storage_ancient) - (libraries ancient db)) + (optional) + (libraries db ancient)) (library (name storage_js) From 5bbe1fbfa99294de366a3aa828cdeb3274a5f010 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 13 Dec 2023 11:16:01 +0100 Subject: [PATCH 174/285] Remove Succ.all --- query/query.ml | 6 ++---- query/succ.ml | 13 +++++-------- query/succ.mli | 3 ++- review.md | 3 ++- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/query/query.ml b/query/query.ml index b54c0cbd18..e576d336d2 100644 --- a/query/query.ml +++ b/query/query.ml @@ -11,8 +11,6 @@ module Private = struct module Succ = Succ end -let inter_list xs = List.fold_left Succ.inter Succ.all xs - let collapse_occ ~count occs = Occ.fold (fun k x acc -> if k < count then acc else Succ.union (Succ.of_array x) acc) @@ -35,7 +33,7 @@ let find_types ~shards names = (fun acc shard -> let db = shard.db_types in let r = - inter_list + Succ.inter_of_list @@ List.map (fun (name, count) -> let name' = String.concat "" name in @@ -60,7 +58,7 @@ let find_names ~(shards : Db.t list) names = | None -> Succ.empty) names in - let candidates = inter_list candidates in + let candidates = Succ.inter_of_list candidates in Succ.union acc candidates) Succ.empty shards diff --git a/query/succ.ml b/query/succ.ml index 4cd538301b..987baf4296 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,5 +1,4 @@ type 'a node = - | All | Empty | Array of 'a array | Inter of 'a node * 'a node @@ -9,7 +8,6 @@ let rec print_node a ~depth s = print_string (String.make (depth * 4) ' ') ; let depth = depth + 1 in match s with - | All -> print_endline "All" | Empty -> print_endline "Empty" | Inter (l, r) -> print_endline "Inter" ; @@ -55,7 +53,6 @@ let array_succ ~strictness = let rec succ ~compare ~strictness t elt = match t with - | All -> invalid_arg "Succ.succ_rec All" | Empty -> None | Array arr -> array_succ ~strictness ~compare elt arr | Union (l, r) -> @@ -73,7 +70,6 @@ let rec succ ~compare ~strictness t elt = let rec first ~compare t = match t with - | All -> invalid_arg "Succ.first All" | Empty -> None | Array s -> Some s.(0) | Inter (l, _) -> @@ -115,7 +111,6 @@ let to_seq ~compare { s; _ } = (** Functions to build a succ tree *) -let all = { cardinal = -1; s = All } let empty = { cardinal = 0; s = Empty } let of_array arr = @@ -126,8 +121,6 @@ let of_array arr = let inter a b = match a.s, b.s with | Empty, _ | _, Empty -> empty - | _, All -> a - | All, _ -> b | x, y when x == y -> a | x, y -> let x, y = if a.cardinal < b.cardinal then x, y else y, x in @@ -137,7 +130,6 @@ let union a b = match a.s, b.s with | Empty, _ -> b | _, Empty -> a - | All, _ | _, All -> all | x, y when x == y -> a | x, y -> let x, y = if a.cardinal < b.cardinal then x, y else y, x in @@ -160,3 +152,8 @@ let union_of_array arr = let union_of_list li = li |> Array.of_list |> union_of_array let print a { s; _ } = print_node a s + +let inter_of_list li = + match li with + | elt :: li -> List.fold_left inter elt li + | [] -> invalid_arg "Succ.inter_of_list []" diff --git a/query/succ.mli b/query/succ.mli index 9ca7a34909..6795c56932 100644 --- a/query/succ.mli +++ b/query/succ.mli @@ -8,7 +8,6 @@ val to_seq : compare:('a -> 'a -> int) -> 'a t -> 'a Seq.t (** Functions to build a succ tree *) -val all : 'a t val empty : 'a t val of_array : 'a array -> 'a t @@ -21,3 +20,5 @@ val union : 'a t -> 'a t -> 'a t val union_of_list : 'a t list -> 'a t (** [union_of_list] has better performance than [List.fold_left union empty]. *) + +val inter_of_list : 'a t list -> 'a t diff --git a/review.md b/review.md index 6ad12bd22e..2b7a5fbe65 100644 --- a/review.md +++ b/review.md @@ -37,6 +37,8 @@ they are interpreted as relative to the `-o` option") - `index` supprimer les `.db` +- `succ.ml` : remove `All` + # Commentaires/Action Point/... - refactor `Query.paths_arrow` vs `index/load_doc.type_distance_paths` @@ -60,7 +62,6 @@ they are interpreted as relative to the `-o` option") -- `succ.ml` : remove `All` - `succ.ml` : soit catcher uniquement StackOverflow, soit catcher tout mais moins profondément !? Dans le jsoo sans doute. From 4ed6deeb10538814d656c8a6da46b80ee550d88b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 13 Dec 2023 11:38:27 +0100 Subject: [PATCH 175/285] catch all is at jsoo level --- jsoo/main.ml | 15 ++++++++++----- query/succ.ml | 12 +----------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/jsoo/main.ml b/jsoo/main.ml index 064981df09..52571d14ba 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -95,11 +95,7 @@ let string_of_kind = | Field _ -> kind_field | Val _ -> kind_value -let search message = - don't_wait_for - @@ - let open Fut.Syntax in - let+ db = db in +let search message db = let query = Jv.get message "data" in let query = query |> Jv.to_jstr |> Jstr.to_string in let _pretty_query, results = @@ -139,6 +135,15 @@ let search message = in () +let search message = + don't_wait_for + @@ + let open Fut.Syntax in + let+ db = db in + (* Here we catch any exception and print it. This allows us to keep running + and answer requests that do not trigger exceptions. *) + try Printexc.print (search message) db with _ -> () + let main () = let module J' = Jstr in let o = Jv.callback ~arity:1 search in diff --git a/query/succ.ml b/query/succ.ml index 987baf4296..e43bbea6d9 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -97,17 +97,7 @@ let to_seq ~compare { s; _ } = state := elt ; elt in - (* Here, as stackoverflow could be thrown. In that case, we do not want to - crash, as a more complex search will have fewer results and probably not - trigger the stackoverflow, and we want the webworker or server to be - running when such a request is inputed. - The Printexc is very important as we need to be able to tell if the - situation described above happens. - With the current algorithm, such a stackoverflow is never triggered even - on big libraries like Base, but it is not tail-rec, so a big enough search - db could trigger it. *) - let next () = try Printexc.print loop () with _ -> None in - Seq.of_dispenser next + Seq.of_dispenser loop (** Functions to build a succ tree *) From abdf7f120fbe01136600cf07f854ab2534ea9dbd Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 13 Dec 2023 11:56:53 +0100 Subject: [PATCH 176/285] suffix_trie collapse gives a tree --- db/suffix_tree.ml | 13 +++++++++++-- db/suffix_tree.mli | 7 +++++++ query/query.ml | 5 +---- query/succ.mli | 1 + review.md | 2 -- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index 610d5fb2ad..8895eb05e8 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -62,7 +62,7 @@ module Buf = struct end module Make (S : SET) = struct - (** Terminals is the temporary storage for the payload of the leafs. It is + (** Terminals is the temporary storage for the payload of the leafs. It is converted into [S.t] after the suffix tree is built. *) module Terminals = struct type t = S.elt list @@ -320,7 +320,7 @@ module Make (S : SET) = struct module Automata = struct (** Automata is the most compact version that uses arrays for branching. It - is not practical to use it for constructing a suffix tree, but it is + is not practical to use it for constructing a suffix tree, but it is better for serialiazing. *) module Uid = struct @@ -394,6 +394,14 @@ module Make (S : SET) = struct Array.fold_left collapse acc t.children let collapse t = collapse [] t.t + + let rec sets_tree ~union ~terminal ~union_of_array t = + union (terminal t.terminals) + (union_of_array + (Array.map (sets_tree ~union ~terminal ~union_of_array) t.children)) + + let sets_tree ~union ~terminal ~union_of_array t = + sets_tree ~union ~terminal ~union_of_array t.t end let export_terminals ~cache_term ts = @@ -440,6 +448,7 @@ module Make (S : SET) = struct let find = Automata.T.find let to_sets = Automata.T.collapse + let sets_tree = Automata.T.sets_tree end module With_elts = Make (Elt.Array) diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index fbf48d8279..1c071ff112 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -25,6 +25,13 @@ module Make (S : SET) : sig val export : writer -> reader val find : reader -> string -> reader option val to_sets : reader -> S.t list + + val sets_tree : + union:('a -> 'a -> 'a) + -> terminal:(S.t -> 'a) + -> union_of_array:('a array -> 'a) + -> reader + -> 'a end module With_elts : module type of Make (Elt.Array) diff --git a/query/query.ml b/query/query.ml index e576d336d2..62c1daf43d 100644 --- a/query/query.ml +++ b/query/query.ml @@ -23,10 +23,7 @@ let collapse_trie_occ ~count t = Succ.empty let collapse_trie t = - (* here we use rev_map, because the order is not important, and the list is - too long : map would stack overflow. - TODO : get a tree instead of a map. *) - t |> Tree.to_sets |> List.rev_map Succ.of_array |> Succ.union_of_list + Succ.(Tree.sets_tree ~union ~terminal:of_array ~union_of_array t) let find_types ~shards names = List.fold_left diff --git a/query/succ.mli b/query/succ.mli index 6795c56932..6ae7940f07 100644 --- a/query/succ.mli +++ b/query/succ.mli @@ -17,6 +17,7 @@ val of_array : 'a array -> 'a t val inter : 'a t -> 'a t -> 'a t val union : 'a t -> 'a t -> 'a t +val union_of_array : 'a t array -> 'a t val union_of_list : 'a t list -> 'a t (** [union_of_list] has better performance than [List.fold_left union empty]. *) diff --git a/review.md b/review.md index 2b7a5fbe65..17a5f1fc4d 100644 --- a/review.md +++ b/review.md @@ -8,8 +8,6 @@ ## With Arthur - - - pretty-query: vraiment necessaire ? - ask about `Query.paths_arrow` vs `index/load_doc.type_distance_paths` From 427bb5469725dfb324187ac63fe02270e801d189 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 13 Dec 2023 12:06:37 +0100 Subject: [PATCH 177/285] fix succ.all removal --- query/query.ml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/query/query.ml b/query/query.ml index 62c1daf43d..86e4b155e6 100644 --- a/query/query.ml +++ b/query/query.ml @@ -66,15 +66,15 @@ type t = } let search ~(shards : Db.t list) query_name query_typ = - let results_name = find_names ~shards query_name in - let results = - match query_typ with - | None -> results_name - | Some query_typ -> - let results_typ = find_types ~shards query_typ in - Succ.inter results_name results_typ - in - results + match query_name, query_typ with + | [], None -> Succ.empty + | _ :: _, None -> find_names ~shards query_name + | [], Some query_typ -> find_types ~shards query_typ + | _ :: _, Some query_typ -> + let results_name = find_names ~shards query_name in + + let results_typ = find_types ~shards query_typ in + Succ.inter results_name results_typ let match_packages ~packages { Db.Elt.pkg; _ } = match pkg with From 4392107333571e6c5285427f5404f878944b9ca9 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 13 Dec 2023 12:20:12 +0100 Subject: [PATCH 178/285] tree leafs for types --- query/query.ml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/query/query.ml b/query/query.ml index 86e4b155e6..5482931613 100644 --- a/query/query.ml +++ b/query/query.ml @@ -17,10 +17,8 @@ let collapse_occ ~count occs = occs Succ.empty let collapse_trie_occ ~count t = - t |> Tree_occ.to_sets - |> List.fold_left - (fun succ occ -> Succ.union succ (collapse_occ ~count occ)) - Succ.empty + Succ.( + Tree_occ.sets_tree ~union ~terminal:(collapse_occ ~count) ~union_of_array t) let collapse_trie t = Succ.(Tree.sets_tree ~union ~terminal:of_array ~union_of_array t) From 863e517737965e60f1853610d2914c627fbc47b3 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 13 Dec 2023 14:57:51 +0100 Subject: [PATCH 179/285] parser/lexer are documented --- query/lexer.mll | 3 +++ query/parser.mly | 5 +++++ review.md | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/query/lexer.mll b/query/lexer.mll index b75f0b619e..8e6db8f24f 100644 --- a/query/lexer.mll +++ b/query/lexer.mll @@ -1,9 +1,12 @@ +(* This is the lexer for the [parser.mly]. *) + { open Parser } rule token = parse | ' ' { token lexbuf } +(* "-" is treated as "->" because we assume it is an incomplete "->" *) | "-" | "->" { ARROW } | "(" { PARENS_OPEN } | ")" { PARENS_CLOSE } diff --git a/query/parser.mly b/query/parser.mly index dbc0ba38c7..493f103db9 100644 --- a/query/parser.mly +++ b/query/parser.mly @@ -1,3 +1,8 @@ +(* This parser parses types as inputed by the user in a query. + It is made in weird way because it is able to correctly parse incomplete + types. It has conflicts because of this, which are impossible to resolve + without losing functionnality. *) + %{ open Query_ast %} diff --git a/review.md b/review.md index 17a5f1fc4d..a3434df4d1 100644 --- a/review.md +++ b/review.md @@ -37,6 +37,8 @@ they are interpreted as relative to the `-o` option") - `succ.ml` : remove `All` +- Documenter parser/lexer de query. + # Commentaires/Action Point/... - refactor `Query.paths_arrow` vs `index/load_doc.type_distance_paths` @@ -50,7 +52,6 @@ they are interpreted as relative to the `-o` option") - la limitation sur le packages de query n'est plus vraiment fonctionelle -- Documenter parser/lexer de query. - `Index.Load_doc.with_tokenizer`: think of which character form a word From 4777e8c60eb5fb8d770b5145826d3a79e2678ba1 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 13 Dec 2023 15:00:33 +0100 Subject: [PATCH 180/285] update review.md --- review.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/review.md b/review.md index a3434df4d1..16a7caaa89 100644 --- a/review.md +++ b/review.md @@ -37,6 +37,10 @@ they are interpreted as relative to the `-o` option") - `succ.ml` : remove `All` +- `succ.ml` : soit catcher uniquement StackOverflow, soit catcher tout mais moins profondément !? Dans le jsoo sans doute. + +- `Succ.All` is used in `query.ml` + - Documenter parser/lexer de query. # Commentaires/Action Point/... @@ -62,9 +66,6 @@ they are interpreted as relative to the `-o` option") -- `succ.ml` : soit catcher uniquement StackOverflow, soit catcher tout mais moins profondément !? Dans le jsoo sans doute. - -- `Succ.All` is used in `query.ml` # Explications commentée From 094ac1d2546220fb9aa26038d68ca4b03581f78b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 13 Dec 2023 17:33:20 +0100 Subject: [PATCH 181/285] wip refactoring of type paths --- db/db.ml | 3 +- db/db.mli | 1 + db/typepath.ml | 185 +++++++++++++++++++++++++++++++++++++++++ db/types.ml | 23 ----- db/typexpr.ml | 0 index/load_doc.ml | 136 +++++------------------------- query/parser.mly | 4 +- query/query.ml | 2 +- query/query_ast.ml | 83 ------------------ query/query_parser.ml | 9 +- review.md | 1 - test/cram/base.t/run.t | 30 +++---- 12 files changed, 232 insertions(+), 245 deletions(-) create mode 100644 db/typepath.ml create mode 100644 db/typexpr.ml delete mode 100644 query/query_ast.ml diff --git a/db/db.ml b/db/db.ml index accd939c65..a9cdea0a64 100644 --- a/db/db.ml +++ b/db/db.ml @@ -3,6 +3,7 @@ module Types = Types module Suffix_tree = Suffix_tree module Occ = Occ module Storage = Storage +module Typepath = Typepath include Types type writer = @@ -31,7 +32,7 @@ let store_type_paths db elt paths = (fun (path, count) -> let word = String.concat "" path in store db ~count word elt) - (regroup paths) + (Typepath.regroup paths) let store_word db word elt = Suffix_tree.With_elts.add_suffixes db.writer_names word elt diff --git a/db/db.mli b/db/db.mli index 837c8a0a17..b22fc8f1d0 100644 --- a/db/db.mli +++ b/db/db.mli @@ -3,6 +3,7 @@ module Types = Types module Storage = Storage module Suffix_tree = Suffix_tree module Occ = Occ +module Typepath = Typepath type t = Types.t = { db_names : Suffix_tree.With_elts.reader diff --git a/db/typepath.ml b/db/typepath.ml new file mode 100644 index 0000000000..36320fd374 --- /dev/null +++ b/db/typepath.ml @@ -0,0 +1,185 @@ +open Types + +type typ = + | Arrow of typ * typ + | Constr of string * typ list + | Tuple of typ list + | Poly of string + | Any + | Unhandled +[@@deriving show] + +let rec show = function + | Arrow (a, b) -> show_parens a ^ " -> " ^ show b + | Constr (t, []) -> t + | Constr (t, [ x ]) -> show_parens x ^ " " ^ t + | Constr (t, xs) -> "(" ^ show_list xs ^ ") " ^ t + | Tuple xs -> show_tuple xs + | Poly "" -> "'_" + | Poly name -> "'" ^ name + | Any -> "_" + | Unhandled -> "???" + +and show_parens t = + match t with + | Arrow _ | Tuple _ -> "(" ^ show t ^ ")" + | _ -> show t + +and show_list = function + | [] -> failwith "show_list: empty" + | [ x ] -> show x + | x :: xs -> show x ^ ", " ^ show_list xs + +and show_tuple = function + | [] -> failwith "show_tuple: empty" + | [ x ] -> show x + | x :: xs -> show_parens x ^ " * " ^ show_tuple xs + +let regroup lst = + Types.String_list_map.bindings + @@ List.fold_left + (fun acc s -> + let count = try String_list_map.find s acc with Not_found -> 0 in + String_list_map.add s (count + 1) acc) + String_list_map.empty lst + +type sgn = + | Pos + | Neg + | Unknown + +let string_of_sgn = function + | Pos -> "+" + | Neg -> "-" + | Unknown -> "+" + +let sgn_not = function + | Pos -> Neg + | Neg -> Pos + | Unknown -> Unknown + +type for_suffix_tree = string list list +type for_distance = string list list + +let rev_concat lst = + List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst + +let rec tails = function + | [] -> [] + | _ :: xs as lst -> lst :: tails xs + +module For_suffix_tree = struct + type t = string list list + + let all_type_names name = tails (String.split_on_char '.' name) + + let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function + | Poly _ -> [ "POLY" :: string_of_sgn sgn :: prefix ] + | Any -> + if ignore_any + then [ prefix ] + else [ "POLY" :: string_of_sgn sgn :: prefix ] + | Arrow (a, b) -> + List.rev_append + (of_typ ~ignore_any ~all_names ~prefix ~sgn:(sgn_not sgn) a) + (of_typ ~ignore_any ~all_names ~prefix ~sgn b) + | Constr (name, args) -> + name + |> (if all_names then all_type_names else fun name -> [ [ name ] ]) + |> List.map (fun name -> + let name = String.concat "." name in + let prefix = name :: string_of_sgn sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + of_typ ~ignore_any ~all_names ~prefix ~sgn arg) + args + end) + |> rev_concat + | Tuple args -> + rev_concat + @@ List.map (of_typ ~ignore_any ~all_names ~prefix ~sgn) + @@ args + | Unhandled -> [] + + (** [of_typ ~ignore_any ~prefix ~sgn t] is a representation of [t] that + encodes the polarity of the elements of the type : in [string -> int] [int] + is positive and [string] negative. + It is registered in the database and search-base type uses this to obtain + results that fit the type asked for by the user. *) + let of_typ ~ignore_any ~all_names t = + of_typ ~ignore_any ~all_names ~prefix:[] ~sgn:Pos t +end + +module For_distance = struct + type t = string list list + + let rec of_typ ~ignore_any ~prefix ~sgn t = + match t with + | Poly _ -> + let poly = "POLY" in + [ poly :: string_of_sgn sgn :: prefix ] + | Any -> + if ignore_any + then [ prefix ] + else + let poly = "POLY" in + [ poly :: string_of_sgn sgn :: prefix ] + | Arrow (a, b) -> + let prefix_left = "->0" :: prefix in + let prefix_right = "->1" :: prefix in + List.rev_append + (of_typ ~ignore_any ~prefix:prefix_left ~sgn:(sgn_not sgn) a) + (of_typ ~ignore_any ~prefix:prefix_right ~sgn b) + | Constr (name, args) -> + let prefix = name :: string_of_sgn sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + of_typ ~ignore_any ~prefix ~sgn arg) + args + end + | Tuple args -> + rev_concat + @@ List.mapi (fun i arg -> + let prefix = (string_of_int i ^ "*") :: prefix in + of_typ ~ignore_any ~prefix ~sgn arg) + @@ args + | Unhandled -> [] + + let hcons_tbl = Hashtbl.create 16 + let uid_generator = ref 0 + + let rec hcons = function + | [] -> -1, [] + | x :: xs -> ( + let uid_xs, xs = hcons xs in + match Hashtbl.find hcons_tbl (uid_xs, x) with + | xxs -> xxs + | exception Not_found -> + let uid = !uid_generator in + uid_generator := uid + 1 ; + let result = uid, x :: xs in + Hashtbl.add hcons_tbl (uid_xs, x) result ; + result) + + (** [of_typ t] is a [string list list] representing + the type [t]. It allows to compute the distance between two types. It is + stored in the database to sort results once they are obtained. *) + let of_typ ~ignore_any typ = + List.map + (fun xs -> + let _, xs = hcons xs in + xs) + (of_typ ~ignore_any ~prefix:[] ~sgn:Pos typ) +end diff --git a/db/types.ml b/db/types.ml index 5b6730b95a..6077b60ed0 100644 --- a/db/types.ml +++ b/db/types.ml @@ -4,29 +4,6 @@ module String_list_map = Map.Make (struct let compare = List.compare String.compare end) -let regroup lst = - String_list_map.bindings - @@ List.fold_left - (fun acc s -> - let count = try String_list_map.find s acc with Not_found -> 0 in - String_list_map.add s (count + 1) acc) - String_list_map.empty lst - -type sgn = - | Pos - | Neg - | Unknown - -let string_of_sgn = function - | Pos -> "+" - | Neg -> "-" - | Unknown -> "+" - -let sgn_not = function - | Pos -> Neg - | Neg -> Pos - | Unknown -> Unknown - type t = { db_names : Suffix_tree.With_elts.reader ; db_types : Suffix_tree.With_occ.reader diff --git a/db/typexpr.ml b/db/typexpr.ml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/index/load_doc.ml b/index/load_doc.ml index 2cf3e501db..32a8bbdde1 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -50,117 +50,18 @@ let cost ~name ~kind ~doc_html = | _ -> 100 *) -let rev_concat lst = - List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst - -let rec tails = function - | [] -> [] - | _ :: xs as lst -> lst :: tails xs - let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) let fullname t = Format.asprintf "%a" Pretty.show_type_name_verbose t -let all_type_names t = - let fullname = fullname t in - tails (String.split_on_char '.' fullname) - -let rec type_distance_paths ~prefix ~sgn t = - match t with - | Odoc_model.Lang.TypeExpr.Var _ -> - let poly = "POLY" in - [ poly :: Types.string_of_sgn sgn :: prefix ] - | Any -> - let poly = "POLY" in - [ poly :: Types.string_of_sgn sgn :: prefix ] - | Arrow (_, a, b) -> - let prefix_left = "->0" :: prefix in - let prefix_right = "->1" :: prefix in - List.rev_append - (type_distance_paths ~prefix:prefix_left ~sgn:(Types.sgn_not sgn) a) - (type_distance_paths ~prefix:prefix_right ~sgn b) +let rec typ_of_odoc_typ otyp = + match otyp with + | Odoc_model.Lang.TypeExpr.Var str -> Db.Typepath.Poly str + | Any -> Db.Typepath.Any + | Arrow (_lbl, left, right) -> + Db.Typepath.Arrow (typ_of_odoc_typ left, typ_of_odoc_typ right) | Constr (name, args) -> - let name = fullname name in - let prefix = name :: Types.string_of_sgn sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - type_distance_paths ~prefix ~sgn arg) - args - end - | Tuple args -> - rev_concat - @@ List.mapi (fun i arg -> - let prefix = (string_of_int i ^ "*") :: prefix in - type_distance_paths ~prefix ~sgn arg) - @@ args - | _ -> [] - -let hcons_tbl = Hashtbl.create 16 -let uid_generator = ref 0 - -let rec hcons = function - | [] -> -1, [] - | x :: xs -> ( - let uid_xs, xs = hcons xs in - match Hashtbl.find hcons_tbl (uid_xs, x) with - | xxs -> xxs - | exception Not_found -> - let uid = !uid_generator in - uid_generator := uid + 1 ; - let result = uid, x :: xs in - Hashtbl.add hcons_tbl (uid_xs, x) result ; - result) - -(** [type_distance_paths ~prefix ~sgn t] is a [string list list] representing - the type [t]. It allows to compute the distance between two types. It is - stored in the database to sort results once they are obtained. *) -let type_distance_paths typ = - List.map - (fun xs -> - let _, xs = hcons xs in - xs) - (type_distance_paths ~prefix:[] ~sgn:Pos typ) - -let rec suffix_tree_type_paths ~prefix ~sgn = function - | Odoc_model.Lang.TypeExpr.Var _ -> - [ "POLY" :: Types.string_of_sgn sgn :: prefix ] - | Any -> [ "POLY" :: Types.string_of_sgn sgn :: prefix ] - | Arrow (_lbl, a, b) -> - List.rev_append - (suffix_tree_type_paths ~prefix ~sgn:(Types.sgn_not sgn) a) - (suffix_tree_type_paths ~prefix ~sgn b) - | Constr (name, args) -> - name |> all_type_names - |> List.map (fun name -> - let name = String.concat "." name in - let prefix = name :: Types.string_of_sgn sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - suffix_tree_type_paths ~prefix ~sgn arg) - args - end) - |> rev_concat - | Tuple args -> - rev_concat @@ List.map (suffix_tree_type_paths ~prefix ~sgn) @@ args - | _ -> [] - -(** [suffix_tree_type_paths ~prefix ~sgn t] is a representation of [t] that - encodes the polarity of the elements of the type : in [string -> int] [int] - is positive and [string] negative. - It is registered in the database and search-base type uses this to obtain - results that fit the type asked for by the user. *) -let suffix_tree_type_paths t = suffix_tree_type_paths ~prefix:[] ~sgn:Pos t + Db.Typepath.Constr (fullname name, List.map typ_of_odoc_typ args) + | _ -> Db.Typepath.Unhandled let with_tokenizer str fn = let str = String.lowercase_ascii str in @@ -213,26 +114,28 @@ let searchable_type_of_record parent_type type_ = let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = let open Odoc_search.Entry in + let type_path type_ = + type_ |> typ_of_odoc_typ + |> Db.Typepath.For_distance.of_typ ~ignore_any:false + in match kind with | TypeDecl _ -> Elt.Kind.TypeDecl (Odoc_search.Html.typedecl_params_of_entry entry) | Module -> Elt.Kind.Module | Value { value = _; type_ } -> - let paths = type_distance_paths type_ in + let paths = type_path type_ in Elt.Kind.val_ paths | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = type_distance_paths searchable_type in + let paths = type_path searchable_type in Elt.Kind.constructor paths | Field { mutable_ = _; parent_type; type_ } -> - let paths = - type_ |> searchable_type_of_record parent_type |> type_distance_paths - in + let paths = type_ |> searchable_type_of_record parent_type |> type_path in Elt.Kind.field paths | Doc _ -> Doc | Exception { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = type_distance_paths searchable_type in + let paths = type_path searchable_type in Elt.Kind.exception_ paths | Class_type _ -> Class_type | Method _ -> Method @@ -240,12 +143,15 @@ let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = | TypeExtension _ -> TypeExtension | ExtensionConstructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = type_distance_paths searchable_type in + let paths = type_path searchable_type in Elt.Kind.extension_constructor paths | ModuleType -> ModuleType let register_type_expr ~db elt type_ = - let type_paths = suffix_tree_type_paths type_ in + let type_paths = + type_ |> typ_of_odoc_typ + |> Db.Typepath.For_suffix_tree.of_typ ~ignore_any:false ~all_names:true + in Db.store_type_paths db elt type_paths let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.kind) = diff --git a/query/parser.mly b/query/parser.mly index 493f103db9..f72b434992 100644 --- a/query/parser.mly +++ b/query/parser.mly @@ -4,7 +4,7 @@ without losing functionnality. *) %{ - open Query_ast + open Db.Typepath %} %token EOF @@ -14,7 +14,7 @@ %token POLY %start main -%type main +%type< Db.Typepath.typ> main %left EOF %% diff --git a/query/query.ml b/query/query.ml index 5482931613..2d4d8f38e5 100644 --- a/query/query.ml +++ b/query/query.ml @@ -35,7 +35,7 @@ let find_types ~shards names = match Tree_occ.find db name' with | Some trie -> collapse_trie_occ ~count trie | None -> Succ.empty) - (regroup names) + (Db.Typepath.regroup names) in Succ.union acc r) Succ.empty shards diff --git a/query/query_ast.ml b/query/query_ast.ml deleted file mode 100644 index a53ca4deb0..0000000000 --- a/query/query_ast.ml +++ /dev/null @@ -1,83 +0,0 @@ -type t = - | Arrow of t * t - | Constr of string * t list - | Tuple of t list - | Poly of string - | Any -[@@deriving show] - -let rec paths_arrow ~prefix ~sgn = function - | Poly _ -> [ "POLY" :: Db.Types.string_of_sgn sgn :: prefix ] - | Any -> [ prefix ] - | Arrow (a, b) -> - let prefix_left = "->0" :: prefix in - let prefix_right = "->1" :: prefix in - List.rev_append - (paths_arrow ~prefix:prefix_left ~sgn:(Db.Types.sgn_not sgn) a) - (paths_arrow ~prefix:prefix_right ~sgn b) - | Constr (name, args) -> - let prefix = name :: Db.Types.string_of_sgn sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - List.concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - paths_arrow ~prefix ~sgn arg) - args - end - | Tuple args -> - List.concat - @@ List.mapi - (fun i arg -> - let prefix = (string_of_int i ^ "*") :: prefix in - paths_arrow ~prefix ~sgn arg) - args - -let rec paths ~prefix ~sgn = function - | Poly _ -> [ "POLY" :: Db.Types.string_of_sgn sgn :: prefix ] - | Any -> [ prefix ] - | Arrow (a, b) -> - paths ~prefix ~sgn:(Db.Types.sgn_not sgn) a @ paths ~prefix ~sgn b - | Constr (name, args) -> - let prefix = name :: Db.Types.string_of_sgn sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - List.concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - paths ~prefix ~sgn arg) - args - end - | Tuple args -> - List.concat @@ List.map (fun arg -> paths ~prefix ~sgn arg) args - -let rec show = function - | Arrow (a, b) -> show_parens a ^ " -> " ^ show b - | Constr (t, []) -> t - | Constr (t, [ x ]) -> show_parens x ^ " " ^ t - | Constr (t, xs) -> "(" ^ show_list xs ^ ") " ^ t - | Tuple xs -> show_tuple xs - | Poly "" -> "'_" - | Poly name -> "'" ^ name - | Any -> "_" - -and show_parens t = - match t with - | Arrow _ | Tuple _ -> "(" ^ show t ^ ")" - | _ -> show t - -and show_list = function - | [] -> failwith "show_list: empty" - | [ x ] -> show x - | x :: xs -> show x ^ ", " ^ show_list xs - -and show_tuple = function - | [] -> failwith "show_tuple: empty" - | [ x ] -> show x - | x :: xs -> show_parens x ^ " * " ^ show_tuple xs diff --git a/query/query_parser.ml b/query/query_parser.ml index f4c4395b0f..eb867c9782 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -1,5 +1,3 @@ -open Query_ast - type t = string list let parse str = Parser.main Lexer.token (Lexing.from_string str) @@ -27,11 +25,12 @@ let of_string str = match parse str_typ with | Any -> "_", [], [] | typ -> - ( Query_ast.show typ + ( Db.Typepath.show typ , List.filter (fun s -> List.length s > 0) - (paths ~prefix:[] ~sgn:Db.Types.Pos typ) - , paths_arrow ~prefix:[] ~sgn:Db.Types.Pos typ ) + (Db.Typepath.For_suffix_tree.of_typ ~ignore_any:true + ~all_names:false typ) + , Db.Typepath.For_distance.of_typ ~ignore_any:true typ ) | exception _ -> "", [], [] in let query_name = naive_of_string str_name in diff --git a/review.md b/review.md index 16a7caaa89..f645878b85 100644 --- a/review.md +++ b/review.md @@ -56,7 +56,6 @@ they are interpreted as relative to the `-o` option") - la limitation sur le packages de query n'est plus vraiment fonctionelle - - `Index.Load_doc.with_tokenizer`: think of which character form a word - It would be cool to be able to see the string corresponding to types, and also of the intermediate string list list diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index b28390b78c..161b4ec725 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,11 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.246s - user 0m1.175s - sys 0m0.060s + real 0m1.292s + user 0m1.218s + sys 0m0.033s + + @@ -40,8 +42,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2736 db.js - 2064 db.js.gz + 2696 db.js + 2036 db.js.gz 1544 megaodocl.gz @@ -77,10 +79,13 @@ $ firefox /tmp/html/base/index.html 627 val Base.Hashtbl.S_poly.add 628 val Base.Hashtbl.S_poly.data 628 val Base.Hashtbl.S_poly.keys + 630 val Base.Hashtbl.S_poly.choose + 632 val Base.Hashtbl.S_poly.to_alist 721 type ('a, 'b) Base.Map.S_poly.t 721 type 'elt Base.Set.S_poly.t 723 val Base.Map.S_poly.add 723 val Base.Map.S_poly.mem + 723 val Base.Map.S_poly.nth 723 val Base.Set.S_poly.add 723 val Base.Set.S_poly.nth 723 type ('a, 'cmp) Base.Set.S_poly.set @@ -92,15 +97,17 @@ $ firefox /tmp/html/base/index.html 724 type 'elt Base.Set.S_poly.tree 725 type ('a, 'b) Base.Hashtbl.S_poly.t 725 val Base.Map.S_poly.empty + 725 val Base.Map.S_poly.split 725 val Base.Set.S_poly.empty 725 val Base.Set.S_poly.equal - 725 val Base.Set.S_poly.inter - 725 val Base.Set.S_poly.union + 725 val Base.Set.S_poly.split 726 val Base.Map.S_poly.length 726 val Base.Set.S_poly.choose 726 val Base.Set.S_poly.length 726 val Base.Set.S_poly.remove 727 type 'a Base.Hashtbl.S_poly.key + 727 val Base.Map.S_poly.max_elt + 727 val Base.Map.S_poly.min_elt 727 val Base.Set.S_poly.max_elt 727 val Base.Set.S_poly.min_elt 727 val Base.Set.S_poly.of_list @@ -110,14 +117,9 @@ $ firefox /tmp/html/base/index.html 728 val Base.Map.S_poly.of_alist 728 val Base.Set.S_poly.elements 728 val Base.Set.S_poly.is_empty - 728 val Base.Set.S_poly.of_array - 728 val Base.Set.S_poly.to_array 729 val Base.Set.S_poly.singleton 730 val Base.Set.S_poly.choose_exn - 730 val Base.Set.S_poly.invariants - 731 val Base.Set.S_poly.max_elt_exn - 731 val Base.Set.S_poly.min_elt_exn - 732 val Base.Hashtbl.S_poly.hashable + 731 val Base.Map.S_poly.of_sequence $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin "group b" 218 val Base.List.group 221 val Base.Hashtbl.group @@ -165,7 +167,6 @@ $ firefox /tmp/html/base/index.html 244 mod Base.Applicative.Make3_using_map2_local 245 sig Base.Applicative.Basic2_using_map2_local 245 sig Base.Applicative.Basic3_using_map2_local - 254 mod Base.Applicative.Make_using_map2.Applicative_infix 321 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t 322 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 323 val Base.Array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t @@ -173,6 +174,7 @@ $ firefox /tmp/html/base/index.html 340 val Base.Applicative.Make_using_map2.all : 'a X.t list -> 'a list X.t 341 type ('a, 'e) Base.Applicative.Make2_using_map2.X.t 341 type ('a, 'd, 'e) Base.Applicative.Make3_using_map2.X.t + 341 val Base.Applicative.Make_using_map2.both : 'a X.t -> 'b X.t -> ('a * 'b) X.t 342 val Base.Applicative.Make_using_map2.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] 343 val Base.Applicative.Make2_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] 343 val Base.Applicative.Make3_using_map2.X.map : [ `Define_using_map2 From fed7a85cf996694450478f058fae538d1bdf883e Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 14 Dec 2023 15:49:12 +0100 Subject: [PATCH 182/285] review discussions --- review.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/review.md b/review.md index f645878b85..3f58f5a0c9 100644 --- a/review.md +++ b/review.md @@ -3,15 +3,23 @@ # To discuss - Tester de virer la compression? + > Verifier si la double compression a de l'interet + > tester que gzip - Type extensions: we might want to search for all extensions of a given extensible type. ## With Arthur - pretty-query: vraiment necessaire ? +> Mettre a part - ask about `Query.paths_arrow` vs `index/load_doc.type_distance_paths` +- Should `_ -> int` be supported ? +> Yes, try to fix it in dynamic cost + +- Suffix_tree -> succ conversion + # done - Réfléchir à `ancient`: enlever pour de bon, rétablir le support ? From 7fc95569d4a061d14326ee5b760cf27cf4d75eb5 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 14 Dec 2023 15:54:11 +0100 Subject: [PATCH 183/285] exceptions bugfix typepath refactoring wip again --- db/db.ml | 4 +- db/db.mli | 4 +- db/db_typedef.ml | 6 ++ db/elt.ml | 21 +---- db/storage.ml | 2 +- db/string_list_map.ml | 5 ++ db/typepath.ml | 152 ++++++---------------------------- db/typepath.mli | 91 ++++++++++++++++++++ db/types.ml | 10 --- db/typexpr.ml | 36 ++++++++ index/load_doc.ml | 44 ++++------ query/dynamic_cost.ml | 141 +++++-------------------------- query/parser.mly | 4 +- query/query.ml | 5 +- query/query_parser.ml | 8 +- query/type_distance.ml | 183 +++++++++++++++++++++++++++++++++++++++++ test/cram/base.t/run.t | 71 ++++++++-------- test/cram/cli.t/run.t | 14 ++-- 18 files changed, 439 insertions(+), 362 deletions(-) create mode 100644 db/db_typedef.ml create mode 100644 db/string_list_map.ml create mode 100644 db/typepath.mli delete mode 100644 db/types.ml create mode 100644 query/type_distance.ml diff --git a/db/db.ml b/db/db.ml index a9cdea0a64..366c8c64bd 100644 --- a/db/db.ml +++ b/db/db.ml @@ -1,10 +1,10 @@ module Elt = Elt -module Types = Types module Suffix_tree = Suffix_tree module Occ = Occ module Storage = Storage module Typepath = Typepath -include Types +module Typexpr = Typexpr +include Db_typedef type writer = { writer_names : Suffix_tree.With_elts.writer diff --git a/db/db.mli b/db/db.mli index b22fc8f1d0..6ab7a600f2 100644 --- a/db/db.mli +++ b/db/db.mli @@ -1,11 +1,11 @@ module Elt = Elt -module Types = Types module Storage = Storage module Suffix_tree = Suffix_tree module Occ = Occ module Typepath = Typepath +module Typexpr = Typexpr -type t = Types.t = +type t = Db_typedef.t = { db_names : Suffix_tree.With_elts.reader ; db_types : Suffix_tree.With_occ.reader } diff --git a/db/db_typedef.ml b/db/db_typedef.ml new file mode 100644 index 0000000000..58617e2778 --- /dev/null +++ b/db/db_typedef.ml @@ -0,0 +1,6 @@ +(* This is defined in a standalone file to avoid dependency cycles*) + +type t = + { db_names : Suffix_tree.With_elts.reader + ; db_types : Suffix_tree.With_occ.reader + } diff --git a/db/elt.ml b/db/elt.ml index 29a67f465d..93d5b1431e 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -1,22 +1,3 @@ -type type_path = string list list - -(** A type can viewed as a tree. - [a -> b -> c * d] is the following tree : - {[ -> - |- a - |- -> - |- b - |- * - |- c - |- d - ]} - {!type_paths} is the list of paths from root to leaf in the tree of - the type. There is an annotation to indicate the child's position. - Here it would be : - [ [["->";"0"; "a"];["->"; "1"; "->"; "0"; "b"]; ...] ] - - It is used to sort results. *) - module Kind = struct type 'a abstract = | Doc @@ -33,7 +14,7 @@ module Kind = struct | Field of 'a | Val of 'a - type t = type_path abstract + type t = Typexpr.t abstract let equal = ( = ) let doc = Doc diff --git a/db/storage.ml b/db/storage.ml index 6c458cdf27..0cde8d2c2c 100644 --- a/db/storage.ml +++ b/db/storage.ml @@ -1,4 +1,4 @@ -type db = Types.t +type db = Db_typedef.t module type S = sig type writer diff --git a/db/string_list_map.ml b/db/string_list_map.ml new file mode 100644 index 0000000000..3899926707 --- /dev/null +++ b/db/string_list_map.ml @@ -0,0 +1,5 @@ +include Map.Make (struct + type t = string list + + let compare = List.compare String.compare +end) diff --git a/db/typepath.ml b/db/typepath.ml index 36320fd374..fbee9d605c 100644 --- a/db/typepath.ml +++ b/db/typepath.ml @@ -1,65 +1,29 @@ -open Types - -type typ = - | Arrow of typ * typ - | Constr of string * typ list - | Tuple of typ list - | Poly of string - | Any - | Unhandled -[@@deriving show] - -let rec show = function - | Arrow (a, b) -> show_parens a ^ " -> " ^ show b - | Constr (t, []) -> t - | Constr (t, [ x ]) -> show_parens x ^ " " ^ t - | Constr (t, xs) -> "(" ^ show_list xs ^ ") " ^ t - | Tuple xs -> show_tuple xs - | Poly "" -> "'_" - | Poly name -> "'" ^ name - | Any -> "_" - | Unhandled -> "???" - -and show_parens t = - match t with - | Arrow _ | Tuple _ -> "(" ^ show t ^ ")" - | _ -> show t - -and show_list = function - | [] -> failwith "show_list: empty" - | [ x ] -> show x - | x :: xs -> show x ^ ", " ^ show_list xs - -and show_tuple = function - | [] -> failwith "show_tuple: empty" - | [ x ] -> show x - | x :: xs -> show_parens x ^ " * " ^ show_tuple xs +open Typexpr let regroup lst = - Types.String_list_map.bindings + String_list_map.bindings @@ List.fold_left (fun acc s -> let count = try String_list_map.find s acc with Not_found -> 0 in String_list_map.add s (count + 1) acc) String_list_map.empty lst -type sgn = - | Pos - | Neg - | Unknown - -let string_of_sgn = function - | Pos -> "+" - | Neg -> "-" - | Unknown -> "+" - -let sgn_not = function - | Pos -> Neg - | Neg -> Pos - | Unknown -> Unknown - -type for_suffix_tree = string list list -type for_distance = string list list +module Sign = struct + type t = + | Pos + | Neg + | Unknown + + let to_string = function + | Pos -> "+" + | Neg -> "-" + | Unknown -> "+" + + let not = function + | Pos -> Neg + | Neg -> Pos + | Unknown -> Unknown +end let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst @@ -71,24 +35,24 @@ let rec tails = function module For_suffix_tree = struct type t = string list list - let all_type_names name = tails (String.split_on_char '.' name) + let all_type_names name = + name |> String.split_on_char '.' |> tails |> List.map (String.concat ".") let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function - | Poly _ -> [ "POLY" :: string_of_sgn sgn :: prefix ] + | Poly _ -> [ "POLY" :: Sign.to_string sgn :: prefix ] | Any -> if ignore_any then [ prefix ] - else [ "POLY" :: string_of_sgn sgn :: prefix ] + else [ "POLY" :: Sign.to_string sgn :: prefix ] | Arrow (a, b) -> List.rev_append - (of_typ ~ignore_any ~all_names ~prefix ~sgn:(sgn_not sgn) a) + (of_typ ~ignore_any ~all_names ~prefix ~sgn:(Sign.not sgn) a) (of_typ ~ignore_any ~all_names ~prefix ~sgn b) | Constr (name, args) -> name - |> (if all_names then all_type_names else fun name -> [ [ name ] ]) + |> (if all_names then all_type_names else fun name -> [ name ]) |> List.map (fun name -> - let name = String.concat "." name in - let prefix = name :: string_of_sgn sgn :: prefix in + let prefix = name :: Sign.to_string sgn :: prefix in begin match args with | [] -> [ prefix ] @@ -116,70 +80,4 @@ module For_suffix_tree = struct of_typ ~ignore_any ~all_names ~prefix:[] ~sgn:Pos t end -module For_distance = struct - type t = string list list - - let rec of_typ ~ignore_any ~prefix ~sgn t = - match t with - | Poly _ -> - let poly = "POLY" in - [ poly :: string_of_sgn sgn :: prefix ] - | Any -> - if ignore_any - then [ prefix ] - else - let poly = "POLY" in - [ poly :: string_of_sgn sgn :: prefix ] - | Arrow (a, b) -> - let prefix_left = "->0" :: prefix in - let prefix_right = "->1" :: prefix in - List.rev_append - (of_typ ~ignore_any ~prefix:prefix_left ~sgn:(sgn_not sgn) a) - (of_typ ~ignore_any ~prefix:prefix_right ~sgn b) - | Constr (name, args) -> - let prefix = name :: string_of_sgn sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - of_typ ~ignore_any ~prefix ~sgn arg) - args - end - | Tuple args -> - rev_concat - @@ List.mapi (fun i arg -> - let prefix = (string_of_int i ^ "*") :: prefix in - of_typ ~ignore_any ~prefix ~sgn arg) - @@ args - | Unhandled -> [] - - let hcons_tbl = Hashtbl.create 16 - let uid_generator = ref 0 - - let rec hcons = function - | [] -> -1, [] - | x :: xs -> ( - let uid_xs, xs = hcons xs in - match Hashtbl.find hcons_tbl (uid_xs, x) with - | xxs -> xxs - | exception Not_found -> - let uid = !uid_generator in - uid_generator := uid + 1 ; - let result = uid, x :: xs in - Hashtbl.add hcons_tbl (uid_xs, x) result ; - result) - (** [of_typ t] is a [string list list] representing - the type [t]. It allows to compute the distance between two types. It is - stored in the database to sort results once they are obtained. *) - let of_typ ~ignore_any typ = - List.map - (fun xs -> - let _, xs = hcons xs in - xs) - (of_typ ~ignore_any ~prefix:[] ~sgn:Pos typ) -end diff --git a/db/typepath.mli b/db/typepath.mli new file mode 100644 index 0000000000..2052644ef8 --- /dev/null +++ b/db/typepath.mli @@ -0,0 +1,91 @@ +(** This module contains the transformation that make types searchable. + +A type can viewed as a tree. [a -> b -> c * d] is the following tree : +{[ -> + |- a + |- -> + |- b + |- * + |- c + |- d +]} +To make types searchable, we consider the list of paths from root to leaf in the +tree of the type. + +Here the paths would be : [ [[-> a]; [-> -> b]; [-> -> * c ]; [-> -> * d]] ] + +There are two submodules, that each encode slightly different information from +the above. *) + +val regroup : string list list -> (string list * int) list + +module Sign : sig + type t = + | Pos + | Neg + | Unknown + + val to_string : t -> string + val not : t -> t +end + +module For_suffix_tree : sig + type t = string list list + (** [For_suffix_tree.t] is a type paths that can used to be register in a + suffix tree. This means that each path represent a text based searchable + version of the type. The chosen representation here is polarity : we do + not represent the [->] or the [*] constructors, but they affect the + "polarity" of their children. + + The polarity of a of component of a type indicate if it is produced or + consumed by the type. In the type [int -> string], [int] has negative + polarity because it is being consumed, and [string] has positive polarity + because it is being produced. + + When you have [t -> u], the polarity of [t] is inversed, and the + polarity of [u] stays the same. So when you have + + If you consider [a -> b -> c * d] with the following tree : + {[ -> + |- a + |- -> + |- b + |- * + |- c + |- d + ]} + + The [For_distance.t] associated is : [ [[- a]; [-; b]; [+; c ]; [+; d]] ] + + [babar : Lib.M.t -> Lib.R.t] + + [[-; Lib.M.t]; [+;Lib.R.t]; [-;M.t]; [-;t]; [+;R.t]; [+;t]] + *) + + val of_typ : ignore_any:bool -> all_names:bool -> Typexpr.t -> t +end + +(* module For_distance : sig + type t = string list list + (** [For_distance.t] is a type paths that can used to compute the distance + between two types. It is much more precise than {!For_suffix.t}, we do not + lose any information about the type. Because of this, we represent [->] + and [*] add annotations to indicate the child's position relative to its + parent (first child or second child ?) + + If you consider [a -> b -> c * d] with the following tree : + {[ -> + |- a + |- -> + |- b + |- * + |- c + |- d + ]} + + The [For_distance.t] associated is : [ [[-> 1 a]; [-> 2 -> 1 b]; [-> 2 -> 2 + * 1 c ]; [-> 2 -> 2 * 2 d]] ] + *) + + val of_typ : ignore_any:bool -> Typexpr.t -> t +end *) diff --git a/db/types.ml b/db/types.ml deleted file mode 100644 index 6077b60ed0..0000000000 --- a/db/types.ml +++ /dev/null @@ -1,10 +0,0 @@ -module String_list_map = Map.Make (struct - type t = string list - - let compare = List.compare String.compare -end) - -type t = - { db_names : Suffix_tree.With_elts.reader - ; db_types : Suffix_tree.With_occ.reader - } diff --git a/db/typexpr.ml b/db/typexpr.ml index e69de29bb2..af9ab901d2 100644 --- a/db/typexpr.ml +++ b/db/typexpr.ml @@ -0,0 +1,36 @@ +type t = + | Arrow of t * t + | Constr of string * t list + | Tuple of t list + | Poly of string + | Any + | Unhandled +[@@deriving show] + +let rec show = function + | Arrow (a, b) -> show_parens a ^ " -> " ^ show b + | Constr (t, []) -> t + | Constr (t, [ x ]) -> show_parens x ^ " " ^ t + | Constr (t, xs) -> "(" ^ show_list xs ^ ") " ^ t + | Tuple xs -> show_tuple xs + | Poly "" -> "'_" + | Poly name -> "'" ^ name + | Any -> "_" + | Unhandled -> "???" + +and show_parens t = + match t with + | Arrow _ | Tuple _ -> "(" ^ show t ^ ")" + | _ -> show t + +and show_list = function + | [] -> failwith "show_list: empty" + | [ x ] -> show x + | x :: xs -> show x ^ ", " ^ show_list xs + +and show_tuple = function + | [] -> failwith "show_tuple: empty" + | [ x ] -> show x + | x :: xs -> show_parens x ^ " * " ^ show_tuple xs + + let size typ = typ |> show |> String.length \ No newline at end of file diff --git a/index/load_doc.ml b/index/load_doc.ml index 32a8bbdde1..f2ae4330f5 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -1,6 +1,5 @@ module Elt = Db.Elt module Db_common = Db -module Types = Db.Types module ModuleName = Odoc_model.Names.ModuleName let generic_cost ~ignore_no_doc name has_doc = @@ -12,13 +11,10 @@ let generic_cost ~ignore_no_doc name has_doc = + (if ignore_no_doc || has_doc then 0 else 30) + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 -let type_cost paths = - paths |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 - let kind_cost (kind : Elt.Kind.t) = match kind with - | Constructor type_path | Field type_path | Val type_path -> - type_cost type_path + | Constructor typ | Field typ | Val typ -> + Db.Typexpr.size typ | Doc -> 400 | TypeDecl _ | Module -> 0 | Exception _ | Class_type | Method | Class -> 10 @@ -54,14 +50,14 @@ let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) let fullname t = Format.asprintf "%a" Pretty.show_type_name_verbose t let rec typ_of_odoc_typ otyp = + let open Db.Typexpr in match otyp with - | Odoc_model.Lang.TypeExpr.Var str -> Db.Typepath.Poly str - | Any -> Db.Typepath.Any + | Odoc_model.Lang.TypeExpr.Var str -> Poly str + | Any -> Any | Arrow (_lbl, left, right) -> - Db.Typepath.Arrow (typ_of_odoc_typ left, typ_of_odoc_typ right) - | Constr (name, args) -> - Db.Typepath.Constr (fullname name, List.map typ_of_odoc_typ args) - | _ -> Db.Typepath.Unhandled + Arrow (typ_of_odoc_typ left, typ_of_odoc_typ right) + | Constr (name, args) -> Constr (fullname name, List.map typ_of_odoc_typ args) + | _ -> Unhandled let with_tokenizer str fn = let str = String.lowercase_ascii str in @@ -114,37 +110,33 @@ let searchable_type_of_record parent_type type_ = let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = let open Odoc_search.Entry in - let type_path type_ = - type_ |> typ_of_odoc_typ - |> Db.Typepath.For_distance.of_typ ~ignore_any:false - in match kind with | TypeDecl _ -> Elt.Kind.TypeDecl (Odoc_search.Html.typedecl_params_of_entry entry) | Module -> Elt.Kind.Module | Value { value = _; type_ } -> - let paths = type_path type_ in - Elt.Kind.val_ paths + let typ = typ_of_odoc_typ type_ in + Elt.Kind.val_ typ | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = type_path searchable_type in - Elt.Kind.constructor paths + let typ = typ_of_odoc_typ searchable_type in + Elt.Kind.constructor typ | Field { mutable_ = _; parent_type; type_ } -> - let paths = type_ |> searchable_type_of_record parent_type |> type_path in - Elt.Kind.field paths + let typ = type_ |> searchable_type_of_record parent_type |> typ_of_odoc_typ in + Elt.Kind.field typ | Doc _ -> Doc | Exception { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = type_path searchable_type in - Elt.Kind.exception_ paths + let typ = typ_of_odoc_typ searchable_type in + Elt.Kind.exception_ typ | Class_type _ -> Class_type | Method _ -> Method | Class _ -> Class | TypeExtension _ -> TypeExtension | ExtensionConstructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in - let paths = type_path searchable_type in - Elt.Kind.extension_constructor paths + let typ = typ_of_odoc_typ searchable_type in + Elt.Kind.extension_constructor typ | ModuleType -> ModuleType let register_type_expr ~db elt type_ = diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index bae56a894e..57e47eb61b 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -1,113 +1,5 @@ module Elt = Db.Elt -module Type_distance = struct - let distance xs ys = - let len_xs = List.length xs in - let len_ys = List.length ys in - let cache = Array.make_matrix (1 + len_xs) (1 + len_ys) (-1) in - let rec memo i j xs ys = - let r = cache.(i).(j) in - if r >= 0 - then r - else begin - let r = go i j xs ys in - cache.(i).(j) <- r ; - r - end - and go i j xs ys = - match xs, ys with - | [], _ -> 0 - | [ "_" ], _ -> 0 - | _, [] -> List.length xs - | x :: xs, y :: ys when String.ends_with ~suffix:x y -> - memo (i + 1) (j + 1) xs ys - | _, "->1" :: ys -> memo i (j + 1) xs ys - | "->1" :: xs, _ -> 1 + memo (i + 1) j xs ys - | _ :: xs', _ :: ys' -> - 7 - + min - (memo (i + 1) (j + 1) xs' ys') - (min (memo (i + 1) j xs' ys) (memo i (j + 1) xs ys')) - in - go 0 0 xs ys - - let minimize = function - | [] -> 0 - | arr -> - let used = Array.make (List.length (List.hd arr)) false in - let arr = - Array.map (fun lst -> - let lst = (1, None) :: List.mapi (fun i x -> x, Some i) lst in - List.sort Stdlib.compare lst) - @@ Array.of_list arr - in - Array.sort (fun xs ys -> Stdlib.compare xs ys) arr ; - let heuristics = Array.make (Array.length arr + 1) 0 in - for i = Array.length heuristics - 2 downto 0 do - let best = fst (List.hd arr.(i)) in - heuristics.(i) <- heuristics.(i + 1) + best - done ; - let best = ref 1000 in - let limit = ref 0 in - let rec go rem acc i = - incr limit ; - if !limit > 10_000 - then false - else if rem <= 0 - then begin - let score = acc + (1 * (Array.length arr - i)) in - best := min score !best ; - true - end - else if i >= Array.length arr - then begin - best := min !best (acc + (100 * rem)) ; - true - end - else if acc + heuristics.(i) >= !best - then true - else - let rec find = function - | [] -> true - | (cost, j) :: rest -> - let ok = - match j with - | None -> - go rem - (acc + cost - + if rem > Array.length arr - i then 100 else 0) - (i + 1) - | Some j -> - if used.(j) - then true - else begin - used.(j) <- true ; - let ok = go (rem - 1) (acc + cost) (i + 1) in - used.(j) <- false ; - ok - end - in - if ok then find rest else false - in - find arr.(i) - in - let _ = go (Array.length used) 0 0 in - !best - - let v query_type paths = - match paths, query_type with - | _, [] | [], _ -> 0 - | _ -> - let arr = - List.map - (fun p -> - let p = List.rev p in - List.map (fun q -> distance (List.rev q) p) query_type) - paths - in - minimize arr -end - module Reasoning = struct module Name_match = struct type t = @@ -198,24 +90,30 @@ module Reasoning = struct let type_distance query_type elt = let open Elt in match query_type, elt.kind with - | [], _ -> None - | ( _ + | None, _ -> None + | ( Some query_type , Elt.Kind.( - ( ExtensionConstructor paths - | Constructor paths - | Field paths - | Val paths )) ) -> - Some (Type_distance.v query_type paths) - | _ -> None + ( ExtensionConstructor eltype + | Constructor eltype + | Field eltype + | Val eltype + | Exception eltype )) ) -> + Some (Type_distance.v ~query:query_type ~element:eltype) + | ( _ + , ( Doc | TypeDecl _ | Module | Class_type | Method | Class + | TypeExtension | ModuleType ) ) -> + None - let type_in_query query_type = - query_type <> [] && List.exists (( <> ) []) query_type + let type_in_query query_type = Option.is_some query_type let type_in_elt elt = let open Elt in match elt.kind with - | ExtensionConstructor _ | Constructor _ | Field _ | Val _ -> true - | _ -> false + | ExtensionConstructor _ | Constructor _ | Field _ | Val _ | Exception _ -> + true + | Doc | TypeDecl _ | Module | Class_type | Method | Class | TypeExtension + | ModuleType -> + false let is_stdlib elt = let open Elt in @@ -325,7 +223,8 @@ module Reasoning = struct then (* If query request a type, elements which do not have one should never appear. *) - assert false + (* assert false *) + 0 else 0 in let is_from_module_type_cost = if is_from_module_type then 400 else 0 in diff --git a/query/parser.mly b/query/parser.mly index f72b434992..15dbc62908 100644 --- a/query/parser.mly +++ b/query/parser.mly @@ -4,7 +4,7 @@ without losing functionnality. *) %{ - open Db.Typepath + open Db.Typexpr %} %token EOF @@ -14,7 +14,7 @@ %token POLY %start main -%type< Db.Typepath.typ> main +%type< Db.Typexpr.t> main %left EOF %% diff --git a/query/query.ml b/query/query.ml index 2d4d8f38e5..218b71516c 100644 --- a/query/query.ml +++ b/query/query.ml @@ -3,7 +3,6 @@ module Dynamic_cost = Dynamic_cost module Storage = Db.Storage module Tree = Db.Suffix_tree.With_elts module Tree_occ = Db.Suffix_tree.With_occ -open Db.Types module Occ = Db.Occ module Private = struct @@ -26,7 +25,7 @@ let collapse_trie t = let find_types ~shards names = List.fold_left (fun acc shard -> - let db = shard.db_types in + let db = Db.(shard.db_types) in let r = Succ.inter_of_list @@ List.map @@ -44,7 +43,7 @@ let find_names ~(shards : Db.t list) names = let names = List.map String.lowercase_ascii names in List.fold_left (fun acc shard -> - let db_names = shard.db_names in + let db_names = Db.(shard.db_names) in let candidates = List.map (fun name -> diff --git a/query/query_parser.ml b/query/query_parser.ml index eb867c9782..93983a346f 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -23,15 +23,15 @@ let of_string str = in let pretty_typ, query_typ, paths_typ = match parse str_typ with - | Any -> "_", [], [] + | Any -> "_", [], None | typ -> - ( Db.Typepath.show typ + ( Db.Typexpr.show typ , List.filter (fun s -> List.length s > 0) (Db.Typepath.For_suffix_tree.of_typ ~ignore_any:true ~all_names:false typ) - , Db.Typepath.For_distance.of_typ ~ignore_any:true typ ) - | exception _ -> "", [], [] + , Some typ ) + | exception _ -> "", [], None in let query_name = naive_of_string str_name in let query_typ = if has_typ then Some query_typ else None in diff --git a/query/type_distance.ml b/query/type_distance.ml new file mode 100644 index 0000000000..89f88a6c0f --- /dev/null +++ b/query/type_distance.ml @@ -0,0 +1,183 @@ +module Type_path = struct + module Sign = Db.Typepath.Sign + + type t = string list list + + let rev_concat lst = + List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst + + let rec of_typ ~ignore_any ~prefix ~sgn t = + match t with + | Db.Typexpr.Poly _ -> + let poly = "POLY" in + [ poly :: Sign.to_string sgn :: prefix ] + | Any -> + if ignore_any + then [ prefix ] + else + let poly = "POLY" in + [ poly :: Sign.to_string sgn :: prefix ] + | Arrow (a, b) -> + let prefix_left = "->0" :: prefix in + let prefix_right = "->1" :: prefix in + List.rev_append + (of_typ ~ignore_any ~prefix:prefix_left ~sgn:(Sign.not sgn) a) + (of_typ ~ignore_any ~prefix:prefix_right ~sgn b) + | Constr (name, args) -> + let prefix = name :: Sign.to_string sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + of_typ ~ignore_any ~prefix ~sgn arg) + args + end + | Tuple args -> + rev_concat + @@ List.mapi (fun i arg -> + let prefix = (string_of_int i ^ "*") :: prefix in + of_typ ~ignore_any ~prefix ~sgn arg) + @@ args + | Unhandled -> [] + + let hcons_tbl = Hashtbl.create 16 + let uid_generator = ref 0 + + let rec hcons = function + | [] -> -1, [] + | x :: xs -> ( + let uid_xs, xs = hcons xs in + match Hashtbl.find hcons_tbl (uid_xs, x) with + | xxs -> xxs + | exception Not_found -> + let uid = !uid_generator in + uid_generator := uid + 1 ; + let result = uid, x :: xs in + Hashtbl.add hcons_tbl (uid_xs, x) result ; + result) + + (** [of_typ t] is a [string list list] representing + the type [t]. It allows to compute the distance between two types. It is + stored in the database to sort results once they are obtained. *) + let of_typ ~ignore_any typ = + List.map + (fun xs -> + let _, xs = hcons xs in + xs) + (of_typ ~ignore_any ~prefix:[] ~sgn:Pos typ) +end + +let distance xs ys = + let len_xs = List.length xs in + let len_ys = List.length ys in + let cache = Array.make_matrix (1 + len_xs) (1 + len_ys) (-1) in + let rec memo i j xs ys = + let r = cache.(i).(j) in + if r >= 0 + then r + else begin + let r = go i j xs ys in + cache.(i).(j) <- r ; + r + end + and go i j xs ys = + match xs, ys with + | [], _ -> 0 + | [ "_" ], _ -> 0 + | _, [] -> List.length xs + | x :: xs, y :: ys when String.ends_with ~suffix:x y -> + memo (i + 1) (j + 1) xs ys + | _, "->1" :: ys -> memo i (j + 1) xs ys + | "->1" :: xs, _ -> 1 + memo (i + 1) j xs ys + | _ :: xs', _ :: ys' -> + 7 + + min + (memo (i + 1) (j + 1) xs' ys') + (min (memo (i + 1) j xs' ys) (memo i (j + 1) xs ys')) + in + go 0 0 xs ys + +let minimize = function + | [] -> 0 + | arr -> + let used = Array.make (List.length (List.hd arr)) false in + let arr = + Array.map (fun lst -> + let lst = (1, None) :: List.mapi (fun i x -> x, Some i) lst in + List.sort Stdlib.compare lst) + @@ Array.of_list arr + in + Array.sort (fun xs ys -> Stdlib.compare xs ys) arr ; + let heuristics = Array.make (Array.length arr + 1) 0 in + for i = Array.length heuristics - 2 downto 0 do + let best = fst (List.hd arr.(i)) in + heuristics.(i) <- heuristics.(i + 1) + best + done ; + let best = ref 1000 in + let limit = ref 0 in + let rec go rem acc i = + incr limit ; + if !limit > 10_000 + then false + else if rem <= 0 + then begin + let score = acc + (1 * (Array.length arr - i)) in + best := min score !best ; + true + end + else if i >= Array.length arr + then begin + best := min !best (acc + (100 * rem)) ; + true + end + else if acc + heuristics.(i) >= !best + then true + else + let rec find = function + | [] -> true + | (cost, j) :: rest -> + let ok = + match j with + | None -> + go rem + (acc + cost + + if rem > Array.length arr - i then 100 else 0) + (i + 1) + | Some j -> + if used.(j) + then true + else begin + used.(j) <- true ; + let ok = go (rem - 1) (acc + cost) (i + 1) in + used.(j) <- false ; + ok + end + in + if ok then find rest else false + in + find arr.(i) + in + let _ = go (Array.length used) 0 0 in + !best + +let length typ = + typ |> Type_path.of_typ ~ignore_any:false |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 + +let v ~query ~element = + let query_paths = Type_path.of_typ ~ignore_any:false query in + let element_paths = Type_path.of_typ ~ignore_any:false element in + match element_paths, query_paths with + | _, [] | [], _ -> 0 + | _ -> + let arr = + List.map + (fun p -> + let p = List.rev p in + List.map (fun q -> distance (List.rev q) p) query_paths) + element_paths + in + minimize arr diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 161b4ec725..27c067ac65 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -9,10 +9,11 @@ $ du -sh megaodocl 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - - real 0m1.292s - user 0m1.218s - sys 0m0.033s + + real 0m1.157s + user 0m1.111s + sys 0m0.043s + @@ -42,8 +43,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2696 db.js - 2036 db.js.gz + 2720 db.js + 2056 db.js.gz 1544 megaodocl.gz @@ -77,49 +78,49 @@ $ firefox /tmp/html/base/index.html 623 val Base.Set.S_poly.mem 625 mod Base.Set.S_poly.Named 627 val Base.Hashtbl.S_poly.add + 627 val Base.Hashtbl.S_poly.map + 627 val Base.Hashtbl.S_poly.set 628 val Base.Hashtbl.S_poly.data + 628 val Base.Hashtbl.S_poly.find 628 val Base.Hashtbl.S_poly.keys 630 val Base.Hashtbl.S_poly.choose - 632 val Base.Hashtbl.S_poly.to_alist 721 type ('a, 'b) Base.Map.S_poly.t 721 type 'elt Base.Set.S_poly.t 723 val Base.Map.S_poly.add 723 val Base.Map.S_poly.mem 723 val Base.Map.S_poly.nth + 723 val Base.Map.S_poly.set 723 val Base.Set.S_poly.add 723 val Base.Set.S_poly.nth 723 type ('a, 'cmp) Base.Set.S_poly.set 723 val Base.Set.S_poly.sum 724 val Base.Map.S_poly.data + 724 val Base.Map.S_poly.find 724 val Base.Map.S_poly.keys 724 type ('a, 'b) Base.Map.S_poly.tree 724 val Base.Set.S_poly.diff + 724 val Base.Set.S_poly.iter 724 type 'elt Base.Set.S_poly.tree 725 type ('a, 'b) Base.Hashtbl.S_poly.t 725 val Base.Map.S_poly.empty 725 val Base.Map.S_poly.split 725 val Base.Set.S_poly.empty 725 val Base.Set.S_poly.equal + 725 val Base.Set.S_poly.inter 725 val Base.Set.S_poly.split + 725 val Base.Set.S_poly.union 726 val Base.Map.S_poly.length 726 val Base.Set.S_poly.choose 726 val Base.Set.S_poly.length 726 val Base.Set.S_poly.remove 727 type 'a Base.Hashtbl.S_poly.key - 727 val Base.Map.S_poly.max_elt - 727 val Base.Map.S_poly.min_elt - 727 val Base.Set.S_poly.max_elt - 727 val Base.Set.S_poly.min_elt 727 val Base.Set.S_poly.of_list 727 val Base.Set.S_poly.of_tree 727 val Base.Set.S_poly.to_list 727 val Base.Set.S_poly.to_tree 728 val Base.Map.S_poly.of_alist - 728 val Base.Set.S_poly.elements 728 val Base.Set.S_poly.is_empty 729 val Base.Set.S_poly.singleton - 730 val Base.Set.S_poly.choose_exn - 731 val Base.Map.S_poly.of_sequence $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin "group b" 218 val Base.List.group 221 val Base.Hashtbl.group @@ -152,8 +153,18 @@ $ firefox /tmp/html/base/index.html 214 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t 216 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 218 val Base.Or_error.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 222 val Base.Either.First.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t 226 val Base.Applicative.Make.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t + 227 val Base.Applicative.Make2.map2 : ('a, 'e) X.t -> ('b, 'e) X.t -> f:('a -> 'b -> 'c) -> ('c, 'e) X.t + 227 val Base.Applicative.Make3.map2 : ('a, 'd, 'e) X.t -> ('b, 'd, 'e) X.t -> f:('a -> 'b -> 'c) -> ('c, 'd, 'e) X.t 227 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 228 val Base.Applicative.Pair.F.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 228 val Base.Applicative.Pair.G.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 230 val Base.Applicative.Of_monad.map2 : 'a M.t -> 'b M.t -> f:('a -> 'b -> 'c) -> 'c M.t + 231 val Base.Applicative.Compose.F.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 231 val Base.Applicative.Compose.G.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 231 val Base.Applicative.S_to_S2.X.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 231 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 235 mod Base.Applicative.Make_using_map2 236 sig Base.Applicative.Basic_using_map2 236 mod Base.Applicative.Make2_using_map2 @@ -171,24 +182,18 @@ $ firefox /tmp/html/base/index.html 322 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 323 val Base.Array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 340 type 'a Base.Applicative.Make_using_map2.X.t - 340 val Base.Applicative.Make_using_map2.all : 'a X.t list -> 'a list X.t + 340 val Base.Applicative.Make_using_map2.map : 'a X.t -> f:('a -> 'b) -> 'b X.t 341 type ('a, 'e) Base.Applicative.Make2_using_map2.X.t 341 type ('a, 'd, 'e) Base.Applicative.Make3_using_map2.X.t - 341 val Base.Applicative.Make_using_map2.both : 'a X.t -> 'b X.t -> ('a * 'b) X.t 342 val Base.Applicative.Make_using_map2.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] 343 val Base.Applicative.Make2_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] 343 val Base.Applicative.Make3_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - 343 val Base.Applicative.Make_using_map2.return : 'a -> 'a X.t - 345 val Base.Applicative.Make_using_map2.X.return : 'a -> 'a t - 347 type 'a Base.Applicative.Make_using_map2_local.X.t - 348 type ('a, 'e) Base.Applicative.Make2_using_map2_local.X.t - 348 type ('a, 'd, 'e) Base.Applicative.Make3_using_map2_local.X.t - 349 val Base.Applicative.Make_using_map2_local.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] - 350 val Base.Applicative.Make2_using_map2_local.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] - 350 val Base.Applicative.Make3_using_map2_local.X.map : [ `Define_using_map2 - | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] 623 val Base.Applicative.S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 624 val Base.Applicative.S2.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t + 624 val Base.Applicative.S3.map2 : ('a, 'd, 'e) t -> ('b, 'd, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'd, 'e) t + 624 val Base.Either.Focused.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t + 629 val Base.Applicative.S_local.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 739 type 'a Base.Applicative.Basic_using_map2.t 740 type ('a, 'e) Base.Applicative.Basic2_using_map2.t 740 type ('a, 'd, 'e) Base.Applicative.Basic3_using_map2.t @@ -197,18 +202,12 @@ $ firefox /tmp/html/base/index.html 742 val Base.Applicative.Basic3_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] 746 type 'a Base.Applicative.Basic_using_map2_local.t - 747 type ('a, 'e) Base.Applicative.Basic2_using_map2_local.t - 747 type ('a, 'd, 'e) Base.Applicative.Basic3_using_map2_local.t - 748 val Base.Applicative.Basic_using_map2_local.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] - 749 val Base.Applicative.Basic2_using_map2_local.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] - 749 val Base.Applicative.Basic3_using_map2_local.map : [ `Define_using_map2 - | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin --static-sort "List map2" - 261 val Base.List.rev_map2_exn - 267 val Base.List.map2_exn - 275 val Base.List.map2 - 299 val Base.List.rev_map2 - 351 val Base.List.Cartesian_product.map2 + 202 val Base.List.rev_map2_exn + 208 val Base.List.map2_exn + 215 val Base.List.map2 + 239 val Base.List.rev_map2 + 292 val Base.List.Cartesian_product.map2 $ sherlodoc --no-rhs --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 2c09c1f58c..c1c775faa4 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -110,12 +110,10 @@ TODO : get a result for the query bellow $ sherlodoc ":extensible_type" cons Main.MyExtension : moo -> extensible_type $ sherlodoc ":exn" - sherlodoc: internal error, uncaught exception: - File "query/dynamic_cost.ml", line 328, characters 8-14: Assertion failed - - [125] + exn Main.Explicit_exn : exn_payload -> exn + exn Main.Implicit_exn : exn_payload -> exn + cons Main.Very_explicit_exn : exn_payload -> exn $ sherlodoc ": exn_payload -> _" - sherlodoc: internal error, uncaught exception: - File "query/dynamic_cost.ml", line 328, characters 8-14: Assertion failed - - [125] + exn Main.Explicit_exn : exn_payload -> exn + exn Main.Implicit_exn : exn_payload -> exn + cons Main.Very_explicit_exn : exn_payload -> exn From 1f7e057b59bee37b45691355f3cadf997e9c941c Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 14 Dec 2023 16:10:19 +0100 Subject: [PATCH 184/285] cache typeexprs --- db/elt.ml | 12 ++++++++---- db/typepath.ml | 2 -- db/typexpr.ml | 18 +++++++++++++++++- db/typexpr.mli | 16 ++++++++++++++++ index/load_doc.ml | 18 ++++++++++-------- query/parser.mly | 24 ++++++++++++------------ query/type_distance.ml | 4 +++- test/cram/base.t/run.t | 21 +++++++++++---------- 8 files changed, 77 insertions(+), 38 deletions(-) create mode 100644 db/typexpr.mli diff --git a/db/elt.ml b/db/elt.ml index 93d5b1431e..6da2e53783 100644 --- a/db/elt.ml +++ b/db/elt.ml @@ -65,12 +65,16 @@ module T = struct let structural_compare a b = begin - match String.compare a.name b.name with + match Int.compare (String.length a.name) (String.length b.name) with | 0 -> begin - match Option.compare compare_pkg a.pkg b.pkg with + match String.compare a.name b.name with | 0 -> begin - match Stdlib.compare a.kind b.kind with - | 0 -> Stdlib.compare a.url b.url + match Option.compare compare_pkg a.pkg b.pkg with + | 0 -> begin + match Stdlib.compare a.kind b.kind with + | 0 -> Stdlib.compare a.url b.url + | c -> c + end | c -> c end | c -> c diff --git a/db/typepath.ml b/db/typepath.ml index fbee9d605c..7b911f27f9 100644 --- a/db/typepath.ml +++ b/db/typepath.ml @@ -79,5 +79,3 @@ module For_suffix_tree = struct let of_typ ~ignore_any ~all_names t = of_typ ~ignore_any ~all_names ~prefix:[] ~sgn:Pos t end - - diff --git a/db/typexpr.ml b/db/typexpr.ml index af9ab901d2..906510ac65 100644 --- a/db/typexpr.ml +++ b/db/typexpr.ml @@ -7,6 +7,22 @@ type t = | Unhandled [@@deriving show] +let table = Hashtbl.create 256 + +let cache t = + match Hashtbl.find_opt table t with + | Some t -> t + | None -> + Hashtbl.add table t t ; + t + +let arrow a b = cache (Arrow (a, b)) +let constr name args = cache (Constr (name, args)) +let tuple args = cache (Tuple args) +let poly name = cache (Poly name) +let any = Any +let unhandled = Unhandled + let rec show = function | Arrow (a, b) -> show_parens a ^ " -> " ^ show b | Constr (t, []) -> t @@ -33,4 +49,4 @@ and show_tuple = function | [ x ] -> show x | x :: xs -> show_parens x ^ " * " ^ show_tuple xs - let size typ = typ |> show |> String.length \ No newline at end of file +let size typ = typ |> show |> String.length diff --git a/db/typexpr.mli b/db/typexpr.mli new file mode 100644 index 0000000000..09d25bbeb3 --- /dev/null +++ b/db/typexpr.mli @@ -0,0 +1,16 @@ +type t = private + | Arrow of t * t + | Constr of string * t list + | Tuple of t list + | Poly of string + | Any + | Unhandled + +val arrow : t -> t -> t +val constr : string -> t list -> t +val tuple : t list -> t +val poly : string -> t +val any : t +val unhandled : t +val show : t -> string +val size : t -> int diff --git a/index/load_doc.ml b/index/load_doc.ml index f2ae4330f5..5b264f25bd 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -13,8 +13,7 @@ let generic_cost ~ignore_no_doc name has_doc = let kind_cost (kind : Elt.Kind.t) = match kind with - | Constructor typ | Field typ | Val typ -> - Db.Typexpr.size typ + | Constructor typ | Field typ | Val typ -> Db.Typexpr.size typ | Doc -> 400 | TypeDecl _ | Module -> 0 | Exception _ | Class_type | Method | Class -> 10 @@ -52,12 +51,13 @@ let fullname t = Format.asprintf "%a" Pretty.show_type_name_verbose t let rec typ_of_odoc_typ otyp = let open Db.Typexpr in match otyp with - | Odoc_model.Lang.TypeExpr.Var str -> Poly str - | Any -> Any + | Odoc_model.Lang.TypeExpr.Var str -> poly str + | Any -> any | Arrow (_lbl, left, right) -> - Arrow (typ_of_odoc_typ left, typ_of_odoc_typ right) - | Constr (name, args) -> Constr (fullname name, List.map typ_of_odoc_typ args) - | _ -> Unhandled + arrow (typ_of_odoc_typ left) (typ_of_odoc_typ right) + | Constr (name, args) -> + constr (fullname name) (List.map typ_of_odoc_typ args) + | _ -> unhandled let with_tokenizer str fn = let str = String.lowercase_ascii str in @@ -122,7 +122,9 @@ let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = let typ = typ_of_odoc_typ searchable_type in Elt.Kind.constructor typ | Field { mutable_ = _; parent_type; type_ } -> - let typ = type_ |> searchable_type_of_record parent_type |> typ_of_odoc_typ in + let typ = + type_ |> searchable_type_of_record parent_type |> typ_of_odoc_typ + in Elt.Kind.field typ | Doc _ -> Doc | Exception { args; res } -> diff --git a/query/parser.mly b/query/parser.mly index 15dbc62908..520bbc1e35 100644 --- a/query/parser.mly +++ b/query/parser.mly @@ -24,34 +24,34 @@ separated_twolong_list(sep, elt): main: | t=typ EOF { t } - | EOF { Any } + | EOF { any } ; typ: - | a=typ1 ARROW b=typ { Arrow (a, b) } - | a=typ1 ARROW { Arrow (a, Any) } - | ARROW b=typ { Arrow (Any, b) } - | ARROW EOF { Arrow (Any, Any) } + | a=typ1 ARROW b=typ { arrow a b } + | a=typ1 ARROW { arrow a any } + | ARROW b=typ { arrow any b } + | ARROW EOF { arrow any any } | t=typ1 { t } ; typ1: - | x=typ0 xs=tups { match xs with [] -> x | xs -> Tuple (x::xs) } + | x=typ0 xs=tups { match xs with [] -> x | xs -> tuple (x::xs) } ; tups: | STAR x=typ0 xs=tups { x::xs } - | STAR { [Any] } + | STAR { [any] } | EOF { [] } | { [] } ; typ0: - | ANY { Any } - | w=POLY { Poly w } - | w=WORD { Constr (w, []) } - | t=typ0 w=WORD { Constr (w, [t]) } - | PARENS_OPEN ts=typ_list PARENS_CLOSE w=WORD { Constr (w, ts) } + | ANY { any } + | w=POLY { poly w } + | w=WORD { constr w [] } + | t=typ0 w=WORD { constr w [t] } + | PARENS_OPEN ts=typ_list PARENS_CLOSE w=WORD { constr w ts } | PARENS_OPEN t=typ PARENS_CLOSE { t } | PARENS_OPEN t=typ EOF { t } ; diff --git a/query/type_distance.ml b/query/type_distance.ml index 89f88a6c0f..ef84627919 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -165,7 +165,9 @@ let minimize = function !best let length typ = - typ |> Type_path.of_typ ~ignore_any:false |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 + typ + |> Type_path.of_typ ~ignore_any:false + |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 let v ~query ~element = let query_paths = Type_path.of_typ ~ignore_any:false query in diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 27c067ac65..8a64ddd3e8 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -9,10 +9,11 @@ $ du -sh megaodocl 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + + real 0m1.154s + user 0m1.110s + sys 0m0.041s - real 0m1.157s - user 0m1.111s - sys 0m0.043s @@ -43,8 +44,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2720 db.js - 2056 db.js.gz + 2560 db.js + 1932 db.js.gz 1544 megaodocl.gz @@ -114,12 +115,12 @@ $ firefox /tmp/html/base/index.html 726 val Base.Set.S_poly.length 726 val Base.Set.S_poly.remove 727 type 'a Base.Hashtbl.S_poly.key + 727 val Base.Set.S_poly.max_elt 727 val Base.Set.S_poly.of_list 727 val Base.Set.S_poly.of_tree 727 val Base.Set.S_poly.to_list 727 val Base.Set.S_poly.to_tree 728 val Base.Map.S_poly.of_alist - 728 val Base.Set.S_poly.is_empty 729 val Base.Set.S_poly.singleton $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin "group b" 218 val Base.List.group @@ -129,8 +130,8 @@ $ firefox /tmp/html/base/index.html 323 val Base.List.groupi 324 val Base.Set.group_by 326 val Base.Hashtbl.Poly.group - 330 val Base.Hashtbl.Creators.group 330 val Base.List.sort_and_group + 330 val Base.Hashtbl.Creators.group 336 val Base.List.Assoc.sort_and_group 429 val Base.Set.Poly.group_by 441 val Base.Set.Using_comparator.group_by @@ -155,16 +156,16 @@ $ firefox /tmp/html/base/index.html 218 val Base.Or_error.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 222 val Base.Either.First.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t 226 val Base.Applicative.Make.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t + 227 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 227 val Base.Applicative.Make2.map2 : ('a, 'e) X.t -> ('b, 'e) X.t -> f:('a -> 'b -> 'c) -> ('c, 'e) X.t 227 val Base.Applicative.Make3.map2 : ('a, 'd, 'e) X.t -> ('b, 'd, 'e) X.t -> f:('a -> 'b -> 'c) -> ('c, 'd, 'e) X.t - 227 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 228 val Base.Applicative.Pair.F.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 228 val Base.Applicative.Pair.G.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 230 val Base.Applicative.Of_monad.map2 : 'a M.t -> 'b M.t -> f:('a -> 'b -> 'c) -> 'c M.t + 231 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 231 val Base.Applicative.Compose.F.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 231 val Base.Applicative.Compose.G.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 231 val Base.Applicative.S_to_S2.X.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 231 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 235 mod Base.Applicative.Make_using_map2 236 sig Base.Applicative.Basic_using_map2 236 mod Base.Applicative.Make2_using_map2 @@ -189,6 +190,7 @@ $ firefox /tmp/html/base/index.html 343 val Base.Applicative.Make2_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] 343 val Base.Applicative.Make3_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] + 343 val Base.Applicative.Make_using_map2.return : 'a -> 'a X.t 623 val Base.Applicative.S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 624 val Base.Applicative.S2.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t 624 val Base.Applicative.S3.map2 : ('a, 'd, 'e) t -> ('b, 'd, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'd, 'e) t @@ -201,7 +203,6 @@ $ firefox /tmp/html/base/index.html 742 val Base.Applicative.Basic2_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] 742 val Base.Applicative.Basic3_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - 746 type 'a Base.Applicative.Basic_using_map2_local.t $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin --static-sort "List map2" 202 val Base.List.rev_map2_exn 208 val Base.List.map2_exn From 76554dfb6b59861f347acb5409b43867a232bc4d Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 14 Dec 2023 17:00:54 +0100 Subject: [PATCH 185/285] cleanup in pretty --- index/load_doc.ml | 17 ++++-- index/pretty.ml | 141 --------------------------------------------- index/typename.ml | 47 +++++++++++++++ index/typename.mli | 6 ++ 4 files changed, 66 insertions(+), 145 deletions(-) delete mode 100644 index/pretty.ml create mode 100644 index/typename.ml create mode 100644 index/typename.mli diff --git a/index/load_doc.ml b/index/load_doc.ml index 5b264f25bd..7cc10d16eb 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -46,7 +46,6 @@ let cost ~name ~kind ~doc_html = *) let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) -let fullname t = Format.asprintf "%a" Pretty.show_type_name_verbose t let rec typ_of_odoc_typ otyp = let open Db.Typexpr in @@ -56,7 +55,7 @@ let rec typ_of_odoc_typ otyp = | Arrow (_lbl, left, right) -> arrow (typ_of_odoc_typ left) (typ_of_odoc_typ right) | Constr (name, args) -> - constr (fullname name) (List.map typ_of_odoc_typ args) + constr (Typename.to_string name) (List.map typ_of_odoc_typ args) | _ -> unhandled let with_tokenizer str fn = @@ -190,6 +189,14 @@ let is_from_module_type Odoc_search.Entry.{ id; _ } = is_from_module_type (parent :> Odoc_model.Paths.Identifier.Any.t) | _ -> is_from_module_type id +let prefixname n = + match + (n :> Odoc_model.Paths.Identifier.t) + |> Odoc_model.Paths.Identifier.fullname |> List.rev + with + | [] -> "" + | _ :: q -> q |> List.rev |> String.concat "." + let register_entry ~db ~index_name ~type_search ~index_docstring (Odoc_search.Entry.{ id; doc; kind } as entry) = let open Odoc_search in @@ -202,7 +209,9 @@ let register_entry ~db ~index_name ~type_search ~index_docstring if Odoc_model.Paths.Identifier.is_internal id || is_type_extension then () else - let full_name = id |> Pretty.fullname |> String.concat "." in + let full_name = + id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." + in let doc_txt = Text.of_doc doc in let doc_html = match doc_txt with @@ -212,7 +221,7 @@ let register_entry ~db ~index_name ~type_search ~index_docstring let kind' = convert_kind entry in let name = match kind with - | Doc _ -> Pretty.prefixname id + | Doc _ -> prefixname id | _ -> full_name in let score = cost ~name ~kind:kind' ~doc_html in diff --git a/index/pretty.ml b/index/pretty.ml deleted file mode 100644 index 14c6ed81a8..0000000000 --- a/index/pretty.ml +++ /dev/null @@ -1,141 +0,0 @@ -(** This file contains useful printer, that are however of dubious - maintainability. Their result is used to be parsed afteward, it is not - printed but consumed as the basis for type-search. Because of this it is - sensitive code. *) - -open Odoc_model -module ModuleName = Odoc_model.Names.ModuleName -module H = Tyxml.Html - -let show_module_name h md = - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) - -let rec show_ident_long h (r : Paths.Identifier.t_pv Paths.Identifier.id) = - match r.Paths.Identifier.iv with - | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) - | `Type (md, n) -> - Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) - | _ -> Format.fprintf h "%S" (Paths.Identifier.name r) - -and show_ident_short h (r : Paths.Identifier.t_pv Paths.Identifier.id) = - match r.Paths.Identifier.iv with - | `Type (_, n) -> Format.fprintf h "%s" (Names.TypeName.to_string n) - | `CoreType n -> Format.fprintf h "%s" (Names.TypeName.to_string n) - | _ -> Format.fprintf h "%S" (Paths.Identifier.name r) - -and show_module_t h p = - Format.fprintf h "%s" - (Odoc_document.Url.render_path (p : Paths.Path.Module.t :> Paths.Path.t)) -(* - function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_ident_long - (Resolved.identifier (t : Resolved.Module.t :> Resolved.t) - :> Paths.Identifier.t_pv Paths.Identifier.id) - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x - | `Root x -> Format.fprintf h "%s" x - | `Apply (m, _) -> Format.fprintf h "%a(_)" show_module_t m - | `Forward str -> Format.fprintf h "%s" str - | `Result _ -> () - | `Identifier _ -> () - *) - -and show_module_path h = function - | `Identifier (`Module (_, md)) -> - Format.fprintf h "" show_module_name md - | `Identifier (`Root (_, md)) -> - Format.fprintf h "" show_module_name md - | `Identifier _ -> Format.fprintf h "" - | `Subst _ -> Format.fprintf h "" - | `Hidden _ -> Format.fprintf h "" - | `Module (pt, md) -> - Format.fprintf h "" show_module_path pt show_module_name - md - | `Canonical (pt, md) -> - Format.fprintf h "" show_module_path pt show_module_t md - | `Apply _ -> Format.fprintf h "" - | `Alias (pt, md) -> - Format.fprintf h "" show_module_path pt show_module_path md - | `OpaqueModule _ -> Format.fprintf h "" - -and show_signature h sig_ = - match sig_.iv with - | `Root (_, name) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) - | `Module (pt, mdl) -> - Format.fprintf h "%a.%a" show_signature pt show_module_name mdl - | `Parameter (_, p) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string p) - | `Result t -> Format.fprintf h "%a" show_signature t - | `ModuleType (_, p) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) - -let rec full_name_aux : Paths.Identifier.t -> string list = - let open Names in - let open Paths.Identifier in - fun x -> - match x.iv with - | `Root (_, name) -> [ ModuleName.to_string name ] - | `Page (_, name) -> [ PageName.to_string name ] - | `LeafPage (_, name) -> [ PageName.to_string name ] - | `Module (parent, name) -> - ModuleName.to_string name :: full_name_aux (parent :> t) - | `Parameter (parent, name) -> - ModuleName.to_string name :: full_name_aux (parent :> t) - | `Result x -> full_name_aux (x :> t) - | `ModuleType (parent, name) -> - ModuleTypeName.to_string name :: full_name_aux (parent :> t) - | `Type (parent, name) -> - TypeName.to_string name :: full_name_aux (parent :> t) - | `CoreType name -> [ TypeName.to_string name ] - | `Constructor (parent, name) -> - ConstructorName.to_string name :: full_name_aux (parent :> t) - | `Field (parent, name) -> - FieldName.to_string name :: full_name_aux (parent :> t) - | `Extension (parent, name) -> - ExtensionName.to_string name :: full_name_aux (parent :> t) - | `Exception (parent, name) -> - ExceptionName.to_string name :: full_name_aux (parent :> t) - | `CoreException name -> [ ExceptionName.to_string name ] - | `Value (parent, name) -> - ValueName.to_string name :: full_name_aux (parent :> t) - | `Class (parent, name) -> - ClassName.to_string name :: full_name_aux (parent :> t) - | `ClassType (parent, name) -> - ClassTypeName.to_string name :: full_name_aux (parent :> t) - | `Method (parent, name) -> - MethodName.to_string name :: full_name_aux (parent :> t) - | `InstanceVariable (parent, name) -> - InstanceVariableName.to_string name :: full_name_aux (parent :> t) - | `Label (parent, name) -> - LabelName.to_string name :: full_name_aux (parent :> t) - | `AssetFile (parent, name) -> name :: full_name_aux (parent :> t) - | `SourceDir (parent, name) -> name :: full_name_aux (parent :> t) - | `SourcePage (parent, name) -> name :: full_name_aux (parent :> t) - | `SourceLocation (parent, name) -> - DefName.to_string name :: full_name_aux (parent :> t) - | `SourceLocationMod id -> full_name_aux (id :> t) - | `SourceLocationInternal (parent, name) -> - LocalName.to_string name :: full_name_aux (parent :> t) - | `ExtensionDecl (parent, name, _) -> - ExtensionName.to_string name :: full_name_aux (parent :> t) - -let fullname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string list = - fun n -> List.rev @@ full_name_aux (n :> Paths.Identifier.t) - -let prefixname : [< Paths.Identifier.t_pv ] Paths.Identifier.id -> string = - fun n -> - match full_name_aux (n :> Paths.Identifier.t) with - | [] -> "" - | _ :: q -> q |> List.rev |> String.concat "." - -let show_type_name_verbose h : Paths.Path.Type.t -> _ = function - | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_ident_long - (Resolved.identifier (t :> Resolved.t)) - | `Identifier (path, _hidden) -> - let name = fullname (path :> Paths.Identifier.t) |> String.concat "." in - Format.fprintf h "%s" name - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x diff --git a/index/typename.ml b/index/typename.ml new file mode 100644 index 0000000000..cd5fcb0649 --- /dev/null +++ b/index/typename.ml @@ -0,0 +1,47 @@ +(* This might be hard to maintain but it is useful *) + +open Odoc_model +module ModuleName = Odoc_model.Names.ModuleName +module H = Tyxml.Html + +let show_module_name h md = + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) + +let rec show_ident_long h (r : Paths.Identifier.t_pv Paths.Identifier.id) = + match r.Paths.Identifier.iv with + | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) + | `Type (md, n) -> + Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) + | _ -> + Format.fprintf h "%S" (r |> Paths.Identifier.fullname |> String.concat ".") + +and show_module_t h p = + Format.fprintf h "%s" + (Odoc_document.Url.render_path (p : Paths.Path.Module.t :> Paths.Path.t)) + +and show_signature h sig_ = + match sig_.iv with + | `Root (_, name) -> + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) + | `Module (pt, mdl) -> + Format.fprintf h "%a.%a" show_signature pt show_module_name mdl + | `Parameter (_, p) -> + Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string p) + | `Result t -> Format.fprintf h "%a" show_signature t + | `ModuleType (_, p) -> + Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) + +let show_type_name_verbose h : Paths.Path.Type.t -> _ = function + | `Resolved t -> + let open Paths.Path in + Format.fprintf h "%a" show_ident_long + (Resolved.identifier (t :> Resolved.t)) + | `Identifier (path, _hidden) -> + let name = + (path :> Paths.Identifier.t) + |> Paths.Identifier.fullname |> String.concat "." + in + Format.fprintf h "%s" name + | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + +let to_string t = Format.asprintf "%a" show_type_name_verbose t diff --git a/index/typename.mli b/index/typename.mli new file mode 100644 index 0000000000..a2492e4351 --- /dev/null +++ b/index/typename.mli @@ -0,0 +1,6 @@ +(** [Typename.string tn] is a string representing the type name of [tn] as a string. + Such a function could be provided by Odoc but we do two things differently : + - Core types like [int] and [string] are represented as [Stdlib.int] or [Stdlib.string] + - We do not use any parenthesis on functors. *) +val to_string : + Odoc_model.Paths.Path.Type.t -> string From 4c58e559e186b6e90a12d0ec1710d591f0fc4db0 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 15 Dec 2023 15:30:50 +0100 Subject: [PATCH 186/285] refactoring and documentation --- README.md | 26 ++++++------ cli/main.ml | 6 +-- db/db.ml | 12 ++---- db/db.mli | 10 ++--- db/dune | 2 +- db/{elt.ml => entry.ml} | 10 ++--- db/occ.ml | 14 +++---- db/occ.mli | 23 ++++++---- db/string_list_map.ml | 5 --- db/string_map.ml | 1 + db/suffix_tree.ml | 2 +- db/suffix_tree.mli | 17 ++++---- db/type_polarity.ml | 79 ++++++++++++++++++++++++++++++++++ db/type_polarity.mli | 60 ++++++++++++++++++++++++++ db/typepath.ml | 81 ----------------------------------- db/typepath.mli | 91 ---------------------------------------- index/load_doc.ml | 30 ++++++------- index/typename.mli | 3 +- jsoo/main.ml | 10 ++--- query/dynamic_cost.ml | 57 +++++++++++++------------ query/query.ml | 12 +++--- query/query.mli | 3 +- query/query_parser.ml | 17 +++----- query/query_parser.mli | 3 ++ query/type_distance.ml | 43 +++++++++++++++---- query/type_distance.mli | 1 + test/cram/base.t/run.t | 12 +++--- test/cram/cli.t/main.mli | 5 ++- test/cram/cli.t/run.t | 15 +++++-- test/cram/simple.t/run.t | 2 +- www/ui.ml | 10 ++--- 31 files changed, 333 insertions(+), 329 deletions(-) rename db/{elt.ml => entry.ml} (91%) delete mode 100644 db/string_list_map.ml create mode 100644 db/string_map.ml create mode 100644 db/type_polarity.ml create mode 100644 db/type_polarity.mli delete mode 100644 db/typepath.ml delete mode 100644 db/typepath.mli create mode 100644 query/query_parser.mli create mode 100644 query/type_distance.mli diff --git a/README.md b/README.md index 543a58aedf..c35f081954 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ available format are `marshal`, `js`. The `js` format, for javascript, is the one compatible with odoc, and the `marshal` for most other uses. -There is a third format : `ancient`, that is only available if the `ancient` -package is installed. It is more complicated than the other two, you can read on -it [here](https://github.com/UnixJunkie/ocaml-ancient). It is used for the +There is a third format : `ancient`, that is only available if the package + `ancient` is installed. It is more complicated than the other two, you can read +on it [here](https://github.com/UnixJunkie/ocaml-ancient). It is used for the [online](https://doc.sherlocode.com) version of sherlodoc, and is a mandatory dependency of the `sherlodoc-www` package. @@ -53,7 +53,7 @@ to input a string query. A query is a list of words, separated by spaces. Results will be entries that have every word of the list present in them. ``` -list map +"list map" ``` The above query will return entries that have both `list` and `map` in them. @@ -65,18 +65,18 @@ exception, a constructor or a record field. Matching a type is fuzzy, if you do the following query : ``` -blabla : string +"blabla : string" ``` It could return `val blablabla : int -> string` and `val blabla2 : string`. -You can have just the type-part of the query : `: string -> int` is a valid +You can have just the type-part of the query : `": string -> int"` is a valid query. You can use wildcards : ``` -: string -> _ +": string -> _" ``` will only return functions that take a string a argument, no matter what they @@ -84,7 +84,7 @@ return. There is limited support for polymorphism : you cannot search for `'a -> 'a` and get every function `int -> int`, `string -> string` etc. However it will return -a function whose litteral type is `'a -> 'a`. Having the first behaviour would +a function whose literal type is `'a -> 'a`. Having the first behaviour would be a lot harder to program, and probably not a good idea, as it would be impossible to search for polymorphic functions. @@ -149,17 +149,17 @@ cp db.js html_output/db.js ; ``` Obviously, most people use dune, and do not call `odoc html-generate`. A patch -for dune is being [worked -on](https://github.com/emileTrotignon/dune/tree/sherlodune). If you want to, you -can test it, it should work. It is still work in progress. +for dune is being [worked on](https://github.com/emileTrotignon/dune/tree/search-odoc-new). +If you want to, you can test it, it should work. It is still work in progress. ## Sherlodoc online If you want to use sherlodoc as a server, like on [doc.sherlocode.com](https://doc.sherlocode.com), you can. This is packaged -separately in `sherlodoc-www`, but also live in this repo. +separately in `sherlodoc-www`, but also lives in this repo. -Once you have installed `shelodoc-www`, you need to generate your search database : +Once you have installed `sherlodoc-www`, you need to generate your search +database : ```bash sherlodoc_index --format=ancient --db=db.bin $(find /path/to/doc -name "*.odocl") diff --git a/cli/main.ml b/cli/main.ml index ec6cf8bb2b..952494829c 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -4,7 +4,7 @@ let pp_or cond pp_true pp_false ppf = if cond then pp_true ppf else pp_false ppf let string_of_kind = - let open Db.Elt.Kind in + let open Db.Entry.Kind in function | Doc -> "doc" | TypeDecl _ -> "type" @@ -21,7 +21,7 @@ let string_of_kind = | Val _ -> "val" let print_result ~print_cost ~no_rhs - Db.Elt. + Db.Entry. { name ; rhs ; url = _ @@ -34,7 +34,7 @@ let print_result ~print_cost ~no_rhs let score = if print_cost then string_of_int score ^ " " else "" in let typedecl_params = (match kind with - | Db.Elt.Kind.TypeDecl args -> args + | Db.Entry.Kind.TypeDecl args -> args | _ -> None) |> Option.map (fun str -> str ^ " ") |> Option.value ~default:"" diff --git a/db/db.ml b/db/db.ml index 366c8c64bd..cb8400a2ed 100644 --- a/db/db.ml +++ b/db/db.ml @@ -1,8 +1,8 @@ -module Elt = Elt +module Entry = Entry module Suffix_tree = Suffix_tree module Occ = Occ module Storage = Storage -module Typepath = Typepath +module Type_polarity = Type_polarity module Typexpr = Typexpr include Db_typedef @@ -27,12 +27,8 @@ let export db = let store db name elt ~count = Suffix_tree.With_occ.add_suffixes db.writer_types name (count, elt) -let store_type_paths db elt paths = - List.iter - (fun (path, count) -> - let word = String.concat "" path in - store db ~count word elt) - (Typepath.regroup paths) +let store_type_polarities db elt polarities = + List.iter (fun (word, count) -> store db ~count word elt) polarities let store_word db word elt = Suffix_tree.With_elts.add_suffixes db.writer_names word elt diff --git a/db/db.mli b/db/db.mli index 6ab7a600f2..05bf120619 100644 --- a/db/db.mli +++ b/db/db.mli @@ -1,8 +1,8 @@ -module Elt = Elt +module Entry = Entry module Storage = Storage module Suffix_tree = Suffix_tree module Occ = Occ -module Typepath = Typepath +module Type_polarity = Type_polarity module Typexpr = Typexpr type t = Db_typedef.t = @@ -12,7 +12,7 @@ type t = Db_typedef.t = (** The type of a database. [db_names] is for text-based part of the query and [db_types] for the type-based part. - [db_types] has [Elt.t array Int_map.t] ([Occ.t]) as a payload because we want + [db_types] has [Entry.t array Int_map.t] ([Occ.t]) as a payload because we want the query [blabla : int -> int -> _] to return only entries that take at least two ints as arguments, an entry of type [int -> string] is invalid. The int_map map a number of occurences to a set of entries. @@ -22,5 +22,5 @@ type writer val make : unit -> writer val export : writer -> t -val store_type_paths : writer -> Elt.t -> string list list -> unit -val store_word : writer -> string -> Elt.t -> unit +val store_type_polarities : writer -> Entry.t -> Type_polarity.t list -> unit +val store_word : writer -> string -> Entry.t -> unit diff --git a/db/dune b/db/dune index db9aea5cea..4899646a37 100644 --- a/db/dune +++ b/db/dune @@ -2,4 +2,4 @@ (library (name db) - (libraries unix)) + (libraries unix dum)) diff --git a/db/elt.ml b/db/entry.ml similarity index 91% rename from db/elt.ml rename to db/entry.ml index 6da2e53783..2fc59f5e74 100644 --- a/db/elt.ml +++ b/db/entry.ml @@ -20,16 +20,16 @@ module Kind = struct let doc = Doc let type_decl args = TypeDecl args let module_ = Module - let exception_ type_path = Exception type_path + let exception_ typ = Exception typ let class_type = Class_type let method_ = Method let class_ = Class let type_extension = TypeExtension - let extension_constructor type_path = ExtensionConstructor type_path + let extension_constructor typ = ExtensionConstructor typ let module_type = ModuleType - let constructor type_path = Constructor type_path - let field type_path = Field type_path - let val_ type_path = Val type_path + let constructor typ = Constructor typ + let field typ = Field typ + let val_ typ = Val typ end module Package = struct diff --git a/db/occ.ml b/db/occ.ml index 60875261b1..bb9db288d8 100644 --- a/db/occ.ml +++ b/db/occ.ml @@ -1,12 +1,12 @@ module Int_map = Map.Make (Int) -type t = Elt.Array.t Int_map.t -type elt = int * Elt.t +type t = Entry.Array.t Int_map.t +type elt = int * Entry.t let find = Int_map.find_opt let fold = Int_map.fold let is_empty = Int_map.is_empty -let equal_elt (a_count, a) (b_count, b) = a_count = b_count && Elt.equal a b +let equal_elt (a_count, a) (b_count, b) = a_count = b_count && Entry.equal a b (* let of_list li = @@ -15,14 +15,14 @@ let of_list li = let elts = try Int_map.find count acc with Not_found -> [] in Int_map.add count (elt :: elts) acc) Int_map.empty li - |> Int_map.map Elt.Array.of_list + |> Int_map.map Entry.Array.of_list *) let of_list li = List.fold_left (fun acc (count, elt) -> match Int_map.find_opt count acc with - | None -> Int_map.add count (Elt.Set.singleton elt) acc - | Some set -> Int_map.add count (Elt.Set.add elt set) acc) + | None -> Int_map.add count (Entry.Set.singleton elt) acc + | Some set -> Int_map.add count (Entry.Set.add elt set) acc) Int_map.empty li - |> Int_map.map (fun set -> set |> Elt.Set.to_seq |> Array.of_seq) + |> Int_map.map (fun set -> set |> Entry.Set.to_seq |> Array.of_seq) diff --git a/db/occ.mli b/db/occ.mli index 8b432cd7df..57f68de1d1 100644 --- a/db/occ.mli +++ b/db/occ.mli @@ -1,15 +1,20 @@ -(** [Occ] stands for occurences. It associate sets of elements to the number - of time members of the set occurs. - The list [[a, a, b, b, c]] would correspond to [[(2, [a; b]); (1, [c]) ]]. - It is used or type search : you want to be able to return every function - that takes two ints as an argument. Without this datastrucure, we would only - to search for functions that take ints, without specifying the amount. *) +(** [Occ] stands for occurences. It associate sets of elements to the number of + time members of the set occurs. + +The list [[a, a, b, b, c]] would correspond to [[(2, [a; b]); (1, [c]) ]]. It is +used or type search : you want to be able to return every function that takes +two ints as an argument. Without this datastrucure, we would only to search for +functions that take ints, without specifying the amount. + +This datastructure is used at the leafs of the suffix tree : so when doing type +search, we first perform a type search ignoring occurences, and afterwards +filter the results according to them. *) type t -type elt = int * Elt.t +type elt = int * Entry.t -val find : int -> t -> Elt.t array option -val fold : (int -> Elt.t array -> 'a -> 'a) -> t -> 'a -> 'a +val find : int -> t -> Entry.t array option +val fold : (int -> Entry.t array -> 'a -> 'a) -> t -> 'a -> 'a val is_empty : t -> bool val equal_elt : elt -> elt -> bool val of_list : elt list -> t diff --git a/db/string_list_map.ml b/db/string_list_map.ml deleted file mode 100644 index 3899926707..0000000000 --- a/db/string_list_map.ml +++ /dev/null @@ -1,5 +0,0 @@ -include Map.Make (struct - type t = string list - - let compare = List.compare String.compare -end) diff --git a/db/string_map.ml b/db/string_map.ml new file mode 100644 index 0000000000..99d658088e --- /dev/null +++ b/db/string_map.ml @@ -0,0 +1 @@ +include Map.Make (String) diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index 8895eb05e8..6493e3b5a1 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -451,5 +451,5 @@ module Make (S : SET) = struct let sets_tree = Automata.T.sets_tree end -module With_elts = Make (Elt.Array) +module With_elts = Make (Entry.Array) module With_occ = Make (Occ) diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index 1c071ff112..ca1cf54ead 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -1,5 +1,8 @@ -(** The suffix tree datastructure. You need to provide a datastructure for the - sets of elements at the leafs of the tree. *) +(** The suffix tree datastructure. This datastructure allows to efficiently + search for strings suffixes. + +You need to provide a datastructure for the sets of elements at the leafs of the +tree. *) module type SET = sig type t @@ -34,10 +37,10 @@ module Make (S : SET) : sig -> 'a end -module With_elts : module type of Make (Elt.Array) -(** [With_elts] is a suffix tree with array of elts at the leafs. It is used for - the text-based part of the database. *) +module With_elts : module type of Make (Entry.Array) +(** [With_elts] is a suffix tree with array of entries at the leafs. It is used + for the text-based part of the database. *) module With_occ : module type of Make (Occ) -(** [With_occ] is a suffix tree with occurence annotated arrays of elts at the - leafs. It is used for the type-based part of the database. *) +(** [With_occ] is a suffix tree with occurence annotated arrays of entries at + the leafs. It is used for the type-based part of the database. *) diff --git a/db/type_polarity.ml b/db/type_polarity.ml new file mode 100644 index 0000000000..465af86864 --- /dev/null +++ b/db/type_polarity.ml @@ -0,0 +1,79 @@ +open Typexpr + +let regroup lst = + String_map.bindings + @@ List.fold_left + (fun acc s -> + let count = try String_map.find s acc with Not_found -> 0 in + String_map.add s (count + 1) acc) + String_map.empty lst + +module Sign = struct + type t = + | Pos + | Neg + + let to_string = function + | Pos -> "+" + | Neg -> "-" + + let not = function + | Pos -> Neg + | Neg -> Pos +end + +let rev_concat lst = + List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst + +let rec tails = function + | [] -> [] + | _ :: xs as lst -> lst :: tails xs + +type t = string * int + +let all_type_names name = + name |> String.split_on_char '.' |> tails |> List.map (String.concat ".") + +let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function + | Poly _ -> [ "POLY" :: Sign.to_string sgn :: prefix ] + | Any -> + if ignore_any + then [ prefix ] + else [ "POLY" :: Sign.to_string sgn :: prefix ] + | Arrow (a, b) -> + List.rev_append + (of_typ ~ignore_any ~all_names ~prefix ~sgn:(Sign.not sgn) a) + (of_typ ~ignore_any ~all_names ~prefix ~sgn b) + | Constr (name, args) -> + name + |> (if all_names then all_type_names else fun name -> [ name ]) + |> List.map (fun name -> + let prefix = Sign.to_string sgn :: name :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + of_typ ~ignore_any ~all_names ~prefix ~sgn arg) + args + end) + |> rev_concat + | Tuple args -> + rev_concat + @@ List.map (of_typ ~ignore_any ~all_names ~prefix ~sgn) + @@ args + | Unhandled -> [] + +(** [of_typ ~ignore_any ~prefix ~sgn t] is a representation of [t] that + encodes the polarity of the elements of the type : in [string -> int] [int] + is positive and [string] negative. + It is registered in the database and search-base type uses this to obtain + results that fit the type asked for by the user. *) +let of_typ ~ignore_any ~all_names t = + t + |> of_typ ~ignore_any ~all_names ~prefix:[] ~sgn:Pos + |> List.map (String.concat "") + |> regroup diff --git a/db/type_polarity.mli b/db/type_polarity.mli new file mode 100644 index 0000000000..9cfae1a306 --- /dev/null +++ b/db/type_polarity.mli @@ -0,0 +1,60 @@ +(** This module provide a way to transform a type into strings, in such a way + that the string can be used for type search. + +The chosen representation is polarity : we do not represent the [->] or the [*] +constructors, but they affect the "polarity" of their children. + +The polarity of a component of a type indicate if it is produced or consumed by +the type. In the type [int -> string], [int] has negative polarity because it is +being consumed, and [string] has positive polarity because it is being produced. + +When you have [t -> u], the polarity of [t] is inversed, and the polarity of [u] +stays the same. So in the type [(int -> string) -> float], the polarities are +[+int], [-string] and [+float]. This is easier to see if you write the type with +an infix notation for the arrow : [-> (-> int string) float]. + +Once you have computed the polarities of the type of an entry [e], you can +register each polarity as corresponding to [e] in the search database. Then, +when the user queries for a type, we compute the polarities of the query type, a +search in a database for every polarity. + +We then return the result corresponding to intersection of each polarity : if +the user queries for [int -> string], we want to have every entry which consumes +an [int] and produces a [string], that is the intersection of the entries +associated to [-int] with the entries associated to [+string]. + +There is however a complication. If the user queries for [int -> int -> string], +then the polarities will be [-int], [-int] and [+string]. An entry of type [int +-> string] would be included in the intersection of these polarities. But the +user explicitely asked for two integer to be consumed. To fix this issue, we +track the number of occurences of each polarity. + +The polarities for [int -> int -> string], become [("-int", 2)] and [("+string", +1)], and allows us to filter entries according to this information. The exact +mechanism for this is explained in {!Occ}. +*) + +module Sign : sig + type t = + | Pos + | Neg + + val to_string : t -> string + val not : t -> t +end + +type t = string * int + +val of_typ : ignore_any:bool -> all_names:bool -> Typexpr.t -> t list +(** [of_typ ~ignore_any ~all_names typ] is the list of polarised types + corresponding to [typ]. + + - If [ignore_any] is true, the type [_] will be ignored, if it is true, it + will be treated like a type variable ['a]. + + - If [all_names] is true, extra polarities are added for every "possible name" + of each type. For instance the possible names of [Stdlib.Int64.t] are ["t"], + ["Int64.t"] and ["Stdlib.Int64.t"]. This allows for the user to use any of + the possible name. It is important to set this when registering entries in + the database, but you not need it when computing the polarities of a query. + *) diff --git a/db/typepath.ml b/db/typepath.ml deleted file mode 100644 index 7b911f27f9..0000000000 --- a/db/typepath.ml +++ /dev/null @@ -1,81 +0,0 @@ -open Typexpr - -let regroup lst = - String_list_map.bindings - @@ List.fold_left - (fun acc s -> - let count = try String_list_map.find s acc with Not_found -> 0 in - String_list_map.add s (count + 1) acc) - String_list_map.empty lst - -module Sign = struct - type t = - | Pos - | Neg - | Unknown - - let to_string = function - | Pos -> "+" - | Neg -> "-" - | Unknown -> "+" - - let not = function - | Pos -> Neg - | Neg -> Pos - | Unknown -> Unknown -end - -let rev_concat lst = - List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst - -let rec tails = function - | [] -> [] - | _ :: xs as lst -> lst :: tails xs - -module For_suffix_tree = struct - type t = string list list - - let all_type_names name = - name |> String.split_on_char '.' |> tails |> List.map (String.concat ".") - - let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function - | Poly _ -> [ "POLY" :: Sign.to_string sgn :: prefix ] - | Any -> - if ignore_any - then [ prefix ] - else [ "POLY" :: Sign.to_string sgn :: prefix ] - | Arrow (a, b) -> - List.rev_append - (of_typ ~ignore_any ~all_names ~prefix ~sgn:(Sign.not sgn) a) - (of_typ ~ignore_any ~all_names ~prefix ~sgn b) - | Constr (name, args) -> - name - |> (if all_names then all_type_names else fun name -> [ name ]) - |> List.map (fun name -> - let prefix = name :: Sign.to_string sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - of_typ ~ignore_any ~all_names ~prefix ~sgn arg) - args - end) - |> rev_concat - | Tuple args -> - rev_concat - @@ List.map (of_typ ~ignore_any ~all_names ~prefix ~sgn) - @@ args - | Unhandled -> [] - - (** [of_typ ~ignore_any ~prefix ~sgn t] is a representation of [t] that - encodes the polarity of the elements of the type : in [string -> int] [int] - is positive and [string] negative. - It is registered in the database and search-base type uses this to obtain - results that fit the type asked for by the user. *) - let of_typ ~ignore_any ~all_names t = - of_typ ~ignore_any ~all_names ~prefix:[] ~sgn:Pos t -end diff --git a/db/typepath.mli b/db/typepath.mli deleted file mode 100644 index 2052644ef8..0000000000 --- a/db/typepath.mli +++ /dev/null @@ -1,91 +0,0 @@ -(** This module contains the transformation that make types searchable. - -A type can viewed as a tree. [a -> b -> c * d] is the following tree : -{[ -> - |- a - |- -> - |- b - |- * - |- c - |- d -]} -To make types searchable, we consider the list of paths from root to leaf in the -tree of the type. - -Here the paths would be : [ [[-> a]; [-> -> b]; [-> -> * c ]; [-> -> * d]] ] - -There are two submodules, that each encode slightly different information from -the above. *) - -val regroup : string list list -> (string list * int) list - -module Sign : sig - type t = - | Pos - | Neg - | Unknown - - val to_string : t -> string - val not : t -> t -end - -module For_suffix_tree : sig - type t = string list list - (** [For_suffix_tree.t] is a type paths that can used to be register in a - suffix tree. This means that each path represent a text based searchable - version of the type. The chosen representation here is polarity : we do - not represent the [->] or the [*] constructors, but they affect the - "polarity" of their children. - - The polarity of a of component of a type indicate if it is produced or - consumed by the type. In the type [int -> string], [int] has negative - polarity because it is being consumed, and [string] has positive polarity - because it is being produced. - - When you have [t -> u], the polarity of [t] is inversed, and the - polarity of [u] stays the same. So when you have - - If you consider [a -> b -> c * d] with the following tree : - {[ -> - |- a - |- -> - |- b - |- * - |- c - |- d - ]} - - The [For_distance.t] associated is : [ [[- a]; [-; b]; [+; c ]; [+; d]] ] - - [babar : Lib.M.t -> Lib.R.t] - - [[-; Lib.M.t]; [+;Lib.R.t]; [-;M.t]; [-;t]; [+;R.t]; [+;t]] - *) - - val of_typ : ignore_any:bool -> all_names:bool -> Typexpr.t -> t -end - -(* module For_distance : sig - type t = string list list - (** [For_distance.t] is a type paths that can used to compute the distance - between two types. It is much more precise than {!For_suffix.t}, we do not - lose any information about the type. Because of this, we represent [->] - and [*] add annotations to indicate the child's position relative to its - parent (first child or second child ?) - - If you consider [a -> b -> c * d] with the following tree : - {[ -> - |- a - |- -> - |- b - |- * - |- c - |- d - ]} - - The [For_distance.t] associated is : [ [[-> 1 a]; [-> 2 -> 1 b]; [-> 2 -> 2 - * 1 c ]; [-> 2 -> 2 * 2 d]] ] - *) - - val of_typ : ignore_any:bool -> Typexpr.t -> t -end *) diff --git a/index/load_doc.ml b/index/load_doc.ml index 7cc10d16eb..b71c40aeeb 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -1,4 +1,4 @@ -module Elt = Db.Elt +module Entry = Db.Entry module Db_common = Db module ModuleName = Odoc_model.Names.ModuleName @@ -11,7 +11,7 @@ let generic_cost ~ignore_no_doc name has_doc = + (if ignore_no_doc || has_doc then 0 else 30) + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 -let kind_cost (kind : Elt.Kind.t) = +let kind_cost (kind : Entry.Kind.t) = match kind with | Constructor typ | Field typ | Val typ -> Db.Typexpr.size typ | Doc -> 400 @@ -23,7 +23,7 @@ let kind_cost (kind : Elt.Kind.t) = let cost ~name ~kind ~doc_html = let ignore_no_doc = match kind with - | Elt.Kind.Module | ModuleType -> true + | Entry.Kind.Module | ModuleType -> true | _ -> false in let has_doc = doc_html <> "" in @@ -111,25 +111,25 @@ let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = let open Odoc_search.Entry in match kind with | TypeDecl _ -> - Elt.Kind.TypeDecl (Odoc_search.Html.typedecl_params_of_entry entry) - | Module -> Elt.Kind.Module + Entry.Kind.TypeDecl (Odoc_search.Html.typedecl_params_of_entry entry) + | Module -> Entry.Kind.Module | Value { value = _; type_ } -> let typ = typ_of_odoc_typ type_ in - Elt.Kind.val_ typ + Entry.Kind.val_ typ | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in let typ = typ_of_odoc_typ searchable_type in - Elt.Kind.constructor typ + Entry.Kind.constructor typ | Field { mutable_ = _; parent_type; type_ } -> let typ = type_ |> searchable_type_of_record parent_type |> typ_of_odoc_typ in - Elt.Kind.field typ + Entry.Kind.field typ | Doc _ -> Doc | Exception { args; res } -> let searchable_type = searchable_type_of_constructor args res in let typ = typ_of_odoc_typ searchable_type in - Elt.Kind.exception_ typ + Entry.Kind.exception_ typ | Class_type _ -> Class_type | Method _ -> Method | Class _ -> Class @@ -137,15 +137,15 @@ let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = | ExtensionConstructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in let typ = typ_of_odoc_typ searchable_type in - Elt.Kind.extension_constructor typ + Entry.Kind.extension_constructor typ | ModuleType -> ModuleType let register_type_expr ~db elt type_ = - let type_paths = + let type_polarities = type_ |> typ_of_odoc_typ - |> Db.Typepath.For_suffix_tree.of_typ ~ignore_any:false ~all_names:true + |> Db.Type_polarity.of_typ ~ignore_any:false ~all_names:true in - Db.store_type_paths db elt type_paths + Db.store_type_polarities db elt type_polarities let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.kind) = let open Odoc_search.Entry in @@ -199,6 +199,7 @@ let prefixname n = let register_entry ~db ~index_name ~type_search ~index_docstring (Odoc_search.Entry.{ id; doc; kind } as entry) = + let module Sherlodoc_entry = Entry in let open Odoc_search in let open Odoc_search.Entry in let is_type_extension = @@ -230,7 +231,8 @@ let register_entry ~db ~index_name ~type_search ~index_docstring let url = Result.get_ok url in let is_from_module_type = is_from_module_type entry in let elt = - Elt.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url ~is_from_module_type () + Sherlodoc_entry.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url + ~is_from_module_type () in if index_docstring then register_doc ~db elt doc_txt ; (if index_name diff --git a/index/typename.mli b/index/typename.mli index a2492e4351..c6410ce6ad 100644 --- a/index/typename.mli +++ b/index/typename.mli @@ -1,6 +1,5 @@ +val to_string : Odoc_model.Paths.Path.Type.t -> string (** [Typename.string tn] is a string representing the type name of [tn] as a string. Such a function could be provided by Odoc but we do two things differently : - Core types like [int] and [string] are represented as [Stdlib.int] or [Stdlib.string] - We do not use any parenthesis on functors. *) -val to_string : - Odoc_model.Paths.Path.Type.t -> string diff --git a/jsoo/main.ml b/jsoo/main.ml index 52571d14ba..012c8add35 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -78,10 +78,10 @@ let db = |> Fut.map Storage_js.load let string_of_kind = - let open Db.Elt.Kind in + let open Db.Entry.Kind in let open Odoc_html_frontend in function - | Db.Elt.Kind.Doc -> kind_doc + | Db.Entry.Kind.Doc -> kind_doc | TypeDecl _ -> kind_typedecl | Module -> kind_module | Exception _ -> kind_exception @@ -104,15 +104,15 @@ let search message db = let _ = Jv.(apply (get global "postMessage")) [| Jv.of_list - (fun Db.Elt.{ name; rhs; doc_html; kind; url; _ } -> + (fun Db.Entry.{ name; rhs; doc_html; kind; url; _ } -> let typedecl_params = match kind with - | Db.Elt.Kind.TypeDecl args -> args + | Db.Entry.Kind.TypeDecl args -> args | _ -> None in let prefix_name, name = match kind with - | Db.Elt.Kind.Doc -> None, None + | Db.Entry.Kind.Doc -> None, None | _ -> let rev_name = name |> String.split_on_char '.' |> List.rev diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 57e47eb61b..0926825db8 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -1,4 +1,4 @@ -module Elt = Db.Elt +module Entry = Db.Entry module Reasoning = struct module Name_match = struct @@ -42,9 +42,9 @@ module Reasoning = struct else (* Matches only in the docstring are always worse *) Doc let with_words query_words elt = - match elt.Elt.kind with - | Elt.Kind.Doc -> List.map (fun _ : t -> Doc) query_words - | _ -> List.map (fun word -> with_word word elt.Elt.name) query_words + match elt.Entry.kind with + | Entry.Kind.Doc -> List.map (fun _ : t -> Doc) query_words + | _ -> List.map (fun word -> with_word word elt.Entry.name) query_words let compare nm nm' = let to_int nm = @@ -88,11 +88,11 @@ module Reasoning = struct } let type_distance query_type elt = - let open Elt in + let open Entry in match query_type, elt.kind with | None, _ -> None | ( Some query_type - , Elt.Kind.( + , Entry.Kind.( ( ExtensionConstructor eltype | Constructor eltype | Field eltype @@ -107,7 +107,7 @@ module Reasoning = struct let type_in_query query_type = Option.is_some query_type let type_in_elt elt = - let open Elt in + let open Entry in match elt.kind with | ExtensionConstructor _ | Constructor _ | Field _ | Val _ | Exception _ -> true @@ -116,31 +116,31 @@ module Reasoning = struct false let is_stdlib elt = - let open Elt in + let open Entry in String.starts_with ~prefix:"Stdlib." elt.name let kind elt = - match elt.Elt.kind with - | Elt.Kind.Doc -> Doc - | Elt.Kind.TypeDecl _ -> TypeDecl - | Elt.Kind.Module -> Module - | Elt.Kind.Exception _ -> Exception - | Elt.Kind.Class_type -> Class_type - | Elt.Kind.Method -> Method - | Elt.Kind.Class -> Class - | Elt.Kind.TypeExtension -> TypeExtension - | Elt.Kind.ExtensionConstructor _ -> ExtensionConstructor - | Elt.Kind.ModuleType -> ModuleType - | Elt.Kind.Constructor _ -> Constructor - | Elt.Kind.Field _ -> Field - | Elt.Kind.Val _ -> Val - - let name_length elt = String.length elt.Elt.name - let is_from_module_type elt = elt.Elt.is_from_module_type + match elt.Entry.kind with + | Entry.Kind.Doc -> Doc + | Entry.Kind.TypeDecl _ -> TypeDecl + | Entry.Kind.Module -> Module + | Entry.Kind.Exception _ -> Exception + | Entry.Kind.Class_type -> Class_type + | Entry.Kind.Method -> Method + | Entry.Kind.Class -> Class + | Entry.Kind.TypeExtension -> TypeExtension + | Entry.Kind.ExtensionConstructor _ -> ExtensionConstructor + | Entry.Kind.ModuleType -> ModuleType + | Entry.Kind.Constructor _ -> Constructor + | Entry.Kind.Field _ -> Field + | Entry.Kind.Val _ -> Val + + let name_length elt = String.length elt.Entry.name + let is_from_module_type elt = elt.Entry.is_from_module_type let v query_words query_type elt = let is_stdlib = is_stdlib elt in - let has_doc = elt.Elt.doc_html <> "" in + let has_doc = elt.Entry.doc_html <> "" in let name_matches = Name_match.with_words query_words elt in let kind = kind elt in let type_distance = type_distance query_type elt in @@ -223,8 +223,7 @@ module Reasoning = struct then (* If query request a type, elements which do not have one should never appear. *) - (* assert false *) - 0 + assert false else 0 in let is_from_module_type_cost = if is_from_module_type then 400 else 0 in @@ -236,4 +235,4 @@ module Reasoning = struct end let elt ~query_name ~query_type elt = - Elt.{ elt with score = Reasoning.score ~query_name ~query_type elt } + Entry.{ elt with score = Reasoning.score ~query_name ~query_type elt } diff --git a/query/query.ml b/query/query.ml index 218b71516c..842d8dd541 100644 --- a/query/query.ml +++ b/query/query.ml @@ -30,11 +30,10 @@ let find_types ~shards names = Succ.inter_of_list @@ List.map (fun (name, count) -> - let name' = String.concat "" name in - match Tree_occ.find db name' with + match Tree_occ.find db name with | Some trie -> collapse_trie_occ ~count trie | None -> Succ.empty) - (Db.Typepath.regroup names) + names in Succ.union acc r) Succ.empty shards @@ -69,11 +68,10 @@ let search ~(shards : Db.t list) query_name query_typ = | [], Some query_typ -> find_types ~shards query_typ | _ :: _, Some query_typ -> let results_name = find_names ~shards query_name in - let results_typ = find_types ~shards query_typ in Succ.inter results_name results_typ -let match_packages ~packages { Db.Elt.pkg; _ } = +let match_packages ~packages { Db.Entry.pkg; _ } = match pkg with | Some { name; version = _ } -> List.exists (String.equal name) packages | None -> false @@ -88,7 +86,7 @@ let api ~(shards : Db.t list) ?(dynamic_sort = true) params = Parser.of_string params.query in let results = search ~shards query_name query_typ in - let results = Succ.to_seq ~compare:Db.Elt.compare results in + let results = Succ.to_seq ~compare:Db.Entry.compare results in let results = match_packages ~packages:params.packages results in let results = List.of_seq @@ Seq.take params.limit results in let results = @@ -99,6 +97,6 @@ let api ~(shards : Db.t list) ?(dynamic_sort = true) params = results else results in - let results = List.sort Db.Elt.compare results in + let results = List.sort Db.Entry.compare results in pretty, results diff --git a/query/query.mli b/query/query.mli index 268719cd66..d147de849c 100644 --- a/query/query.mli +++ b/query/query.mli @@ -4,7 +4,8 @@ type t = ; limit : int } -val api : shards:Db.t list -> ?dynamic_sort:bool -> t -> string * Db.Elt.t list +val api : + shards:Db.t list -> ?dynamic_sort:bool -> t -> string * Db.Entry.t list (** [api ~shard ~dynamic_sort {query; packages; limit}] returns [(pretty_query, results)] where [pretty_query] is a re-printed version of [query] and [results] is the list of results corresponding to the query and the diff --git a/query/query_parser.ml b/query/query_parser.ml index 93983a346f..c555c81509 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -1,11 +1,5 @@ -type t = string list - let parse str = Parser.main Lexer.token (Lexing.from_string str) -let alphanum = function - | 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '\'' -> true - | _ -> false - let naive_of_string str = List.filter (fun s -> String.length s > 0) (String.split_on_char ' ' str) @@ -21,19 +15,18 @@ let of_string str = | _ when guess_type_search str -> true, "", str | _ -> false, str, "" in - let pretty_typ, query_typ, paths_typ = + let pretty_typ, type_polarities, typ = match parse str_typ with | Any -> "_", [], None | typ -> ( Db.Typexpr.show typ , List.filter - (fun s -> List.length s > 0) - (Db.Typepath.For_suffix_tree.of_typ ~ignore_any:true - ~all_names:false typ) + (fun (word, _count) -> String.length word > 0) + (Db.Type_polarity.of_typ ~ignore_any:true ~all_names:false typ) , Some typ ) | exception _ -> "", [], None in let query_name = naive_of_string str_name in - let query_typ = if has_typ then Some query_typ else None in + let type_polarities = if has_typ then Some type_polarities else None in let pretty_query = String.concat " " query_name ^ " : " ^ pretty_typ in - query_name, query_typ, paths_typ, pretty_query + query_name, type_polarities, typ, pretty_query diff --git a/query/query_parser.mli b/query/query_parser.mli new file mode 100644 index 0000000000..f046173d8a --- /dev/null +++ b/query/query_parser.mli @@ -0,0 +1,3 @@ +val of_string : + string + -> string list * Db.Type_polarity.t list option * Db.Typexpr.t option * string diff --git a/query/type_distance.ml b/query/type_distance.ml index ef84627919..273b0d05af 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -1,5 +1,39 @@ -module Type_path = struct - module Sign = Db.Typepath.Sign +module Type_path : sig + (** This module contains the transformation that make it possible to compute the + distance between types.. + +A type can viewed as a tree. [a -> b -> c * d] is the following tree : +{[ -> + |- a + |- -> + |- b + |- * + |- c + |- d +]} +We consider the list of paths from root to leaf in the tree of the type. + +Here the paths would be : [ [[-> a]; [-> -> b]; [-> -> * c ]; [-> -> * d]] ] + +We encode slightly more information than that. In the above, it not possible by +looking at a type path to know the child position relative to its parent : In +the path [[-> a]]; [a] is the first child of [->], and in [[-> -> b]]; [[-> b]] +is the second child of [->]. This information is not possible to recover without +the whole tree, so we add it in the list, ass a number after the arrow. + +This makes the type path of the example type look like this : + +{[ [[-> 1 a]; [-> 2 -> 1 b]; [-> 2 -> 2 * 1 c ]; [-> 2 -> 2 * 2 d]] ]} +*) + + type t = string list list + + val of_typ : ignore_any:bool -> Db.Typexpr.t -> t + (* [of_typ ~ignore_any typ] is the list of type path associated to [typ]. + If [ignore_any] is true, [Any] constructors in [typ] will be ignored, + if it is false, they will be treated like a polymorphic variable. *) +end = struct + module Sign = Db.Type_polarity.Sign type t = string list list @@ -164,11 +198,6 @@ let minimize = function let _ = go (Array.length used) 0 0 in !best -let length typ = - typ - |> Type_path.of_typ ~ignore_any:false - |> List.concat |> List.map String.length |> List.fold_left ( + ) 0 - let v ~query ~element = let query_paths = Type_path.of_typ ~ignore_any:false query in let element_paths = Type_path.of_typ ~ignore_any:false element in diff --git a/query/type_distance.mli b/query/type_distance.mli new file mode 100644 index 0000000000..49cf1bca7d --- /dev/null +++ b/query/type_distance.mli @@ -0,0 +1 @@ +val v : query:Db.Typexpr.t -> element:Db.Typexpr.t -> int diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 8a64ddd3e8..876bd4e1cf 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,9 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.154s - user 0m1.110s - sys 0m0.041s + real 0m1.236s + user 0m1.181s + sys 0m0.050s @@ -44,8 +44,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2560 db.js - 1932 db.js.gz + 2576 db.js + 1944 db.js.gz 1544 megaodocl.gz @@ -56,7 +56,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cp db.js html/ $ cp ../../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 5.1M html/sherlodoc.js + 5.2M html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/cli.t/main.mli b/test/cram/cli.t/main.mli index 069546a5fb..9c483d7021 100644 --- a/test/cram/cli.t/main.mli +++ b/test/cram/cli.t/main.mli @@ -68,7 +68,10 @@ type extensible_type += MyExtension of moo type exn_payload -exception Implicit_exn of exn_payload +exception Implicit_exn of exn_payload exception Explicit_exn : exn_payload -> exn type exn += Very_explicit_exn : exn_payload -> exn +type long_name_type + +val long_name_value : long_name_type \ No newline at end of file diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index c1c775faa4..3853c3983a 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -84,11 +84,13 @@ doc $ sherlodoc "qwertyuiopasdfghjklzxcvbnm" [No results] -TODO : get a result for the query bellow $ sherlodoc "hidden" [No results] +TODO : get a result for the query bellow $ sherlodoc ":mo" - [No results] + val Main.value : moo + val Main.produce : unit -> moo + val Main.produce_2' : unit -> unit -> moo $ sherlodoc ":'a" val Main.poly_1 : 'a -> 'b -> 'c val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c @@ -106,7 +108,7 @@ TODO : get a result for the query bellow val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t TODO : get a result for the query bellow $ sherlodoc ": 'a bo" - [No results] + val Main.poly_param : 'a boo $ sherlodoc ":extensible_type" cons Main.MyExtension : moo -> extensible_type $ sherlodoc ":exn" @@ -117,3 +119,10 @@ TODO : get a result for the query bellow exn Main.Explicit_exn : exn_payload -> exn exn Main.Implicit_exn : exn_payload -> exn cons Main.Very_explicit_exn : exn_payload -> exn + $ sherlodoc ": long_name_type" + val Main.long_name_value : long_name_type + $ sherlodoc ": long_nam" + val Main.long_name_value : long_name_type + $ sherlodoc "long_name" + type Main.long_name_type + val Main.long_name_value : long_name_type diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index d5f7b7fd64..abc22f06df 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 5.1M sherlodoc.js + 5.2M sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html diff --git a/www/ui.ml b/www/ui.ml index d6954e4185..7753e9e102 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -5,13 +5,13 @@ let list_of_option = function | Some x -> [ x ] let render_link elt = - let open Db.Elt in + let open Db.Entry in match link elt with | Some link -> [ a_href link ] | None -> [] let string_of_kind = - let open Db.Elt.Kind in + let open Db.Entry.Kind in function | Doc -> "doc" | TypeDecl _ -> "type" @@ -28,7 +28,7 @@ let string_of_kind = | Val _ -> "val" let render_elt elt = - let open Db.Elt in + let open Db.Entry in let link = render_link elt in let html_txt = Unsafe.data in let rhs = @@ -40,7 +40,7 @@ let render_elt elt = [ txt kind; a ~a:link [ em [ txt elt.name ] ] ] @ rhs let render_pkg elt = - let open Db.Elt in + let open Db.Entry in match elt.pkg with | Some { name; version } -> let link = elt |> pkg_link |> Option.get in @@ -57,7 +57,7 @@ let render_pkg elt = | None -> [] let render_result elt = - let open Db.Elt in + let open Db.Entry in render_pkg elt @ [ pre (render_elt elt); Unsafe.data elt.doc_html ] let render ~pretty results = From 7344ec76af12b314421bd43c7e43f926a5f065bf Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 15 Dec 2023 15:33:56 +0100 Subject: [PATCH 187/285] score to cost refactoring --- cli/main.ml | 6 +++--- db/entry.ml | 8 ++++---- index/load_doc.ml | 4 ++-- query/dynamic_cost.ml | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index 952494829c..3fa17fd30c 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -26,12 +26,12 @@ let print_result ~print_cost ~no_rhs ; rhs ; url = _ ; kind - ; score + ; cost ; doc_html = _ ; pkg = _ ; is_from_module_type = _ } = - let score = if print_cost then string_of_int score ^ " " else "" in + let cost = if print_cost then string_of_int cost ^ " " else "" in let typedecl_params = (match kind with | Db.Entry.Kind.TypeDecl args -> args @@ -46,7 +46,7 @@ let print_result ~print_cost ~no_rhs | Some _ when no_rhs -> () | Some rhs -> Format.fprintf h "%s" (Unescape.string rhs) in - Format.printf "%s%s %s%s%a\n" score kind typedecl_params name pp_rhs rhs + Format.printf "%s%s %s%s%a\n" cost kind typedecl_params name pp_rhs rhs let search ~print_cost ~static_sort ~limit ~db ~no_rhs query = match diff --git a/db/entry.ml b/db/entry.ml index 2fc59f5e74..9d05f20a64 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -54,7 +54,7 @@ module T = struct ; rhs : string option ; url : string ; kind : Kind.t - ; score : int + ; cost : int ; doc_html : string ; pkg : Package.t option ; is_from_module_type : bool @@ -86,7 +86,7 @@ module T = struct if a == b then 0 else - let cmp = Int.compare a.score b.score in + let cmp = Int.compare a.cost b.cost in if cmp = 0 then structural_compare a b else cmp end @@ -128,6 +128,6 @@ let link t = in Some (pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name) -let v ~name ~kind ~score ~rhs ~doc_html ~url ~is_from_module_type ?(pkg = None) +let v ~name ~kind ~cost ~rhs ~doc_html ~url ~is_from_module_type ?(pkg = None) () = - { name; kind; url; score; doc_html; pkg; rhs; is_from_module_type } + { name; kind; url; cost; doc_html; pkg; rhs; is_from_module_type } diff --git a/index/load_doc.ml b/index/load_doc.ml index b71c40aeeb..d71a456086 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -225,13 +225,13 @@ let register_entry ~db ~index_name ~type_search ~index_docstring | Doc _ -> prefixname id | _ -> full_name in - let score = cost ~name ~kind:kind' ~doc_html in + let cost = cost ~name ~kind:kind' ~doc_html in let rhs = Html.rhs_of_kind kind in let url = Html.url id in let url = Result.get_ok url in let is_from_module_type = is_from_module_type entry in let elt = - Sherlodoc_entry.v ~name ~kind:kind' ~rhs ~doc_html ~score ~url + Sherlodoc_entry.v ~name ~kind:kind' ~rhs ~doc_html ~cost ~url ~is_from_module_type () in if index_docstring then register_doc ~db elt doc_txt ; diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 0926825db8..d01cfd1460 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -235,4 +235,4 @@ module Reasoning = struct end let elt ~query_name ~query_type elt = - Entry.{ elt with score = Reasoning.score ~query_name ~query_type elt } + Entry.{ elt with cost = Reasoning.score ~query_name ~query_type elt } From 5d1af003740b74c38f9f16fe9bd00533ed7d9dec Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 15 Dec 2023 15:34:51 +0100 Subject: [PATCH 188/285] opam deps : search odoc --- dune-project | 3 ++- sherlodoc.opam | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dune-project b/dune-project index 1598be2f51..37dffb80be 100644 --- a/dune-project +++ b/dune-project @@ -34,7 +34,8 @@ (>= 5.7.0)) (fpath (>= 0.7.3)) - odoc + (odoc + (>= 2.4.0)) (opam-core (>= 2.1.5)) (tyxml diff --git a/sherlodoc.opam b/sherlodoc.opam index 249e756518..b09cfb2205 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -14,7 +14,7 @@ depends: [ "base64" {>= "3.5.1"} "lwt" {>= "5.7.0"} "fpath" {>= "0.7.3"} - "odoc" + "odoc" {>= "2.4.0"} "opam-core" {>= "2.1.5"} "tyxml" {>= "4.6.0"} "brr" {>= "0.0.6"} From 9398d01f5030334a6884ff3b7007849a6a51683d Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Fri, 15 Dec 2023 15:36:39 +0100 Subject: [PATCH 189/285] installation instruction in readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index c35f081954..ce6b66f11e 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,12 @@ and record fields. # Usage +First, install sherlodoc : + +```bash +opam install sherlodoc +``` + ## Generating a search-database The first step to using sherlodoc is generating a search-database. You do this From 30e1fe727bec3cc4efb714a0a742160d8b4cc74a Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 18 Dec 2023 12:53:00 +0100 Subject: [PATCH 190/285] bugfixes, and changes --- db/db.ml | 3 +- db/db.mli | 26 ++-- db/entry.ml | 9 +- db/entry.mli | 82 +++++++++++++ db/occ.mli | 52 +++++++- db/type_polarity.ml | 12 +- db/type_polarity.mli | 72 +++++++---- index/load_doc.ml | 1 + index/load_doc.mli | 3 + query/dynamic_cost.ml | 215 ++++++++++++++------------------- query/parser.mly | 3 +- query/query.ml | 6 +- query/query_parser.ml | 11 +- query/type_distance.ml | 8 +- query/type_distance.mli | 6 +- review.md | 22 ++-- test/cram/base.t/run.t | 65 ++++++++-- test/cram/cli_small.t/main.mli | 9 ++ test/cram/cli_small.t/run.t | 5 + 19 files changed, 406 insertions(+), 204 deletions(-) create mode 100644 db/entry.mli diff --git a/db/db.ml b/db/db.ml index cb8400a2ed..d565c1d1e3 100644 --- a/db/db.ml +++ b/db/db.ml @@ -28,7 +28,8 @@ let store db name elt ~count = Suffix_tree.With_occ.add_suffixes db.writer_types name (count, elt) let store_type_polarities db elt polarities = - List.iter (fun (word, count) -> store db ~count word elt) polarities + List.iter (fun (word, count) -> + store db ~count word elt) polarities let store_word db word elt = Suffix_tree.With_elts.add_suffixes db.writer_names word elt diff --git a/db/db.mli b/db/db.mli index 05bf120619..0f6bfaf7ed 100644 --- a/db/db.mli +++ b/db/db.mli @@ -9,18 +9,26 @@ type t = Db_typedef.t = { db_names : Suffix_tree.With_elts.reader ; db_types : Suffix_tree.With_occ.reader } -(** The type of a database. - [db_names] is for text-based part of the query and [db_types] for the - type-based part. - [db_types] has [Entry.t array Int_map.t] ([Occ.t]) as a payload because we want - the query [blabla : int -> int -> _] to return only entries that take at - least two ints as arguments, an entry of type [int -> string] is invalid. - The int_map map a number of occurences to a set of entries. - *) +(** The type of a search database. + +[db_names] is for text-based part of the query and [db_types] for the +type-based part. + +[db_types] has [Entry.t array Int_map.t] ([Occ.t]) as a payload because we want +the query [blabla : int -> int -> _] to return only entries that take at +least two ints as arguments, an entry of type [int -> string] is invalid. +The [Int_map.t] maps a number of occurences to a set of entries. See {!Occ}. +[db_types] still is a suffix tree, so you can search in it only for text. The +way we transform types into searchable text is in {!Type_polarity}. +*) type writer +(** The type that builds a database. You can use it to add things to it, but + you cannot make queries on it. *) val make : unit -> writer -val export : writer -> t +(** [make ()] returns an empty search database. *) + val store_type_polarities : writer -> Entry.t -> Type_polarity.t list -> unit val store_word : writer -> string -> Entry.t -> unit +val export : writer -> t diff --git a/db/entry.ml b/db/entry.ml index 9d05f20a64..9da9340dca 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -41,13 +41,6 @@ module Package = struct let v ~name ~version = { name; version } end -type package = Package.t = - { name : string - ; version : string - } - -type kind = Kind.t - module T = struct type t = { name : string @@ -60,7 +53,7 @@ module T = struct ; is_from_module_type : bool } - let compare_pkg { name; version = _ } (b : package) = + let compare_pkg Package.{ name; version = _ } (b : Package.t) = String.compare name b.name let structural_compare a b = diff --git a/db/entry.mli b/db/entry.mli new file mode 100644 index 0000000000..38fdaa4a6e --- /dev/null +++ b/db/entry.mli @@ -0,0 +1,82 @@ +module Kind : sig + type 'a abstract = + | Doc + | TypeDecl of string option + | Module + | Exception of 'a + | Class_type + | Method + | Class + | TypeExtension + | ExtensionConstructor of 'a + | ModuleType + | Constructor of 'a + | Field of 'a + | Val of 'a + + type t = Typexpr.t abstract + + val equal : 'a -> 'a -> bool + val doc : 'a abstract + val type_decl : string option -> 'a abstract + val module_ : 'a abstract + val exception_ : 'a -> 'a abstract + val class_type : 'a abstract + val method_ : 'a abstract + val class_ : 'a abstract + val type_extension : 'a abstract + val extension_constructor : 'a -> 'a abstract + val module_type : 'a abstract + val constructor : 'a -> 'a abstract + val field : 'a -> 'a abstract + val val_ : 'a -> 'a abstract +end + +module Package : sig + type t = + { name : string + ; version : string + } + + val v : name:string -> version:string -> t +end + +type t = + { name : string + ; rhs : string option + ; url : string + ; kind : Kind.t + ; cost : int + ; doc_html : string + ; pkg : Package.t option + ; is_from_module_type : bool + } + +val compare : t -> t -> int +val equal : t -> t -> bool + +module Set : Set.S with type elt = t + +module Array : sig + type elt = t + type nonrec t = t array + + val is_empty : t -> bool + val of_list : elt list -> t + val equal_elt : elt -> elt -> bool +end + +val pkg_link : t -> string option +val link : t -> string option + +val v : + name:string + -> kind:Kind.t + -> cost:int + -> rhs:string option + -> doc_html:string + -> url:string + -> is_from_module_type:bool + -> ?pkg:Package.t option + -> unit + -> t diff --git a/db/occ.mli b/db/occ.mli index 57f68de1d1..7b4f2d0f6f 100644 --- a/db/occ.mli +++ b/db/occ.mli @@ -3,12 +3,58 @@ The list [[a, a, b, b, c]] would correspond to [[(2, [a; b]); (1, [c]) ]]. It is used or type search : you want to be able to return every function that takes -two ints as an argument. Without this datastrucure, we would only to search for -functions that take ints, without specifying the amount. +two ints as an argument. Without this datastrucure, we would only be able to +search for functions that take ints, without specifying the amount. This datastructure is used at the leafs of the suffix tree : so when doing type search, we first perform a type search ignoring occurences, and afterwards -filter the results according to them. *) +filter the results according to them. + +I will give an example bellow, it is probably better to read {!Type_polarities} +first to understand it completely. + +If you have the following entries : + +{[ +val a : string -> int +val b : string -> string -> int +val c : string -> string -> (int * int) +val d : (string * string) -> float -> (int * int) + +]} + +Their polarities will be : + +{[ +val a : {(-string, 1); (+int, 1)} +val b : {(-string, 2); (+int, 1)} +val c : {(-string, 2); (+int, 2)} +val d : {(-string, 2); (+int, 2); (-float, 1)} +]} + +We can combine them into a database that will look like this : + +{[ ++int -> + { 1 -> {a; b} + 2 -> {c; d} + } +-string -> + { 1 -> {a} + 2 -> {b; c; d} + } +-float -> + { 1 -> {d} + } +]} + +If there is a query for type [string -> string -> (int * int)], the polarities +of the query are [(-string, 2)], [(+int, 2)]. + +The entries of [(-string, 2)] are [{b; c; d}], and the entries of [(+int, 2)] +are [{c; d}]. The intersection of the two is [{c; d}]. + +*) type t type elt = int * Entry.t diff --git a/db/type_polarity.ml b/db/type_polarity.ml index 465af86864..c2fba16478 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -35,16 +35,19 @@ let all_type_names name = name |> String.split_on_char '.' |> tails |> List.map (String.concat ".") let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function - | Poly _ -> [ "POLY" :: Sign.to_string sgn :: prefix ] + | Poly _ -> [ Sign.to_string sgn :: "POLY" :: prefix ] | Any -> if ignore_any - then [ prefix ] - else [ "POLY" :: Sign.to_string sgn :: prefix ] + then ( + + [ prefix ]) + else [ Sign.to_string sgn :: "POLY" :: prefix ] | Arrow (a, b) -> List.rev_append (of_typ ~ignore_any ~all_names ~prefix ~sgn:(Sign.not sgn) a) (of_typ ~ignore_any ~all_names ~prefix ~sgn b) | Constr (name, args) -> + name |> (if all_names then all_type_names else fun name -> [ name ]) |> List.map (fun name -> @@ -65,7 +68,8 @@ let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function rev_concat @@ List.map (of_typ ~ignore_any ~all_names ~prefix ~sgn) @@ args - | Unhandled -> [] + | Unhandled -> + [] (** [of_typ ~ignore_any ~prefix ~sgn t] is a representation of [t] that encodes the polarity of the elements of the type : in [string -> int] [int] diff --git a/db/type_polarity.mli b/db/type_polarity.mli index 9cfae1a306..90e7ba90af 100644 --- a/db/type_polarity.mli +++ b/db/type_polarity.mli @@ -1,37 +1,50 @@ (** This module provide a way to transform a type into strings, in such a way - that the string can be used for type search. + that the strings can be used for type search. The chosen representation is polarity : we do not represent the [->] or the [*] -constructors, but they affect the "polarity" of their children. +constructors, but instead compute the "polarity" of every type name/constructor +like [int] or ['a] that is part of the whole type expression. -The polarity of a component of a type indicate if it is produced or consumed by +The polarity of a component of a type indicates if it is produced or consumed by the type. In the type [int -> string], [int] has negative polarity because it is being consumed, and [string] has positive polarity because it is being produced. - -When you have [t -> u], the polarity of [t] is inversed, and the polarity of [u] -stays the same. So in the type [(int -> string) -> float], the polarities are -[+int], [-string] and [+float]. This is easier to see if you write the type with -an infix notation for the arrow : [-> (-> int string) float]. +We say that the polarities of [int -> string] are [-int] and [+string]. Once you have computed the polarities of the type of an entry [e], you can -register each polarity as corresponding to [e] in the search database. Then, -when the user queries for a type, we compute the polarities of the query type, a -search in a database for every polarity. +register each polarity as corresponding to [e] in the search database. + +Then, when the user queries for a type, we compute the polarities of the query +type, and search for the entries. The -We then return the result corresponding to intersection of each polarity : if -the user queries for [int -> string], we want to have every entry which consumes -an [int] and produces a [string], that is the intersection of the entries +We then return the result corresponding to intersection of each polarity: if the +user queries for [int -> string], we want to have every entry which consumes an +[int] and produces a [string], that is the intersection of the entries associated to [-int] with the entries associated to [+string]. +How is polarity computed exactly ? When you have [t -> u], the polarity of [t] +is inversed, and the polarity of [u] stays the same. A good example of this is +the type of {!Stdlib.Out_channel.with_open_gen} : + +{| val with_open_gen : open_flag list -> int -> string -> (t -> 'a) -> 'a |} + +Here the polarities are [-open_flag list], [-int], [-string], [+Out_channel.t], +[-'a] and [+'a]. The fact that we have [+Out_channel.t] might be puzzling at +first, because an [Out_channel.t] is not returned by the function, but +{!Stdlib.Out_channel.with_open_gen} is indeed one of the possible ways to create +an [Out_channel.t]. + There is however a complication. If the user queries for [int -> int -> string], then the polarities will be [-int], [-int] and [+string]. An entry of type [int -> string] would be included in the intersection of these polarities. But the -user explicitely asked for two integer to be consumed. To fix this issue, we +user explicitely asked for two integers to be consumed. To fix this issue, we track the number of occurences of each polarity. -The polarities for [int -> int -> string], become [("-int", 2)] and [("+string", +The polarities for [int -> int -> string], become [(-int, 2)] and [(+string, 1)], and allows us to filter entries according to this information. The exact mechanism for this is explained in {!Occ}. + +There is a mechanism for types with parameters like ['a list]. I might explain +it in the future. *) module Sign : sig @@ -44,17 +57,32 @@ module Sign : sig end type t = string * int +(** The search database is a suffix tree structure, implemented in + {!Suffix_tree}. It is a solely text-based datastructure. Therefore, we need + a text represention for the polarities. + + The polarity [+t] is represented by ["+t"], and the polarity [-t] is + represented by ["-t"]. + + The fact that the sign is in the front is important : ["+flo"] is a prefix of + ["+float"], but ["flo+"] is not a prefix nor a suffix of ["float+"]. This + allows to answer incomplete queries. + + The integer represents the occurences of the polarity, as explained in the + toplevel documentation of the module. +*) val of_typ : ignore_any:bool -> all_names:bool -> Typexpr.t -> t list (** [of_typ ~ignore_any ~all_names typ] is the list of polarised types corresponding to [typ]. - - If [ignore_any] is true, the type [_] will be ignored, if it is true, it - will be treated like a type variable ['a]. + - If [ignore_any] is true, the type [_] will be ignored, otherwise it will be + treated like a type variable ['a]. - If [all_names] is true, extra polarities are added for every "possible name" - of each type. For instance the possible names of [Stdlib.Int64.t] are ["t"], - ["Int64.t"] and ["Stdlib.Int64.t"]. This allows for the user to use any of - the possible name. It is important to set this when registering entries in - the database, but you not need it when computing the polarities of a query. + of each type constructor. For instance the possible names of + [Stdlib.Int64.t] are ["t"], ["Int64.t"] and ["Stdlib.Int64.t"]. This allows + for the user to use any of the possible name. It is important to set this + when registering entries in the database, but you not need it when computing + the polarities of a query. *) diff --git a/index/load_doc.ml b/index/load_doc.ml index d71a456086..7a0a02c489 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -56,6 +56,7 @@ let rec typ_of_odoc_typ otyp = arrow (typ_of_odoc_typ left) (typ_of_odoc_typ right) | Constr (name, args) -> constr (Typename.to_string name) (List.map typ_of_odoc_typ args) + | Tuple li -> tuple (List.map typ_of_odoc_typ li) | _ -> unhandled let with_tokenizer str fn = diff --git a/index/load_doc.mli b/index/load_doc.mli index 168ccc5edf..280ac220ed 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -1,3 +1,6 @@ + +(** [register_entry ~db ~index_name ~type_search ~index_docstring e] register + the entry [e] in [db]. *) val register_entry : db:Db.writer -> index_name:bool diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index d01cfd1460..6b421bcae5 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -1,7 +1,13 @@ module Entry = Db.Entry module Reasoning = struct + (** The [Reasoning] module contains a representation that include every reason + for which a search entry would be ranked higher or lower. It does not + decide which reason is more important. *) + module Name_match = struct + (** [Name_match.t] represents how good of a match there is between the query + and the name of an entry. *) type t = | DotSuffix | PrefixSuffix @@ -41,25 +47,13 @@ module Reasoning = struct then Lowercase else (* Matches only in the docstring are always worse *) Doc - let with_words query_words elt = - match elt.Entry.kind with + let with_words query_words entry = + match entry.Entry.kind with | Entry.Kind.Doc -> List.map (fun _ : t -> Doc) query_words - | _ -> List.map (fun word -> with_word word elt.Entry.name) query_words - - let compare nm nm' = - let to_int nm = - match nm with - | DotSuffix -> 0 - | PrefixSuffix -> 1 - | SubDot -> 2 - | SubUnderscore -> 3 - | Sub -> 4 - | Lowercase -> 5 - | Doc -> 6 - in - Int.compare (to_int nm) (to_int nm') + | _ -> List.map (fun word -> with_word word entry.Entry.name) query_words end + (** The kind of the entry is used to rank it, but the payload is not needed. *) type kind = | Doc | TypeDecl @@ -82,23 +76,23 @@ module Reasoning = struct ; name_matches : Name_match.t list ; type_distance : int option ; type_in_query : bool - ; type_in_elt : bool + ; type_in_entry : bool ; kind : kind ; is_from_module_type : bool } - let type_distance query_type elt = + let type_distance query_type entry = let open Entry in - match query_type, elt.kind with + match query_type, entry.kind with | None, _ -> None | ( Some query_type , Entry.Kind.( - ( ExtensionConstructor eltype - | Constructor eltype - | Field eltype - | Val eltype - | Exception eltype )) ) -> - Some (Type_distance.v ~query:query_type ~element:eltype) + ( ExtensionConstructor entry_type + | Constructor entry_type + | Field entry_type + | Val entry_type + | Exception entry_type )) ) -> + Some (Type_distance.v ~query:query_type ~entry:entry_type) | ( _ , ( Doc | TypeDecl _ | Module | Class_type | Method | Class | TypeExtension | ModuleType ) ) -> @@ -106,21 +100,21 @@ module Reasoning = struct let type_in_query query_type = Option.is_some query_type - let type_in_elt elt = + let type_in_entry entry = let open Entry in - match elt.kind with + match entry.kind with | ExtensionConstructor _ | Constructor _ | Field _ | Val _ | Exception _ -> true | Doc | TypeDecl _ | Module | Class_type | Method | Class | TypeExtension | ModuleType -> false - let is_stdlib elt = + let is_stdlib entry = let open Entry in - String.starts_with ~prefix:"Stdlib." elt.name + String.starts_with ~prefix:"Stdlib." entry.name - let kind elt = - match elt.Entry.kind with + let kind entry = + match entry.Entry.kind with | Entry.Kind.Doc -> Doc | Entry.Kind.TypeDecl _ -> TypeDecl | Entry.Kind.Module -> Module @@ -135,104 +129,83 @@ module Reasoning = struct | Entry.Kind.Field _ -> Field | Entry.Kind.Val _ -> Val - let name_length elt = String.length elt.Entry.name - let is_from_module_type elt = elt.Entry.is_from_module_type - - let v query_words query_type elt = - let is_stdlib = is_stdlib elt in - let has_doc = elt.Entry.doc_html <> "" in - let name_matches = Name_match.with_words query_words elt in - let kind = kind elt in - let type_distance = type_distance query_type elt in - let type_in_elt = type_in_elt elt in - let type_in_query = type_in_query query_type in - let name_length = name_length elt in - let is_from_module_type = is_from_module_type elt in - { is_stdlib - ; has_doc - ; name_matches - ; type_distance - ; type_in_elt - ; type_in_query - ; kind - ; name_length - ; is_from_module_type + let name_length entry = String.length entry.Entry.name + let is_from_module_type entry = entry.Entry.is_from_module_type + + (** Compute the reasoning for the cost of an entry *) + let v query_words query_type entry = + { is_stdlib = is_stdlib entry + ; has_doc = entry.Entry.doc_html <> "" + ; name_matches = Name_match.with_words query_words entry + ; type_distance = type_distance query_type entry + ; type_in_entry = type_in_entry entry + ; type_in_query = type_in_query query_type + ; kind = kind entry + ; name_length = name_length entry + ; is_from_module_type = is_from_module_type entry } +end - let compare_kind k k' = - let to_int = function - | Val -> 0 - | Module -> 0 - | Doc -> 5 - | Constructor -> 1 - | Field -> 1 - | TypeDecl -> 1 - | ModuleType -> 2 - | Exception -> 3 - | Class_type -> 4 - | Class -> 4 - | TypeExtension -> 4 - | ExtensionConstructor -> 5 - | Method -> 5 - in - Int.compare (to_int k) (to_int k') - - let score +(** [cost_of_reasoning r] is the cost of a entry according to the reasons + contained in [r]. *) +let cost_of_reasoning + Reasoning. { is_stdlib ; has_doc ; name_matches ; type_distance - ; type_in_elt + ; type_in_entry ; type_in_query ; kind ; name_length ; is_from_module_type } = - let ignore_no_doc = - match kind with - | Module | ModuleType -> true - | _ -> false - in - let kind = - match kind with - | Val | Module | ModuleType | Constructor | Field | TypeDecl -> 0 - | Exception -> 30 - | Class_type | Class | TypeExtension -> 40 - | ExtensionConstructor | Method | Doc -> 50 - in - let name_matches = - let open Name_match in - name_matches - |> List.map (function - | DotSuffix -> 0 - | PrefixSuffix -> 103 - | SubDot -> 104 - | SubUnderscore -> 105 - | Sub -> 106 - | Lowercase -> 107 - | Doc -> 1000) - |> List.fold_left ( + ) 0 - in - - let type_cost = - if type_in_elt && type_in_query - then Option.get type_distance - else if type_in_elt - then 0 - else if type_in_query - then - (* If query request a type, elements which do not have one should never - appear. *) - assert false - else 0 - in - let is_from_module_type_cost = if is_from_module_type then 400 else 0 in - (if is_stdlib then 0 else 100) - + (if has_doc || ignore_no_doc then 0 else 100) - + name_matches + type_cost + kind + name_length + is_from_module_type_cost - - let score ~query_name ~query_type elt = score (v query_name query_type elt) -end - -let elt ~query_name ~query_type elt = - Entry.{ elt with cost = Reasoning.score ~query_name ~query_type elt } + let ignore_no_doc = + match kind with + | Module | ModuleType -> true + | _ -> false + in + let kind = + match kind with + | Val | Module | ModuleType | Constructor | Field | TypeDecl -> 0 + | Exception -> 30 + | Class_type | Class | TypeExtension -> 40 + | ExtensionConstructor | Method | Doc -> 50 + in + let name_matches = + let open Reasoning.Name_match in + name_matches + |> List.map (function + | DotSuffix -> 0 + | PrefixSuffix -> 103 + | SubDot -> 104 + | SubUnderscore -> 105 + | Sub -> 106 + | Lowercase -> 107 + | Doc -> 1000) + |> List.fold_left ( + ) 0 + in + let type_cost = + if type_in_entry && type_in_query + then Option.get type_distance + else if type_in_entry + then 0 + else if type_in_query + then + (* If query request a type, elements which do not have one should never + appear. *) + assert false + else 0 + in + let is_from_module_type_cost = if is_from_module_type then 400 else 0 in + (if is_stdlib then 0 else 100) + + (if has_doc || ignore_no_doc then 0 else 100) + + name_matches + type_cost + kind + name_length + is_from_module_type_cost + +let cost_of_entry ~query_name ~query_type entry = + cost_of_reasoning (Reasoning.v query_name query_type entry) + +(** [update_entry ~query_name ~query_type e] updates [e.cost] to take into + account the query described by [query_name] and [query_type]. *) +let update_entry ~query_name ~query_type entry = + Entry.{ entry with cost = cost_of_entry ~query_name ~query_type entry } diff --git a/query/parser.mly b/query/parser.mly index 520bbc1e35..e92ea40614 100644 --- a/query/parser.mly +++ b/query/parser.mly @@ -16,7 +16,6 @@ %start main %type< Db.Typexpr.t> main -%left EOF %% separated_twolong_list(sep, elt): @@ -29,7 +28,7 @@ main: typ: | a=typ1 ARROW b=typ { arrow a b } - | a=typ1 ARROW { arrow a any } + | a=typ1 ARROW EOF { arrow a any } | ARROW b=typ { arrow any b } | ARROW EOF { arrow any any } | t=typ1 { t } diff --git a/query/query.ml b/query/query.ml index 842d8dd541..50c0d3ef0c 100644 --- a/query/query.ml +++ b/query/query.ml @@ -22,7 +22,7 @@ let collapse_trie_occ ~count t = let collapse_trie t = Succ.(Tree.sets_tree ~union ~terminal:of_array ~union_of_array t) -let find_types ~shards names = +let find_types ~shards polarities = List.fold_left (fun acc shard -> let db = Db.(shard.db_types) in @@ -33,7 +33,7 @@ let find_types ~shards names = match Tree_occ.find db name with | Some trie -> collapse_trie_occ ~count trie | None -> Succ.empty) - names + polarities in Succ.union acc r) Succ.empty shards @@ -93,7 +93,7 @@ let api ~(shards : Db.t list) ?(dynamic_sort = true) params = if dynamic_sort then List.map - (Dynamic_cost.elt ~query_name ~query_type:query_typ_arrow) + (Dynamic_cost.update_entry ~query_name ~query_type:query_typ_arrow) results else results in diff --git a/query/query_parser.ml b/query/query_parser.ml index c555c81509..9b7369120d 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -17,16 +17,17 @@ let of_string str = in let pretty_typ, type_polarities, typ = match parse str_typ with - | Any -> "_", [], None + | Any -> "_", None, None | typ -> ( Db.Typexpr.show typ - , List.filter + , Some (List.filter (fun (word, _count) -> String.length word > 0) - (Db.Type_polarity.of_typ ~ignore_any:true ~all_names:false typ) + (Db.Type_polarity.of_typ ~ignore_any:true ~all_names:false typ)) , Some typ ) - | exception _ -> "", [], None + | exception Parser.Error -> + "", None, None in let query_name = naive_of_string str_name in - let type_polarities = if has_typ then Some type_polarities else None in + let type_polarities = if has_typ then type_polarities else None in let pretty_query = String.concat " " query_name ^ " : " ^ pretty_typ in query_name, type_polarities, typ, pretty_query diff --git a/query/type_distance.ml b/query/type_distance.ml index 273b0d05af..0175ef0814 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -198,10 +198,10 @@ let minimize = function let _ = go (Array.length used) 0 0 in !best -let v ~query ~element = +let v ~query ~entry = let query_paths = Type_path.of_typ ~ignore_any:false query in - let element_paths = Type_path.of_typ ~ignore_any:false element in - match element_paths, query_paths with + let entry_paths = Type_path.of_typ ~ignore_any:false entry in + match entry_paths, query_paths with | _, [] | [], _ -> 0 | _ -> let arr = @@ -209,6 +209,6 @@ let v ~query ~element = (fun p -> let p = List.rev p in List.map (fun q -> distance (List.rev q) p) query_paths) - element_paths + entry_paths in minimize arr diff --git a/query/type_distance.mli b/query/type_distance.mli index 49cf1bca7d..0564fb163e 100644 --- a/query/type_distance.mli +++ b/query/type_distance.mli @@ -1 +1,5 @@ -val v : query:Db.Typexpr.t -> element:Db.Typexpr.t -> int + +(** [Type_distance.v ~query ~entry] is an integer representing a notion of + distance between two types. [query] is a type from a query, and [entry] is + the type of a possible response to this query. *) +val v : query:Db.Typexpr.t -> entry:Db.Typexpr.t -> int diff --git a/review.md b/review.md index 3f58f5a0c9..0e4b5ed87d 100644 --- a/review.md +++ b/review.md @@ -8,18 +8,6 @@ - Type extensions: we might want to search for all extensions of a given extensible type. -## With Arthur - -- pretty-query: vraiment necessaire ? -> Mettre a part - -- ask about `Query.paths_arrow` vs `index/load_doc.type_distance_paths` - -- Should `_ -> int` be supported ? -> Yes, try to fix it in dynamic cost - -- Suffix_tree -> succ conversion - # done - Réfléchir à `ancient`: enlever pour de bon, rétablir le support ? @@ -51,7 +39,8 @@ they are interpreted as relative to the `-o` option") - Documenter parser/lexer de query. -# Commentaires/Action Point/... +- It would be cool to be able to see the string corresponding to types, and also of the intermediate string list list +> Some examples were added - refactor `Query.paths_arrow` vs `index/load_doc.type_distance_paths` `Query.paths_arrow` is the right implementation, load_doc should tranform the @@ -59,6 +48,8 @@ they are interpreted as relative to the `-o` option") path. Be careful about hash consing. +# TODO + - Have something more robust than sizes in tests. Remove them, and use current-bench or just a manual benchmark. @@ -66,13 +57,16 @@ they are interpreted as relative to the `-o` option") - `Index.Load_doc.with_tokenizer`: think of which character form a word -- It would be cool to be able to see the string corresponding to types, and also of the intermediate string list list - Maybe store all "arbitrary constants" relative to the cost function somewhere +- Rewrite the type parser in a more flexible framework than menhir (combinator or recursive descent) + +- separate pretty_query from the api function +- Try to support `_ -> int` with dynamic cost ? # Explications commentée diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 876bd4e1cf..4c3a11e7b8 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,10 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.236s - user 0m1.181s - sys 0m0.050s + real 0m1.170s + user 0m1.122s + sys 0m0.043s + @@ -44,8 +45,8 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ gzip -k megaodocl $ du -s *.js *.gz - 2576 db.js - 1944 db.js.gz + 2644 db.js + 1996 db.js.gz 1544 megaodocl.gz @@ -71,7 +72,7 @@ indent to see results $ cp -r html /tmp $ firefox /tmp/html/base/index.html $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin "S_poly" + $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin --limit 100 "S_poly" 115 sig Base.Map.S_poly 115 sig Base.Set.S_poly 119 sig Base.Hashtbl.S_poly @@ -83,11 +84,17 @@ $ firefox /tmp/html/base/index.html 627 val Base.Hashtbl.S_poly.set 628 val Base.Hashtbl.S_poly.data 628 val Base.Hashtbl.S_poly.find + 628 val Base.Hashtbl.S_poly.fold 628 val Base.Hashtbl.S_poly.keys + 628 val Base.Hashtbl.S_poly.mapi 630 val Base.Hashtbl.S_poly.choose + 632 val Base.Hashtbl.S_poly.find_exn + 632 val Base.Hashtbl.S_poly.to_alist + 634 val Base.Hashtbl.S_poly.choose_exn 721 type ('a, 'b) Base.Map.S_poly.t 721 type 'elt Base.Set.S_poly.t 723 val Base.Map.S_poly.add + 723 val Base.Map.S_poly.map 723 val Base.Map.S_poly.mem 723 val Base.Map.S_poly.nth 723 val Base.Map.S_poly.set @@ -97,31 +104,75 @@ $ firefox /tmp/html/base/index.html 723 val Base.Set.S_poly.sum 724 val Base.Map.S_poly.data 724 val Base.Map.S_poly.find + 724 val Base.Map.S_poly.fold + 724 val Base.Map.S_poly.iter 724 val Base.Map.S_poly.keys + 724 val Base.Map.S_poly.mapi + 724 val Base.Map.S_poly.rank 724 type ('a, 'b) Base.Map.S_poly.tree 724 val Base.Set.S_poly.diff + 724 val Base.Set.S_poly.find + 724 val Base.Set.S_poly.fold 724 val Base.Set.S_poly.iter 724 type 'elt Base.Set.S_poly.tree 725 type ('a, 'b) Base.Hashtbl.S_poly.t + 725 val Base.Map.S_poly.count 725 val Base.Map.S_poly.empty - 725 val Base.Map.S_poly.split + 725 val Base.Map.S_poly.iteri + 725 val Base.Set.S_poly.count 725 val Base.Set.S_poly.empty 725 val Base.Set.S_poly.equal 725 val Base.Set.S_poly.inter + 725 val Base.Set.S_poly.iter2 725 val Base.Set.S_poly.split 725 val Base.Set.S_poly.union + 726 val Base.Map.S_poly.append + 726 val Base.Map.S_poly.exists 726 val Base.Map.S_poly.length + 726 val Base.Map.S_poly.remove 726 val Base.Set.S_poly.choose + 726 val Base.Set.S_poly.exists + 726 val Base.Set.S_poly.filter 726 val Base.Set.S_poly.length 726 val Base.Set.S_poly.remove 727 type 'a Base.Hashtbl.S_poly.key + 727 val Base.Hashtbl.S_poly.mem + 727 val Base.Map.S_poly.add_exn + 727 val Base.Map.S_poly.max_elt + 727 val Base.Map.S_poly.min_elt + 727 val Base.Map.S_poly.nth_exn + 727 val Base.Map.S_poly.of_tree + 727 val Base.Map.S_poly.to_tree + 727 val Base.Set.S_poly.for_all 727 val Base.Set.S_poly.max_elt + 727 val Base.Set.S_poly.min_elt 727 val Base.Set.S_poly.of_list 727 val Base.Set.S_poly.of_tree 727 val Base.Set.S_poly.to_list 727 val Base.Set.S_poly.to_tree + 728 val Base.Hashtbl.S_poly.copy + 728 val Base.Map.S_poly.find_exn + 728 val Base.Map.S_poly.is_empty + 728 val Base.Map.S_poly.map_keys 728 val Base.Map.S_poly.of_alist + 728 val Base.Set.S_poly.elements + 728 val Base.Set.S_poly.find_exn + 728 val Base.Set.S_poly.is_empty + 728 val Base.Set.S_poly.of_array + 728 val Base.Set.S_poly.to_array + 729 val Base.Hashtbl.S_poly.clear + 729 val Base.Map.S_poly.singleton + 729 val Base.Set.S_poly.is_subset 729 val Base.Set.S_poly.singleton + 730 val Base.Hashtbl.S_poly.length + 730 val Base.Map.S_poly.invariants + 730 val Base.Set.S_poly.choose_exn + 730 val Base.Set.S_poly.invariants + 731 val Base.Map.S_poly.max_elt_exn + 731 val Base.Map.S_poly.min_elt_exn + 731 val Base.Set.S_poly.max_elt_exn + 731 val Base.Set.S_poly.min_elt_exn + 732 val Base.Hashtbl.S_poly.hashable $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin "group b" 218 val Base.List.group 221 val Base.Hashtbl.group diff --git a/test/cram/cli_small.t/main.mli b/test/cram/cli_small.t/main.mli index a3685d09dc..9e1d7609a7 100644 --- a/test/cram/cli_small.t/main.mli +++ b/test/cram/cli_small.t/main.mli @@ -5,5 +5,14 @@ module List : sig type 'a t = 'a list val map : ('a -> 'b) -> 'a t -> 'b t + + val empty : 'a t * 'b t + + end +type ('a, 'b) result + +val ok: 'a -> ('a, 'b) result + +val ok_zero : (int, 'a) result \ No newline at end of file diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 5caf0eccf5..e20b3b601b 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -11,3 +11,8 @@ 209 type 'a Main.list 315 type 'a Main.List.t = 'a list 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 319 val Main.List.empty : 'a t * 'b t + $ export OCAMLRUNPARAM=b +This is a bug in the parser, there should be results (TODO fix it) + $ sherlodoc ": (int, 'a) result" + [No results] From bc5ff03c05878227e6892c8d1b5b921ec9999066 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 18 Dec 2023 15:05:29 +0100 Subject: [PATCH 191/285] remove pretty from api --- cli/main.ml | 6 +++--- db/db.ml | 3 +-- db/type_polarity.ml | 12 ++++-------- index/load_doc.mli | 5 ++--- jsoo/main.ml | 4 ++-- query/dynamic_cost.ml | 6 +++--- query/query.ml | 36 ++++++++++++++++++++++++------------ query/query.mli | 7 ++++--- query/query_parser.ml | 32 +++++++++++++------------------- query/query_parser.mli | 3 +-- query/type_distance.mli | 3 +-- test/cram/base.t/run.t | 6 +++--- www/www.ml | 3 ++- 13 files changed, 63 insertions(+), 63 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index 3fa17fd30c..a681fcd215 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -51,11 +51,11 @@ let print_result ~print_cost ~no_rhs let search ~print_cost ~static_sort ~limit ~db ~no_rhs query = match Query.( - api ~shards:db ~dynamic_sort:(not static_sort) + search ~shards:db ~dynamic_sort:(not static_sort) { query; packages = []; limit }) with - | _, [] -> print_endline "[No results]" - | _, (_ :: _ as results) -> + | [] -> print_endline "[No results]" + | _ :: _ as results -> List.iter (print_result ~print_cost ~no_rhs) results ; flush stdout diff --git a/db/db.ml b/db/db.ml index d565c1d1e3..cb8400a2ed 100644 --- a/db/db.ml +++ b/db/db.ml @@ -28,8 +28,7 @@ let store db name elt ~count = Suffix_tree.With_occ.add_suffixes db.writer_types name (count, elt) let store_type_polarities db elt polarities = - List.iter (fun (word, count) -> - store db ~count word elt) polarities + List.iter (fun (word, count) -> store db ~count word elt) polarities let store_word db word elt = Suffix_tree.With_elts.add_suffixes db.writer_names word elt diff --git a/db/type_polarity.ml b/db/type_polarity.ml index c2fba16478..94e288f6a3 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -35,19 +35,16 @@ let all_type_names name = name |> String.split_on_char '.' |> tails |> List.map (String.concat ".") let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function - | Poly _ -> [ Sign.to_string sgn :: "POLY" :: prefix ] + | Poly _ -> [ Sign.to_string sgn :: "POLY" :: prefix ] | Any -> if ignore_any - then ( - - [ prefix ]) - else [ Sign.to_string sgn :: "POLY" :: prefix ] + then [ prefix ] + else [ Sign.to_string sgn :: "POLY" :: prefix ] | Arrow (a, b) -> List.rev_append (of_typ ~ignore_any ~all_names ~prefix ~sgn:(Sign.not sgn) a) (of_typ ~ignore_any ~all_names ~prefix ~sgn b) | Constr (name, args) -> - name |> (if all_names then all_type_names else fun name -> [ name ]) |> List.map (fun name -> @@ -68,8 +65,7 @@ let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function rev_concat @@ List.map (of_typ ~ignore_any ~all_names ~prefix ~sgn) @@ args - | Unhandled -> - [] + | Unhandled -> [] (** [of_typ ~ignore_any ~prefix ~sgn t] is a representation of [t] that encodes the polarity of the elements of the type : in [string -> int] [int] diff --git a/index/load_doc.mli b/index/load_doc.mli index 280ac220ed..f7f5ad898c 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -1,6 +1,3 @@ - -(** [register_entry ~db ~index_name ~type_search ~index_docstring e] register - the entry [e] in [db]. *) val register_entry : db:Db.writer -> index_name:bool @@ -8,3 +5,5 @@ val register_entry : -> index_docstring:bool -> Odoc_search.Entry.t -> unit +(** [register_entry ~db ~index_name ~type_search ~index_docstring e] register + the entry [e] in [db]. *) diff --git a/jsoo/main.ml b/jsoo/main.ml index 012c8add35..63a4abc898 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -98,8 +98,8 @@ let string_of_kind = let search message db = let query = Jv.get message "data" in let query = query |> Jv.to_jstr |> Jstr.to_string in - let _pretty_query, results = - Query.(api ~shards:db { query; packages = []; limit = 50 }) + let results = + Query.(search ~shards:db { query; packages = []; limit = 50 }) in let _ = Jv.(apply (get global "postMessage")) diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 6b421bcae5..20e396cc66 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -84,8 +84,8 @@ module Reasoning = struct let type_distance query_type entry = let open Entry in match query_type, entry.kind with - | None, _ -> None - | ( Some query_type + | Error _, _ -> None + | ( Ok query_type , Entry.Kind.( ( ExtensionConstructor entry_type | Constructor entry_type @@ -98,7 +98,7 @@ module Reasoning = struct | TypeExtension | ModuleType ) ) -> None - let type_in_query query_type = Option.is_some query_type + let type_in_query query_type = Result.is_ok query_type let type_in_entry entry = let open Entry in diff --git a/query/query.ml b/query/query.ml index 50c0d3ef0c..71c88e2dcf 100644 --- a/query/query.ml +++ b/query/query.ml @@ -22,7 +22,13 @@ let collapse_trie_occ ~count t = let collapse_trie t = Succ.(Tree.sets_tree ~union ~terminal:of_array ~union_of_array t) -let find_types ~shards polarities = +let polarities typ = + List.filter + (fun (word, _count) -> String.length word > 0) + (Db.Type_polarity.of_typ ~ignore_any:true ~all_names:false typ) + +let find_types ~shards typ = + let polarities = polarities typ in List.fold_left (fun acc shard -> let db = Db.(shard.db_types) in @@ -63,10 +69,10 @@ type t = let search ~(shards : Db.t list) query_name query_typ = match query_name, query_typ with - | [], None -> Succ.empty - | _ :: _, None -> find_names ~shards query_name - | [], Some query_typ -> find_types ~shards query_typ - | _ :: _, Some query_typ -> + | [], Error _ -> Succ.empty + | _ :: _, Error _ -> find_names ~shards query_name + | [], Ok query_typ -> find_types ~shards query_typ + | _ :: _, Ok query_typ -> let results_name = find_names ~shards query_name in let results_typ = find_types ~shards query_typ in Succ.inter results_name results_typ @@ -81,11 +87,9 @@ let match_packages ~packages results = | [] -> results | _ -> Seq.filter (match_packages ~packages) results -let api ~(shards : Db.t list) ?(dynamic_sort = true) params = - let query_name, query_typ, query_typ_arrow, pretty = - Parser.of_string params.query - in - let results = search ~shards query_name query_typ in +let search ~(shards : Db.t list) ?(dynamic_sort = true) params = + let words, typ = Parser.of_string params.query in + let results = search ~shards words typ in let results = Succ.to_seq ~compare:Db.Entry.compare results in let results = match_packages ~packages:params.packages results in let results = List.of_seq @@ Seq.take params.limit results in @@ -93,10 +97,18 @@ let api ~(shards : Db.t list) ?(dynamic_sort = true) params = if dynamic_sort then List.map - (Dynamic_cost.update_entry ~query_name ~query_type:query_typ_arrow) + (Dynamic_cost.update_entry ~query_name:words ~query_type:typ) results else results in let results = List.sort Db.Entry.compare results in + results - pretty, results +let pretty params = + let words, typ = Parser.of_string params.query in + let words = String.concat " " words in + match typ with + | Ok typ -> words ^ " : " ^ Db.Typexpr.show typ + | Error `parse -> words ^ " : " + | Error `any -> words ^ " : _" + | Error `empty -> words diff --git a/query/query.mli b/query/query.mli index d147de849c..2b8523e592 100644 --- a/query/query.mli +++ b/query/query.mli @@ -4,9 +4,8 @@ type t = ; limit : int } -val api : - shards:Db.t list -> ?dynamic_sort:bool -> t -> string * Db.Entry.t list -(** [api ~shard ~dynamic_sort {query; packages; limit}] returns [(pretty_query, +val search : shards:Db.t list -> ?dynamic_sort:bool -> t -> Db.Entry.t list +(** [search ~shard ~dynamic_sort {query; packages; limit}] returns [(pretty_query, results)] where [pretty_query] is a re-printed version of [query] and [results] is the list of results corresponding to the query and the various parameters. @@ -31,6 +30,8 @@ val api : - [packages] is not function, use [[]] for this argument. *) +val pretty : t -> string + (** For testing *) module Private : sig module Array_succ = Array_succ diff --git a/query/query_parser.ml b/query/query_parser.ml index 9b7369120d..dd2c8aa22f 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -9,25 +9,19 @@ let guess_type_search str = let of_string str = let str = String.trim str in - let has_typ, str_name, str_typ = + let str_name, str_typ = match String.split_on_char ':' str with - | [ a; b ] -> true, a, b - | _ when guess_type_search str -> true, "", str - | _ -> false, str, "" + | [ a; b ] -> a, Ok b + | _ when guess_type_search str -> "", Ok str + | _ -> str, Error `empty in - let pretty_typ, type_polarities, typ = - match parse str_typ with - | Any -> "_", None, None - | typ -> - ( Db.Typexpr.show typ - , Some (List.filter - (fun (word, _count) -> String.length word > 0) - (Db.Type_polarity.of_typ ~ignore_any:true ~all_names:false typ)) - , Some typ ) - | exception Parser.Error -> - "", None, None + + let typ = + Result.bind str_typ (fun str_typ -> + match parse str_typ with + | Any -> Error `any + | typ -> Ok typ + | exception Parser.Error -> Error `parse) in - let query_name = naive_of_string str_name in - let type_polarities = if has_typ then type_polarities else None in - let pretty_query = String.concat " " query_name ^ " : " ^ pretty_typ in - query_name, type_polarities, typ, pretty_query + let words = naive_of_string str_name in + words, typ diff --git a/query/query_parser.mli b/query/query_parser.mli index f046173d8a..9d53e92ef3 100644 --- a/query/query_parser.mli +++ b/query/query_parser.mli @@ -1,3 +1,2 @@ val of_string : - string - -> string list * Db.Type_polarity.t list option * Db.Typexpr.t option * string + string -> string list * (Db.Typexpr.t, [> `any | `parse | `empty ]) result diff --git a/query/type_distance.mli b/query/type_distance.mli index 0564fb163e..5a6dc5b39f 100644 --- a/query/type_distance.mli +++ b/query/type_distance.mli @@ -1,5 +1,4 @@ - +val v : query:Db.Typexpr.t -> entry:Db.Typexpr.t -> int (** [Type_distance.v ~query ~entry] is an integer representing a notion of distance between two types. [query] is a type from a query, and [entry] is the type of a possible response to this query. *) -val v : query:Db.Typexpr.t -> entry:Db.Typexpr.t -> int diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 4c3a11e7b8..c67168e449 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,9 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.170s - user 0m1.122s - sys 0m0.043s + real 0m1.201s + user 0m1.148s + sys 0m0.050s diff --git a/www/www.ml b/www/www.ml index 5e70bfc574..1c8ce82566 100644 --- a/www/www.ml +++ b/www/www.ml @@ -2,7 +2,8 @@ module Storage = Db.Storage module H = Tyxml.Html let api ~shards params = - let pretty, results = Query.api ~shards params in + let results = Query.search ~shards params in + let pretty = Query.pretty params in Lwt.return (Ui.render ~pretty results) let api ~shards params = From 270a266cbe031eb27f53ce8c761a6ba757183296 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 18 Dec 2023 15:07:00 +0100 Subject: [PATCH 192/285] update review to be constitant with previous commit --- review.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/review.md b/review.md index 0e4b5ed87d..53f3abe89f 100644 --- a/review.md +++ b/review.md @@ -48,6 +48,9 @@ they are interpreted as relative to the `-o` option") path. Be careful about hash consing. +- separate pretty_query from the api function + + # TODO - Have something more robust than sizes in tests. Remove them, and use @@ -64,8 +67,6 @@ they are interpreted as relative to the `-o` option") - Rewrite the type parser in a more flexible framework than menhir (combinator or recursive descent) -- separate pretty_query from the api function - - Try to support `_ -> int` with dynamic cost ? # Explications commentée From 0ed3599e27bc2c8f488a7d06907622430fd12ea4 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 18 Dec 2023 18:36:23 +0100 Subject: [PATCH 193/285] new recursive descent parser --- cli/main.ml | 32 ++++--- db/dune | 1 + db/typexpr.ml | 2 +- db/typexpr.mli | 2 +- query/dune | 4 +- query/parser.mly | 60 ------------- query/query.ml | 1 + query/query.mli | 1 + query/query_parser.ml | 8 +- query/test/test.ml | 125 +--------------------------- query/test/test_array.ml | 63 ++++++++++++++ query/test/test_succ.ml | 57 +++++++++++++ query/test/test_type_parser.ml | 39 +++++++++ query/{lexer.mll => type_lexer.mll} | 11 ++- query/type_parser.ml | 124 +++++++++++++++++++++++++++ test/cram/base.t/run.t | 8 +- test/cram/cli.t/run.t | 6 +- test/cram/cli_small.t/run.t | 3 +- test/cram/simple.t/run.t | 2 +- 19 files changed, 333 insertions(+), 216 deletions(-) delete mode 100644 query/parser.mly create mode 100644 query/test/test_array.ml create mode 100644 query/test/test_succ.ml create mode 100644 query/test/test_type_parser.ml rename query/{lexer.mll => type_lexer.mll} (75%) create mode 100644 query/type_parser.ml diff --git a/cli/main.ml b/cli/main.ml index a681fcd215..d6e78405d8 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -48,25 +48,23 @@ let print_result ~print_cost ~no_rhs in Format.printf "%s%s %s%s%a\n" cost kind typedecl_params name pp_rhs rhs -let search ~print_cost ~static_sort ~limit ~db ~no_rhs query = - match - Query.( - search ~shards:db ~dynamic_sort:(not static_sort) - { query; packages = []; limit }) - with +let search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query = + let query = Query.{ query; packages = []; limit } in + if pretty_query then print_endline (Query.pretty query) ; + match Query.(search ~shards:db ~dynamic_sort:(not static_sort) query) with | [] -> print_endline "[No results]" | _ :: _ as results -> List.iter (print_result ~print_cost ~no_rhs) results ; flush stdout -let rec search_loop ~print_cost ~no_rhs ~static_sort ~limit ~db = +let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db = match In_channel.input_line stdin with | Some query -> - search ~print_cost ~static_sort ~limit ~db ~no_rhs query ; - search_loop ~print_cost ~no_rhs ~static_sort ~limit ~db + search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query ; + search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db | None -> print_endline "[Search session ended]" -let main db query print_cost no_rhs static_sort limit = +let main db query print_cost no_rhs static_sort limit pretty_query = match db with | None -> output_string stderr @@ -76,8 +74,11 @@ let main db query print_cost no_rhs static_sort limit = | Some db -> ( let db = Storage_marshal.load db in match query with - | None -> search_loop ~print_cost ~no_rhs ~static_sort ~limit ~db - | Some query -> search ~print_cost ~no_rhs ~static_sort ~limit ~db query) + | None -> + search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db + | Some query -> + search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db query + ) open Cmdliner @@ -114,9 +115,14 @@ let no_rhs = let doc = "Do not print the right-hand side of results." in Arg.(value & flag & info [ "no-rhs"; "no-right-hand-side" ] ~doc) +let pretty_query = + let doc = "Prints the query itself as it was parsed" in + Arg.(value & flag & info [ "pretty-query" ] ~doc) + let main = Term.( - const main $ db_filename $ query $ print_cost $ no_rhs $ static_sort $ limit) + const main $ db_filename $ query $ print_cost $ no_rhs $ static_sort $ limit + $ pretty_query) let cmd = let doc = "CLI interface to query sherlodoc" in diff --git a/db/dune b/db/dune index 4899646a37..83acfde513 100644 --- a/db/dune +++ b/db/dune @@ -2,4 +2,5 @@ (library (name db) + (preprocess(pps ppx_deriving.show)) (libraries unix dum)) diff --git a/db/typexpr.ml b/db/typexpr.ml index 906510ac65..1b35683707 100644 --- a/db/typexpr.ml +++ b/db/typexpr.ml @@ -46,7 +46,7 @@ and show_list = function and show_tuple = function | [] -> failwith "show_tuple: empty" - | [ x ] -> show x + | [ x ] -> show_parens x | x :: xs -> show_parens x ^ " * " ^ show_tuple xs let size typ = typ |> show |> String.length diff --git a/db/typexpr.mli b/db/typexpr.mli index 09d25bbeb3..fabceaa0fb 100644 --- a/db/typexpr.mli +++ b/db/typexpr.mli @@ -5,6 +5,7 @@ type t = private | Poly of string | Any | Unhandled + [@@deriving show] val arrow : t -> t -> t val constr : string -> t list -> t @@ -12,5 +13,4 @@ val tuple : t list -> t val poly : string -> t val any : t val unhandled : t -val show : t -> string val size : t -> int diff --git a/query/dune b/query/dune index f78522e1df..5b3efcaedd 100644 --- a/query/dune +++ b/query/dune @@ -5,7 +5,5 @@ (name query) (libraries lwt re db)) -(menhir - (modules parser)) +(ocamllex type_lexer) -(ocamllex lexer) diff --git a/query/parser.mly b/query/parser.mly deleted file mode 100644 index e92ea40614..0000000000 --- a/query/parser.mly +++ /dev/null @@ -1,60 +0,0 @@ -(* This parser parses types as inputed by the user in a query. - It is made in weird way because it is able to correctly parse incomplete - types. It has conflicts because of this, which are impossible to resolve - without losing functionnality. *) - -%{ - open Db.Typexpr -%} - -%token EOF -%token PARENS_OPEN PARENS_CLOSE -%token ARROW COMMA ANY STAR -%token WORD -%token POLY - -%start main -%type< Db.Typexpr.t> main - -%% - -separated_twolong_list(sep, elt): - | e1=elt sep e2=elt sep li=separated_list(sep, elt) { e1 :: e2 :: li } - -main: - | t=typ EOF { t } - | EOF { any } - ; - -typ: - | a=typ1 ARROW b=typ { arrow a b } - | a=typ1 ARROW EOF { arrow a any } - | ARROW b=typ { arrow any b } - | ARROW EOF { arrow any any } - | t=typ1 { t } - ; - -typ1: - | x=typ0 xs=tups { match xs with [] -> x | xs -> tuple (x::xs) } - ; - -tups: - | STAR x=typ0 xs=tups { x::xs } - | STAR { [any] } - | EOF { [] } - | { [] } - ; - -typ0: - | ANY { any } - | w=POLY { poly w } - | w=WORD { constr w [] } - | t=typ0 w=WORD { constr w [t] } - | PARENS_OPEN ts=typ_list PARENS_CLOSE w=WORD { constr w ts } - | PARENS_OPEN t=typ PARENS_CLOSE { t } - | PARENS_OPEN t=typ EOF { t } - ; - -(* ( int EOF EOF *) - -typ_list: ts=separated_twolong_list(COMMA, typ) { ts } ; diff --git a/query/query.ml b/query/query.ml index 71c88e2dcf..08de5d4da5 100644 --- a/query/query.ml +++ b/query/query.ml @@ -8,6 +8,7 @@ module Occ = Db.Occ module Private = struct module Array_succ = Array_succ module Succ = Succ + module Type_parser = Type_parser end let collapse_occ ~count occs = diff --git a/query/query.mli b/query/query.mli index 2b8523e592..e53d93fdca 100644 --- a/query/query.mli +++ b/query/query.mli @@ -36,4 +36,5 @@ val pretty : t -> string module Private : sig module Array_succ = Array_succ module Succ = Succ + module Type_parser = Type_parser end diff --git a/query/query_parser.ml b/query/query_parser.ml index dd2c8aa22f..78ab7aa3e0 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -1,4 +1,4 @@ -let parse str = Parser.main Lexer.token (Lexing.from_string str) +let parse str = Type_parser.of_string str let naive_of_string str = List.filter (fun s -> String.length s > 0) (String.split_on_char ' ' str) @@ -19,9 +19,9 @@ let of_string str = let typ = Result.bind str_typ (fun str_typ -> match parse str_typ with - | Any -> Error `any - | typ -> Ok typ - | exception Parser.Error -> Error `parse) + | Ok Any -> Error `any + | Ok typ -> Ok typ + | Error _ -> Error `parse) in let words = naive_of_string str_name in words, typ diff --git a/query/test/test.ml b/query/test/test.ml index 500569c7d5..374859a2f0 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -1,130 +1,7 @@ -open Query.Private - -module Test_array = struct - let rec succ_ge_reference i ~compare elt arr = - Printf.printf "ref_succ_ge %i\n%!" i ; - if i = Array.length arr - then None - else if compare arr.(i) elt >= 0 - then Some arr.(i) - else succ_ge_reference (i + 1) ~compare elt arr - - let rec succ_gt_reference i ~compare elt arr = - if i = Array.length arr - then None - else if compare arr.(i) elt > 0 - then Some arr.(i) - else succ_gt_reference (i + 1) ~compare elt arr - - let succ_ge_reference ~compare elt arr = succ_ge_reference 0 ~compare elt arr - let succ_gt_reference ~compare elt arr = succ_gt_reference 0 ~compare elt arr - - let test_succ_ge elt arr () = - Alcotest.(check (option int)) - "same int option" - (succ_ge_reference ~compare:Int.compare elt arr) - (Array_succ.succ_ge ~compare:Int.compare elt arr) - - let test_succ_gt elt arr () = - Alcotest.(check (option int)) - "same int option" - (succ_gt_reference ~compare:Int.compare elt arr) - (Array_succ.succ_gt ~compare:Int.compare elt arr) - - let () = Random.init 123 - - (* The tests *) - - let random_array size = - let r = - List.init size (fun _ -> Random.full_int (size * 2)) - |> List.sort_uniq Int.compare |> Array.of_list - in - - r - - let tests_arr name test = - List.init 50 (fun i -> - let elt = Random.full_int ((i * 2) + 1) in - let arr = random_array i in - let arr_string = - if i <= 5 - then - "[|" - ^ (arr |> Array.to_list |> List.map string_of_int - |> String.concat "; ") - ^ "|]" - else "[|...|]" - in - Alcotest.test_case - (Printf.sprintf "%s %i %s " name elt arr_string) - `Quick (test elt arr)) - - let tests_succ_ge = tests_arr "succ_ge" test_succ_ge - let tests_succ_gt = tests_arr "succ_gt" test_succ_gt -end - -module Test_succ = struct - (** This module does the same thing as Succ, but its correctness is obvious - and its performance terrible. *) - module Reference = struct - include Set.Make (Int) - - let of_array arr = arr |> Array.to_seq |> of_seq - let to_seq ~compare:_ = to_seq - end - - (** This module is used to construct a pair of a "set array" using [Reference] - and a Succ that are exactly the same. *) - module Both = struct - let empty = Reference.empty, Succ.empty - let union (l, l') (r, r') = Reference.union l r, Succ.union l' r' - let inter (l, l') (r, r') = Reference.inter l r, Succ.inter l' r' - let of_array arr = Reference.of_array arr, Succ.of_array arr - end - - (** This is a problematic exemple that was found randomly. It is saved here - to check for regressions. *) - let extra_succ = - Both.( - union - (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) - (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |]))) - - let rec random_set ~empty ~union ~inter ~of_array size = - let random_set = random_set ~empty ~union ~inter ~of_array in - if size = 0 - then empty - else - match Random.int 3 with - | 0 -> - let arr = Test_array.random_array size in - Array.sort Int.compare arr ; - of_array arr - | 1 -> inter (random_set (size / 2)) (random_set (size / 2)) - | 2 -> union (random_set (size / 2)) (random_set (size / 2)) - | _ -> assert false - - let test_to_seq tree () = - let ref = - fst tree |> Reference.to_seq ~compare:Int.compare |> List.of_seq - in - let real = snd tree |> Succ.to_seq ~compare:Int.compare |> List.of_seq in - Alcotest.(check (list int)) "same int list" ref real - - let tests_to_seq = - [ Alcotest.test_case "Succ.to_seq extra" `Quick (test_to_seq extra_succ) ] - @ List.init 50 (fun i -> - let i = i * 7 in - let succ = i |> Both.(random_set ~empty ~union ~inter ~of_array) in - Alcotest.test_case - (Printf.sprintf "Succ.to_seq size %i" i) - `Quick (test_to_seq succ)) -end - let () = let open Alcotest in run "Query" [ "Array_succ", Test_array.tests_succ_ge @ Test_array.tests_succ_gt ; "Succ", Test_succ.tests_to_seq + ; "Type_parser", Test_type_parser.tests ] diff --git a/query/test/test_array.ml b/query/test/test_array.ml new file mode 100644 index 0000000000..64a7d72086 --- /dev/null +++ b/query/test/test_array.ml @@ -0,0 +1,63 @@ +open Query.Private + +let rec succ_ge_reference i ~compare elt arr = + Printf.printf "ref_succ_ge %i\n%!" i ; + if i = Array.length arr + then None + else if compare arr.(i) elt >= 0 + then Some arr.(i) + else succ_ge_reference (i + 1) ~compare elt arr + +let rec succ_gt_reference i ~compare elt arr = + if i = Array.length arr + then None + else if compare arr.(i) elt > 0 + then Some arr.(i) + else succ_gt_reference (i + 1) ~compare elt arr + +let succ_ge_reference ~compare elt arr = succ_ge_reference 0 ~compare elt arr +let succ_gt_reference ~compare elt arr = succ_gt_reference 0 ~compare elt arr + +let test_succ_ge elt arr () = + Alcotest.(check (option int)) + "same int option" + (succ_ge_reference ~compare:Int.compare elt arr) + (Array_succ.succ_ge ~compare:Int.compare elt arr) + +let test_succ_gt elt arr () = + Alcotest.(check (option int)) + "same int option" + (succ_gt_reference ~compare:Int.compare elt arr) + (Array_succ.succ_gt ~compare:Int.compare elt arr) + +let () = Random.init 123 + +(* The tests *) + +let random_array size = + let r = + List.init size (fun _ -> Random.full_int (size * 2)) + |> List.sort_uniq Int.compare |> Array.of_list + in + + r + +let tests_arr name test = + List.init 50 (fun i -> + let elt = Random.full_int ((i * 2) + 1) in + let arr = random_array i in + let arr_string = + if i <= 5 + then + "[|" + ^ (arr |> Array.to_list |> List.map string_of_int + |> String.concat "; ") + ^ "|]" + else "[|...|]" + in + Alcotest.test_case + (Printf.sprintf "%s %i %s " name elt arr_string) + `Quick (test elt arr)) + +let tests_succ_ge = tests_arr "succ_ge" test_succ_ge +let tests_succ_gt = tests_arr "succ_gt" test_succ_gt diff --git a/query/test/test_succ.ml b/query/test/test_succ.ml new file mode 100644 index 0000000000..e80f22c2b5 --- /dev/null +++ b/query/test/test_succ.ml @@ -0,0 +1,57 @@ +open Query.Private + + + (** This module does the same thing as Succ, but its correctness is obvious + and its performance terrible. *) +module Reference = struct + include Set.Make (Int) + + + let of_array arr = arr |> Array.to_seq |> of_seq + let to_seq ~compare:_ = to_seq +end + +(** This module is used to construct a pair of a "set array" using [Reference] + and a Succ that are exactly the same. *) +module Both = struct + let empty = Reference.empty, Succ.empty + let union (l, l') (r, r') = Reference.union l r, Succ.union l' r' + let inter (l, l') (r, r') = Reference.inter l r, Succ.inter l' r' + let of_array arr = Reference.of_array arr, Succ.of_array arr +end + +(** This is a problematic exemple that was found randomly. It is saved here + to check for regressions. *) +let extra_succ = + Both.( + union + (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) + (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |]))) + +let rec random_set ~empty ~union ~inter ~of_array size = + let random_set = random_set ~empty ~union ~inter ~of_array in + if size = 0 + then empty + else + match Random.int 3 with + | 0 -> + let arr = Test_array.random_array size in + Array.sort Int.compare arr ; + of_array arr + | 1 -> inter (random_set (size / 2)) (random_set (size / 2)) + | 2 -> union (random_set (size / 2)) (random_set (size / 2)) + | _ -> assert false + +let test_to_seq tree () = + let ref = fst tree |> Reference.to_seq ~compare:Int.compare |> List.of_seq in + let real = snd tree |> Succ.to_seq ~compare:Int.compare |> List.of_seq in + Alcotest.(check (list int)) "same int list" ref real + +let tests_to_seq = + [ Alcotest.test_case "Succ.to_seq extra" `Quick (test_to_seq extra_succ) ] + @ List.init 50 (fun i -> + let i = i * 7 in + let succ = i |> Both.(random_set ~empty ~union ~inter ~of_array) in + Alcotest.test_case + (Printf.sprintf "Succ.to_seq size %i" i) + `Quick (test_to_seq succ)) diff --git a/query/test/test_type_parser.ml b/query/test/test_type_parser.ml new file mode 100644 index 0000000000..d6f55599fb --- /dev/null +++ b/query/test/test_type_parser.ml @@ -0,0 +1,39 @@ +open Db.Typexpr + +let random_elt arr = arr.(Random.int (Array.length arr)) +let random_poly () = poly (random_elt [| "a"; "b"; "c"; "d"; "e" |]) + +let random_constr () = + constr (random_elt [| "float"; "int"; "string"; "foo"; "bar"; "t" |]) [] + +let rec random_type size = + match size with + | 0 | 1 -> random_elt [| random_poly; random_constr; (fun () -> any) |] () + | (2 | 3 | 4) when Random.bool () -> random_constr_params size + | _ when Random.int 100 < 20 -> + let n = 2 + Random.int 3 in + tuple (List.init n (fun _i -> random_type (size / n))) + | _ -> + let size = size / 2 in + arrow (random_type size) (random_type size) + +and random_constr_params n = + constr + (random_elt [| "list"; "option"; "t"; "result"; "array" |]) + (List.init (n-1) (fun i -> random_type i)) + +open Query.Private + +let test_parser typ () = + let str = Db.Typexpr.show typ in + let typ' = Type_parser.of_string str in + let str' = Result.map Db.Typexpr.show typ' in + Alcotest.(check (result string string)) "same string" (Ok str) str' + +let tests = + List.init 50 (fun i -> + let i = i in + let typ = random_type i in + Alcotest.test_case + (Printf.sprintf "Type_parser size %i" i) + `Quick (test_parser typ)) diff --git a/query/lexer.mll b/query/type_lexer.mll similarity index 75% rename from query/lexer.mll rename to query/type_lexer.mll index 8e6db8f24f..e5e126b7b3 100644 --- a/query/lexer.mll +++ b/query/type_lexer.mll @@ -1,7 +1,16 @@ (* This is the lexer for the [parser.mly]. *) { - open Parser + type token = + | ARROW + | PARENS_OPEN + | PARENS_CLOSE + | COMMA + | ANY + | STAR + | POLY of string + | WORD of string + | EOF } rule token = parse diff --git a/query/type_parser.ml b/query/type_parser.ml new file mode 100644 index 0000000000..de6b1f99e7 --- /dev/null +++ b/query/type_parser.ml @@ -0,0 +1,124 @@ +exception Parse_error of string + +let error str = raise (Parse_error str) +let errorf a = Format.kasprintf error a + +open Type_lexer +open Db.Typexpr + +type a = int * float -> string + +let pp_token f t = + Format.pp_print_string f + (match t with + | ARROW -> "ARROW" + | PARENS_OPEN -> "PARENS_OPEN" + | PARENS_CLOSE -> "PARENS_CLOSE" + | COMMA -> "COMMA" + | ANY -> "ANY" + | STAR -> "STAR" + | POLY p -> Printf.sprintf "POLY %s" p + | WORD w -> Printf.sprintf "WORD %s" w + | EOF -> "EOF") + +module Tokens_gen = struct + type t = + { lexer : Lexing.lexbuf -> token + ; lexbuf : Lexing.lexbuf + ; mutable peeked : token option + } + + let get ({ lexer; lexbuf; peeked } as t) = + match peeked with + | None -> lexer lexbuf + | Some token -> + t.peeked <- None ; + token + + let discard t = ignore (get t) + + let peek t = + match t.peeked with + | Some token -> token + | None -> + let token = get t in + t.peeked <- Some token ; + token +end + +open Tokens_gen + +let rec typ tokens = + match peek tokens with + | ARROW -> + discard tokens ; + typ tokens + | _ -> ( + let typ_left = typ2 tokens in + match peek tokens with + | ARROW -> + discard tokens ; + let typ_right = typ tokens in + arrow typ_left typ_right + | EOF -> typ_left + | PARENS_CLOSE | COMMA -> typ_left + | _ -> error "typ") + +and typ2 tokens = + let typ = typ1 tokens in + let tups = tups tokens in + match tups with + | [] -> typ + | _ :: _ -> tuple (typ :: tups) + +and tups tokens = + match peek tokens with + | STAR -> + discard tokens ; + let typ = typ1 tokens in + typ :: tups tokens + | _ -> [] + +and parens tokens = + let typ = typ tokens in + match get tokens with + | COMMA -> ( + let params = typ :: params tokens in + match get tokens with + | WORD w -> constr w params + | _ -> error "parens 1") + | PARENS_CLOSE -> typ + | _ -> error "parens 2" + +and params tokens = + let typ = typ tokens in + match get tokens with + | COMMA -> typ :: params tokens + | PARENS_CLOSE -> [ typ ] + | tok -> errorf "params %a" pp_token tok + +and constr_one_param tokens = + match peek tokens with + | WORD w -> + discard tokens; + fun typ -> constr w [typ] + | _ -> Fun.id + +and typ1 tokens = + let typ = typ0 tokens in + constr_one_param tokens typ + + +and typ0 tokens = + match get tokens with + | ANY -> any + | POLY w -> poly w + | WORD w -> constr w [] + | PARENS_OPEN -> parens tokens + | _ -> error "typ0" + +let of_string str = + let tokens = + { lexbuf = Lexing.from_string str; lexer = Type_lexer.token; peeked = None } + in + try Ok (typ tokens) with Parse_error msg -> Error msg diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index c67168e449..eb90d545af 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,9 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.201s - user 0m1.148s - sys 0m0.050s + real 0m1.316s + user 0m1.266s + sys 0m0.043s @@ -57,7 +57,7 @@ $ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstr $ cp db.js html/ $ cp ../../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 5.2M html/sherlodoc.js + 5.1M html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 3853c3983a..735dcbae77 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -29,7 +29,7 @@ val Main.Map.to_list : foo val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo - doc + doc $ sherlodoc "map" mod Main.Map val Main.List.map : ('a -> 'b) -> 'a t -> 'b t @@ -81,7 +81,7 @@ val Main.Nest.nesting_priority : foo cons Main.MyExtension : moo -> extensible_type val Main.foo : foo - doc + doc $ sherlodoc "qwertyuiopasdfghjklzxcvbnm" [No results] $ sherlodoc "hidden" @@ -104,10 +104,12 @@ TODO : get a result for the query bellow val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc ": ('a -> 'b) -> 'a t -> 'b t" + : ('a -> 'b) -> 'a t -> 'b t val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t TODO : get a result for the query bellow $ sherlodoc ": 'a bo" + : 'a bo val Main.poly_param : 'a boo $ sherlodoc ":extensible_type" cons Main.MyExtension : moo -> extensible_type diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index e20b3b601b..0cdf843a34 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -13,6 +13,5 @@ 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t 319 val Main.List.empty : 'a t * 'b t $ export OCAMLRUNPARAM=b -This is a bug in the parser, there should be results (TODO fix it) $ sherlodoc ": (int, 'a) result" - [No results] + val Main.ok_zero : (int, 'a) result diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index abc22f06df..d5f7b7fd64 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 5.2M sherlodoc.js + 5.1M sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html From 24879e3b16556a007fbd1e9c3df86793cf35d314 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 18 Dec 2023 18:40:49 +0100 Subject: [PATCH 194/285] fix tests --- test/cram/cli.t/run.t | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 735dcbae77..3853c3983a 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -29,7 +29,7 @@ val Main.Map.to_list : foo val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo - doc + doc $ sherlodoc "map" mod Main.Map val Main.List.map : ('a -> 'b) -> 'a t -> 'b t @@ -81,7 +81,7 @@ val Main.Nest.nesting_priority : foo cons Main.MyExtension : moo -> extensible_type val Main.foo : foo - doc + doc $ sherlodoc "qwertyuiopasdfghjklzxcvbnm" [No results] $ sherlodoc "hidden" @@ -104,12 +104,10 @@ TODO : get a result for the query bellow val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc ": ('a -> 'b) -> 'a t -> 'b t" - : ('a -> 'b) -> 'a t -> 'b t val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t TODO : get a result for the query bellow $ sherlodoc ": 'a bo" - : 'a bo val Main.poly_param : 'a boo $ sherlodoc ":extensible_type" cons Main.MyExtension : moo -> extensible_type From 1d03b3e75f61b5f7cd1a6ae685a21c4dd7b67a5b Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 18 Dec 2023 18:47:26 +0100 Subject: [PATCH 195/285] new parser works on partial queries --- db/dune | 1 - db/typexpr.ml | 1 - db/typexpr.mli | 2 +- query/dune | 1 - query/test/test_succ.ml | 4 +--- query/test/test_type_parser.ml | 2 +- query/type_parser.ml | 14 +++++++++----- test/cram/base.t/run.t | 6 +++--- test/cram/query_syntax.t/main.mli | 0 test/cram/query_syntax.t/run.t | 17 +++++++++++++++++ 10 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 test/cram/query_syntax.t/main.mli create mode 100644 test/cram/query_syntax.t/run.t diff --git a/db/dune b/db/dune index 83acfde513..4899646a37 100644 --- a/db/dune +++ b/db/dune @@ -2,5 +2,4 @@ (library (name db) - (preprocess(pps ppx_deriving.show)) (libraries unix dum)) diff --git a/db/typexpr.ml b/db/typexpr.ml index 1b35683707..e02c9a638e 100644 --- a/db/typexpr.ml +++ b/db/typexpr.ml @@ -5,7 +5,6 @@ type t = | Poly of string | Any | Unhandled -[@@deriving show] let table = Hashtbl.create 256 diff --git a/db/typexpr.mli b/db/typexpr.mli index fabceaa0fb..592c06ab01 100644 --- a/db/typexpr.mli +++ b/db/typexpr.mli @@ -5,7 +5,6 @@ type t = private | Poly of string | Any | Unhandled - [@@deriving show] val arrow : t -> t -> t val constr : string -> t list -> t @@ -14,3 +13,4 @@ val poly : string -> t val any : t val unhandled : t val size : t -> int +val show : t -> string diff --git a/query/dune b/query/dune index 5b3efcaedd..40292f5b99 100644 --- a/query/dune +++ b/query/dune @@ -6,4 +6,3 @@ (libraries lwt re db)) (ocamllex type_lexer) - diff --git a/query/test/test_succ.ml b/query/test/test_succ.ml index e80f22c2b5..9341f7f9b2 100644 --- a/query/test/test_succ.ml +++ b/query/test/test_succ.ml @@ -1,12 +1,10 @@ open Query.Private - - (** This module does the same thing as Succ, but its correctness is obvious +(** This module does the same thing as Succ, but its correctness is obvious and its performance terrible. *) module Reference = struct include Set.Make (Int) - let of_array arr = arr |> Array.to_seq |> of_seq let to_seq ~compare:_ = to_seq end diff --git a/query/test/test_type_parser.ml b/query/test/test_type_parser.ml index d6f55599fb..285209520e 100644 --- a/query/test/test_type_parser.ml +++ b/query/test/test_type_parser.ml @@ -20,7 +20,7 @@ let rec random_type size = and random_constr_params n = constr (random_elt [| "list"; "option"; "t"; "result"; "array" |]) - (List.init (n-1) (fun i -> random_type i)) + (List.init (n - 1) (fun i -> random_type i)) open Query.Private diff --git a/query/type_parser.ml b/query/type_parser.ml index de6b1f99e7..057500f8a2 100644 --- a/query/type_parser.ml +++ b/query/type_parser.ml @@ -50,6 +50,7 @@ open Tokens_gen let rec typ tokens = match peek tokens with + | EOF -> any | ARROW -> discard tokens ; typ tokens @@ -88,6 +89,7 @@ and parens tokens = | WORD w -> constr w params | _ -> error "parens 1") | PARENS_CLOSE -> typ + | EOF -> any | _ -> error "parens 2" and params tokens = @@ -100,14 +102,16 @@ and params tokens = and constr_one_param tokens = match peek tokens with | WORD w -> - discard tokens; - fun typ -> constr w [typ] + discard tokens ; + fun typ -> constr w [ typ ] | _ -> Fun.id and typ1 tokens = - let typ = typ0 tokens in - constr_one_param tokens typ - + match peek tokens with + | EOF -> any + | _ -> + let typ = typ0 tokens in + constr_one_param tokens typ and typ0 tokens = match get tokens with diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index eb90d545af..42f51908e5 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,9 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.316s - user 0m1.266s - sys 0m0.043s + real 0m1.103s + user 0m1.063s + sys 0m0.037s diff --git a/test/cram/query_syntax.t/main.mli b/test/cram/query_syntax.t/main.mli new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/cram/query_syntax.t/run.t b/test/cram/query_syntax.t/run.t new file mode 100644 index 0000000000..41c4f18376 --- /dev/null +++ b/test/cram/query_syntax.t/run.t @@ -0,0 +1,17 @@ + $ ocamlc -c main.mli -bin-annot -I . + $ odoc compile -I . main.cmti + $ odoc link -I . main.odoc + $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') + $ export SHERLODOC_DB=db.bin + $ sherlodoc --pretty-query ": ->" + : _ + [No results] + $ sherlodoc --pretty-query ": int ->" + : int -> _ + [No results] + $ sherlodoc --pretty-query ": int *" + : int * _ + [No results] + $ sherlodoc --pretty-query ": string -> (" + : string -> _ + [No results] From 1dce4746d5890570c6b1764a1c22e21ed96a9214 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 11:46:10 +0100 Subject: [PATCH 196/285] better type parser tests --- query/test/test_type_parser.ml | 6 ++++-- query/type_parser.ml | 2 +- test/cram/base.t/run.t | 6 +++--- test/cram/query_syntax.t/run.t | 6 ++++++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/query/test/test_type_parser.ml b/query/test/test_type_parser.ml index 285209520e..595acea72f 100644 --- a/query/test/test_type_parser.ml +++ b/query/test/test_type_parser.ml @@ -13,14 +13,16 @@ let rec random_type size = | _ when Random.int 100 < 20 -> let n = 2 + Random.int 3 in tuple (List.init n (fun _i -> random_type (size / n))) + | _ when Random.int 100 < 5 -> random_constr_params size | _ -> let size = size / 2 in arrow (random_type size) (random_type size) -and random_constr_params n = +and random_constr_params size = + let n_params = 1 + Random.int 3 in constr (random_elt [| "list"; "option"; "t"; "result"; "array" |]) - (List.init (n - 1) (fun i -> random_type i)) + (List.init n_params (fun _i -> random_type (size / n_params))) open Query.Private diff --git a/query/type_parser.ml b/query/type_parser.ml index 057500f8a2..76bfdfe59f 100644 --- a/query/type_parser.ml +++ b/query/type_parser.ml @@ -103,7 +103,7 @@ and constr_one_param tokens = match peek tokens with | WORD w -> discard tokens ; - fun typ -> constr w [ typ ] + fun typ -> constr_one_param tokens @@ constr w [ typ ] | _ -> Fun.id and typ1 tokens = diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 42f51908e5..56b6d6bcc9 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,9 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.103s - user 0m1.063s - sys 0m0.037s + real 0m1.235s + user 0m1.181s + sys 0m0.050s diff --git a/test/cram/query_syntax.t/run.t b/test/cram/query_syntax.t/run.t index 41c4f18376..1a5abbf92b 100644 --- a/test/cram/query_syntax.t/run.t +++ b/test/cram/query_syntax.t/run.t @@ -3,6 +3,9 @@ $ odoc link -I . main.odoc $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') $ export SHERLODOC_DB=db.bin + $ sherlodoc --pretty-query ": int list option" + : int list option + [No results] $ sherlodoc --pretty-query ": ->" : _ [No results] @@ -15,3 +18,6 @@ $ sherlodoc --pretty-query ": string -> (" : string -> _ [No results] + $ sherlodoc --pretty-query ": (int" + : _ + [No results] From fd308b801126e458fab76222a90fe0d00a78924e Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 11:47:42 +0100 Subject: [PATCH 197/285] better tests --- query/type_parser.ml | 2 +- test/cram/base.t/run.t | 6 +++--- test/cram/query_syntax.t/run.t | 10 +++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/query/type_parser.ml b/query/type_parser.ml index 76bfdfe59f..d9f8901c26 100644 --- a/query/type_parser.ml +++ b/query/type_parser.ml @@ -89,7 +89,7 @@ and parens tokens = | WORD w -> constr w params | _ -> error "parens 1") | PARENS_CLOSE -> typ - | EOF -> any + | EOF -> typ | _ -> error "parens 2" and params tokens = diff --git a/test/cram/base.t/run.t b/test/cram/base.t/run.t index 56b6d6bcc9..3b824faf32 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base.t/run.t @@ -10,9 +10,9 @@ 4.8M megaodocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.235s - user 0m1.181s - sys 0m0.050s + real 0m1.158s + user 0m1.113s + sys 0m0.043s diff --git a/test/cram/query_syntax.t/run.t b/test/cram/query_syntax.t/run.t index 1a5abbf92b..095ca01955 100644 --- a/test/cram/query_syntax.t/run.t +++ b/test/cram/query_syntax.t/run.t @@ -19,5 +19,13 @@ : string -> _ [No results] $ sherlodoc --pretty-query ": (int" - : _ + : int + [No results] + $ sherlodoc --pretty-query ": (int ->" + : int -> _ + [No results] + $ sherlodoc --pretty-query ": (int *" + : int * _ [No results] + + From 37e7ebf5b2ed946de74125927dd22df0304ac742 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 11:48:54 +0100 Subject: [PATCH 198/285] bigger size tests --- query/test/test_type_parser.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query/test/test_type_parser.ml b/query/test/test_type_parser.ml index 595acea72f..4bdf103480 100644 --- a/query/test/test_type_parser.ml +++ b/query/test/test_type_parser.ml @@ -34,7 +34,7 @@ let test_parser typ () = let tests = List.init 50 (fun i -> - let i = i in + let i = i * 5 in let typ = random_type i in Alcotest.test_case (Printf.sprintf "Type_parser size %i" i) From 97e2eb1b29d733b1ba78832f135b6b9eff606248 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 12:15:38 +0100 Subject: [PATCH 199/285] delete useless files from jsoo --- jsoo/index.html | 17 -------------- jsoo/result.db | Bin 1718 -> 0 bytes jsoo/style.css | 58 ------------------------------------------------ 3 files changed, 75 deletions(-) delete mode 100644 jsoo/index.html delete mode 100644 jsoo/result.db delete mode 100644 jsoo/style.css diff --git a/jsoo/index.html b/jsoo/index.html deleted file mode 100644 index ca72ff23a2..0000000000 --- a/jsoo/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - JSherlodoc - - - - - diff --git a/jsoo/result.db b/jsoo/result.db deleted file mode 100644 index 5f0b025234f8df7e198bd16eff7b13e07eef4ee4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1718 zcmah}&x;&I6s~SwZCC>dh@xl+nd$ABolO{jBpbX)s&^A1!mgt$A=ldJ+OeRzd$ziJ zNG_iI1D1u{iyU&#VXt9M@gg`NUc^H{f_hLv)QdmxbyxN5uzSeBW2(Bo_r3SN_o}{l z@aPF4OAiV0KPTkO8m^z4$LwInqUn@9`>3}jzlv`B}d-XEtVa; zc$ZhhESw7Aekt>27IM^8IQ{2%oKYMXSMtfoopGt>owzc4b*ly(P3QP+}+oEtVs#&m`1x4^4_8Ftzm(^48>E+|A{4Vu=HimjXq5X*0nR-vD z_ch-4MbK61{Z@f~Mf;@&eMP-*PcU7h-d`2yPqaU3&^Ofk{sd^9djD3Sf6)G}LElmD z2NrE?-el2i#;Et7VbzO9{blMspF#`Xm@;?;?VLlgi26&&;V&^bGh_C>qy9?_&LRRI zL@bf|uOiI*9hcB&5v<~W8|^~PF~c8AjUlNa(hzP)!lrPZ`eX{{U>$L9q4iumjljeZ zVTd*)GejA5Tl8db8*^v*i*bVrhp+RC`0iA=@-z;vV_tVzRA+{H!#Z5UQZP4IuB(0z zYt@KJ&_-z7)qrKf4S2u8Dg)aHs)Xgx8Qk8@L3ovkfvar!=AdJ@nlC;D49pf9L=J diff --git a/jsoo/style.css b/jsoo/style.css deleted file mode 100644 index 0a6c2aaf31..0000000000 --- a/jsoo/style.css +++ /dev/null @@ -1,58 +0,0 @@ -body { - margin: 2em; -} - -#search-bar { - border: 1px solid black; -} - -#search-bar input#search { - margin: 0.5em 1em; - font-family: monospace; - width: 40%; -} - -.result { - max-height: 2rem; - overflow: hidden; - padding: 0 1em; -} - -.result > code { - margin: 0; - padding: 0 0; - font-size: 1.2em; - line-height: 2rem; - vertical-align: center; - display: inline-block; - width: 40%; - float: left; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.result > code em { - font-weight: bold; - font-style: normal; -} - -.result .docstring { - display: inline-block; - line-height: 2rem; - width: 60%; - font-style: italic; -} - -.result .docstring p { - margin: 0; - padding: 0; - padding-left: 2em; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.result:nth-child(odd) { - background: #eee; -} From 98d1e91a35efcc4a9ef02905ac1680583696cdb5 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 13:56:08 +0100 Subject: [PATCH 200/285] separate tests on base --- .../cram/base.t/base_internalhash_types.odocl | Bin 3125 -> 0 bytes test/cram/base_benchmark.t | 18 ++ test/cram/{base.t/run.t => base_cli.t} | 183 +++++++++++------- .../base_odocls/base_internalhash_types.odocl | Bin 0 -> 3119 bytes test/cram/{base.t => base_odocls}/caml.odocl | Bin 28624 -> 28618 bytes .../{base.t => base_odocls}/md5_lib.odocl | Bin 2256 -> 2250 bytes .../{base.t => base_odocls}/page-index.odocl | Bin 36966 -> 36960 bytes .../shadow_stdlib.odocl | Bin 81027 -> 81021 bytes test/cram/base_web.t | 47 +++++ test/cram/dune | 2 +- 10 files changed, 177 insertions(+), 73 deletions(-) delete mode 100644 test/cram/base.t/base_internalhash_types.odocl create mode 100644 test/cram/base_benchmark.t rename test/cram/{base.t/run.t => base_cli.t} (62%) create mode 100644 test/cram/base_odocls/base_internalhash_types.odocl rename test/cram/{base.t => base_odocls}/caml.odocl (96%) rename test/cram/{base.t => base_odocls}/md5_lib.odocl (79%) rename test/cram/{base.t => base_odocls}/page-index.odocl (94%) rename test/cram/{base.t => base_odocls}/shadow_stdlib.odocl (99%) create mode 100644 test/cram/base_web.t diff --git a/test/cram/base.t/base_internalhash_types.odocl b/test/cram/base.t/base_internalhash_types.odocl deleted file mode 100644 index 1e7621ab4ad1ae95c242683eb59de0228dd99653..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3125 zcmcguYitx%6rLG(YKKP@u>mw7eQfD-x1>;zfX=-a< z-?!hMbG~!V++8DWr0S#54a?WHtyh4|qW36PPr~lasg_W3y}3i0Z6?NeKjwX& zL?UuSRprbd%98tc?w-_o@aEo~`&cy--{3f5EyooXaooe($vedyH;?-tY6^TuCOeVh z@jIC~(n*9TWZ_aJqYrgxg<)nC8=9h}tiFZ=2U5#Bd-wlb{Nv)*qir9Q5K`G@r*$pa z*U&p~G_&34n66}eFIW;(BHUars8x0qx3$O(WO|t$H=I0HKXZjywxse+ylyv~zO$pQ@wWqqANsq2zhAQ96$JUnQTZq6_kydl zz9*4-Cu-S>tqM&?o;@K|*$EfL9yDN?kb%e)f|e1?wG-jqk^3!_nHDJ`Xf+W^ubo-U z;!<`d<r??CNK`lghda(XxnPyS0ni6P@uZaO5Xam#C0Xte&O;h1~%AyWm zxCj728@*tP8w^nbb@`eV00?@KX-X9u<^_t;OTJ_s0D@9pJ}aN3>rRCbC`C}(7j6PT zP`8)Q=%yN#5@@rp*#dwdo%Nv{c7%$yQ3hpvQ2_u!CJPkJTUvHAmAy(iWcjk!0T5JR zvU0n}Eou*C&~{(69{@p|%ref&nOXs6O2Zv=X~ZF4`#vzxAZ`^4S+!N|-ENra7*!v3 zdBipQ>V9CF;ds-kSl`3u^@+B1x!1f4kj(r z+y@S$e*8n0o=Q&}kBl2@8g|`K1n*b5q%Vbq4Ba?&6g}N5`C6vcI0xbqa@GhpUuzM8d zdllvIYk{r>5L^v-SnhV0!`#w9*#*>6IL{5mWY3+*D=vw-m4O!ez^#PijhbB@A`d2k z!kj;8kvA!%G2ABAXqk+f*5Hwd$+CP}Mtw(!@Jn*xbRwL+a()k7hPNj*UUKM@D$Mx$ z1YeypOx31WFv$OXU5fliPKBkaX<^#O`wmHS;JO6x;MMgMC?rDcgOl}< z>Zq1hv$kgU%JOkJ)YC|H7>j&=xQaoirrXfdw8>5Lgrc>}{*>wqiGUhU{>3AIg#-ac zlqB*ehgUf?`6#QRG?^Hz^=IESZ@7gsVGF-IRYU0n;n;$^Qf**hJmoJMyZlj#|898k zk@WETE`{n7B(KHYx}n&@BbS}2ev4gdJT;EhVmH7jRo)n0rQc#!Mb&ldme*nyBD6Ik zeeRX|wrmr=ABA|woViUV`9k|jb;%>x)8*%TvU36l)NQ2*0D|Tf`okt wQ^G!w6Wa_oO7JWT(__cBNOKE`Fg+eO((I9T!cj(XR2tru$cM6w+&@|V2d}&Jng9R* diff --git a/test/cram/base_benchmark.t b/test/cram/base_benchmark.t new file mode 100644 index 0000000000..baa8c07c88 --- /dev/null +++ b/test/cram/base_benchmark.t @@ -0,0 +1,18 @@ + $ find . -name '*.odocl' | sort + ./base_odocls/base.odocl + ./base_odocls/base_internalhash_types.odocl + ./base_odocls/caml.odocl + ./base_odocls/md5_lib.odocl + ./base_odocls/page-index.odocl + ./base_odocls/shadow_stdlib.odocl + $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + + real 0m1.449s + user 0m1.407s + sys 0m0.037s + + + + + + diff --git a/test/cram/base.t/run.t b/test/cram/base_cli.t similarity index 62% rename from test/cram/base.t/run.t rename to test/cram/base_cli.t index 3b824faf32..ab1f454d49 100644 --- a/test/cram/base.t/run.t +++ b/test/cram/base_cli.t @@ -1,76 +1,10 @@ $ find . -name '*.odocl' | sort - ./base.odocl - ./base_internalhash_types.odocl - ./caml.odocl - ./md5_lib.odocl - ./page-index.odocl - ./shadow_stdlib.odocl - $ cat $(find . -name '*.odocl') > megaodocl - $ du -sh megaodocl - 4.8M megaodocl - $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - - real 0m1.158s - user 0m1.113s - sys 0m0.043s - - - - - - - - - - - - - - - - - - - - - -$ sherlodoc_index --format=js --empty-payload --db=db_empty_payload.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --index-docstring=false --db=db_no_docstring.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --index-name=false --db=db_no_name.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --type-search=false --db=db_no_type.js $(find . -name '*.odocl') 2> /dev/null -$ sherlodoc_index --format=js --type-search=false --empty-payload --index-docstring=false --db=db_only_names.js $(find . -name '*.odocl') 2> /dev/null - - $ gzip -k db.js - - $ gzip -k megaodocl - - $ du -s *.js *.gz - 2644 db.js - 1996 db.js.gz - 1544 megaodocl.gz - - - $ for f in $(find . -name '*.odocl'); do - > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f - > done - $ odoc support-files -o html - $ cp db.js html/ - $ cp ../../../jsoo/main.bc.js html/sherlodoc.js - $ du -sh html/sherlodoc.js - 5.1M html/sherlodoc.js - $ ls html - base - db.js - fonts - highlight.pack.js - katex.min.css - katex.min.js - odoc.css - odoc_search.js - sherlodoc.js -indent to see results -$ cp -r html /tmp -$ firefox /tmp/html/base/index.html + ./base_odocls/base.odocl + ./base_odocls/base_internalhash_types.odocl + ./base_odocls/caml.odocl + ./base_odocls/md5_lib.odocl + ./base_odocls/page-index.odocl + ./base_odocls/shadow_stdlib.odocl $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin --limit 100 "S_poly" 115 sig Base.Map.S_poly @@ -263,3 +197,108 @@ $ firefox /tmp/html/base/index.html $ sherlodoc --no-rhs --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group + $ sherlodoc --print-cost --db=db_marshal.bin "list" + 109 mod Base.List + 109 mod Caml.List + 118 mod Shadow_stdlib.List + 209 type 'a Base.list = 'a List.t + 216 type 'a Base.Export.list = 'a List.t + 217 val Base.List.map : 'a t -> f:('a -> 'b) -> 'b t + 217 val Base.List.mem : 'a t -> 'a -> equal:('a -> 'a -> bool) -> bool + 217 val Base.List.rev : 'a t -> 'a t + 217 val Base.List.sub : 'a t -> pos:int -> len:int -> 'a t + 217 val Base.List.sum : (module Container.Summable with type t = 'sum) -> + 'a t -> + f:('a -> 'sum) -> + 'sum + 218 val Base.List.bind : 'a t -> f:('a -> 'b t) -> 'b t + 218 val Base.List.drop : 'a t -> int -> 'a t + 218 val Base.List.find : 'a t -> f:('a -> bool) -> 'a option + 218 val Base.List.fold : 'a t -> init:'acc -> f:('acc -> 'a -> 'acc) -> 'acc + 218 val Base.List.init : int -> f:(int -> 'a) -> 'a t + 218 val Base.List.join : 'a t t -> 'a t + 218 val Base.List.last : 'a t -> 'a option + 218 val Base.List.mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t + 218 val Base.List.sort : 'a t -> compare:('a -> 'a -> int) -> 'a t + 218 val Base.List.take : 'a t -> int -> 'a t + 219 val Base.List.(>>|) : 'a t -> ('a -> 'b) -> 'b t + 219 mod Base.List.Assoc + 219 mod Base.List.Infix + 219 val Base.List.count : 'a t -> f:('a -> bool) -> int + 219 mod Base.ListLabels + 219 mod Caml.ListLabels + 219 val Base.Set.to_list : ('a, _) t -> 'a list + 220 val Base.List.append : 'a t -> 'a t -> 'a t + 220 val Base.List.concat : 'a t t -> 'a t + 220 val Base.List.hd_exn : 'a t -> 'a + 220 val Base.List.return : 'a -> 'a t + 220 val Base.List.tl_exn : 'a t -> 'a t + 221 val Base.List.nth_exn : 'a t -> int -> 'a + 221 val Base.Bytes.to_list : t -> char list + 221 val Base.Queue.of_list : 'a list -> 'a t + 221 val Base.Stack.of_list : 'a list -> 'a t + 224 mod Base.List.Let_syntax + 225 mod Base.List.Monad_infix + 228 mod Shadow_stdlib.ListLabels + 315 type 'a Base.List.t = 'a list + 316 val Base.List.hd : 'a t -> 'a option + 318 val Base.equal_list : 'a. ('a -> 'a -> bool) -> 'a list -> 'a list -> bool + 320 val Base.compare_list : 'a. ('a -> 'a -> int) -> 'a list -> 'a list -> int + 320 val Base.sexp_of_list : 'a. ('a -> Sexplib0.Sexp.t) -> 'a list -> Sexplib0.Sexp.t + 321 type ('a, 'b) Base.List.Assoc.t = ('a * 'b) list + 321 val Base.list_of_sexp : 'a. (Sexplib0.Sexp.t -> 'a) -> Sexplib0.Sexp.t -> 'a list + 322 val Base.globalize_list : 'a. ('a -> 'a) -> 'a list -> 'a list + 322 val Base.hash_fold_list : 'a. (Hash.state -> 'a -> Hash.state) -> Hash.state -> 'a list -> Hash.state + 623 val Base.Queue.S.of_list : 'a list -> 'a t + 623 val Base.Stack.S.of_list : 'a list -> 'a t + $ sherlodoc --print-cost --db=db_marshal.bin ": list" + 116 val Base.Map.data : (_, 'v, _) t -> 'v list + 116 val Base.Map.keys : ('k, _, _) t -> 'k list + 118 val Base.Set.to_list : ('a, _) t -> 'a list + 119 val Base.Hashtbl.data : (_, 'b) t -> 'b list + 119 val Base.Hashtbl.keys : ('a, _) t -> 'a key list + 119 val Base.Set.elements : ('a, _) t -> 'a list + 119 val Base.String.split : t -> on:char -> t list + 119 val Base.Bytes.to_list : t -> char list + 121 val Base.Map.to_alist : ?key_order:[ `Increasing | `Decreasing ] -> ('k, 'v, _) t -> ('k * 'v) list + 123 val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + 123 val Base.Map.find_multi : ('k, 'v list, 'cmp) t -> 'k -> 'v list + 124 val Base.Hashtbl.to_alist : ('a, 'b) t -> ('a key * 'b) list + 124 val Base.Hashtbl.Poly.data : (_, 'b) t -> 'b list + 124 val Base.Pretty_printer.all : unit -> string list + 124 val Base.String.split_lines : t -> t list + 124 val Base.String.to_list_rev : t -> char list + 126 val Base.Sequence.to_list_rev : 'a t -> 'a list + 210 val Caml.(@) : 'a list -> 'a list -> 'a list + 213 val Base.Bool.all : t list + 213 val Base.Char.all : t list + 213 val Base.Sign.all : t list + 213 val Base.Unit.all : t list + 216 val Base.Nothing.all : t list + 217 val Base.Ordering.all : t list + 218 val Base.List.to_list : 'a t -> 'a list + 219 val Shadow_stdlib.(@) : 'a list -> 'a list -> 'a list + 219 val Base.Array.to_list : 'a t -> 'a list + 219 val Base.Queue.to_list : 'a t -> 'a list + 219 val Base.Stack.to_list : 'a t -> 'a list + 220 val Base.Map.Poly.data : (_, 'v) t -> 'v list + 220 val Base.Map.Poly.keys : ('k, _) t -> 'k list + 220 val Base.Option.to_list : 'a t -> 'a list + 220 val Base.String.to_list : t -> elt list + 220 val Base.Float.Class.all : t list + 220 val Base.Sign_or_nan.all : t list + 221 val Base.Lazy.all : 'a t list -> 'a list t + 221 val Base.List.all : 'a t list -> 'a list t + 222 val Base.Sequence.to_list : 'a t -> 'a list + 222 val Base.Set.Poly.to_list : 'a t -> 'a list + 223 val Base.Option.all : 'a t list -> 'a list t + 225 val Base.Result.all : ('a, 'e) t list -> ('a list, 'e) t + 227 val Base.Monad.Make.all : 'a X.t list -> 'a list X.t + 526 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list + 526 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + 621 val Base.Queue.S.to_list : 'a t -> 'a list + 621 val Base.Stack.S.to_list : 'a t -> 'a list + 622 val Base.Map.S_poly.data : (_, 'v) t -> 'v list + 622 val Base.Map.S_poly.keys : ('k, _) t -> 'k list + 624 val Base.Monad.S.all : 'a t list -> 'a list t + 627 val Base.Monad.S2.all : ('a, 'e) t list -> ('a list, 'e) t diff --git a/test/cram/base_odocls/base_internalhash_types.odocl b/test/cram/base_odocls/base_internalhash_types.odocl new file mode 100644 index 0000000000000000000000000000000000000000..74916f84bd0be14f7f9d6ea9ea2bedc89ef7b144 GIT binary patch literal 3119 zcmcguU2GIp6rLG(YKNaFVgqPE`m?3KyNfLa3FzDlA{2!pl$L5(XLqM`V0LGjnO#yu zOwj9Ei)ab6BwoUv8*n|;yp%IjjLHrSL1D_u~|*qR@_KK zDelMO$y7npGx3bttrT=Saq`yohNj>49lY=F1b??|{mTgQk;C#&(C_(|XMIm1jZW0E z65^?Q*&=bJ4!|7ns3e9cM8J9s^ zr?2}4m`*rdo=(ZpBENMRywsNs5)6CT%0$&hUfEi3y ztpWsB10I&U-Q_U1Bv5t%wFJ&HLowNNC-RC*Vs3e$g+6f0;drBFSBJ=hNuV(2Pg>+n z3TX_tNp)H_t7bHKBx15GpOjJGAtL;eS}>gmr!Sq|4VU4~Nlh0V`lJdozCOm+rVUfI z=@ks}e_xj(|B+K=scJ@;_VJzr(j2%h0o?nxq)Fv)(#X^iu|IR_+;4)Sq8C)5Y~xE^ zQlp&=sQ;FyoaTA&9GE|R+uDu;R+sSRV1?+;fo=+t!^dWJT+rCBIhv-D4?v6u{~@#J4L@>fU@U_?nGe|&hA zLz9oPD#}yI!Fqr8EzQF%oC;g`-KiN$CkRL8-vRRs2Oor+4xRGX$v=fdpilg%Iu0%eRW#slctKDgKP5j|S5-C4H7MBA-%nL_Bi8{A0Bhw3+yDRo diff --git a/test/cram/base.t/page-index.odocl b/test/cram/base_odocls/page-index.odocl similarity index 94% rename from test/cram/base.t/page-index.odocl rename to test/cram/base_odocls/page-index.odocl index a9b23f6961110d20199ba109a796c24108fb866d..612207c84c9c4d4b1a67a16db6bda0c2f276f8f5 100644 GIT binary patch delta 21 ccmaF1fa$>kCa(OH{A67tJrg~HjRIj409)P%fB*mh delta 27 icmaE`fa%!+CV~8v{A68K)iBqfU{8NPRn?7LVG{t3Q3*%@ diff --git a/test/cram/base.t/shadow_stdlib.odocl b/test/cram/base_odocls/shadow_stdlib.odocl similarity index 99% rename from test/cram/base.t/shadow_stdlib.odocl rename to test/cram/base_odocls/shadow_stdlib.odocl index ee36e459420e1ca1aa260b24ba7b7b49b52103b8..f7b78fc841d24b98fc24923077d8e929a4efc5a3 100644 GIT binary patch delta 24 fcmZqv$@2FH3s-(hezLBSo{648qrg@H#$p=)dRPcf delta 30 lcmezSgQfW=i$H!#ezLBrYM5(Ku&2MDs%j(GRxZY38vwQ<3J?GQ diff --git a/test/cram/base_web.t b/test/cram/base_web.t new file mode 100644 index 0000000000..5ba088f197 --- /dev/null +++ b/test/cram/base_web.t @@ -0,0 +1,47 @@ + $ find . -name '*.odocl' | sort + ./base_odocls/base.odocl + ./base_odocls/base_internalhash_types.odocl + ./base_odocls/caml.odocl + ./base_odocls/md5_lib.odocl + ./base_odocls/page-index.odocl + ./base_odocls/shadow_stdlib.odocl + $ cat $(find . -name '*.odocl') > megaodocl + $ du -sh megaodocl + 4.8M megaodocl + $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + + $ gzip -k db.js + +We want to compare the compressed size with the size of the odocl. The search +database contains information than the odocl, but the information is organised +in queryable way, so a size increase is expected. It should just be reasonable. + $ gzip -k megaodocl + + $ du -s *.js *.gz + 2644 db.js + 1996 db.js.gz + 1544 megaodocl.gz + + $ for f in $(find . -name '*.odocl'); do + > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f + > done + $ odoc support-files -o html + $ cp db.js html/ +The --no-preserve flag is here so that copying to /tmp will not fail because of +a previous run. .js files built by dune are read only. + $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js + $ du -sh html/sherlodoc.js + 5.1M html/sherlodoc.js + $ ls html + base + db.js + fonts + highlight.pack.js + katex.min.css + katex.min.js + odoc.css + odoc_search.js + sherlodoc.js +indent to see results +$ cp -r html /tmp +$ firefox /tmp/html/base/index.html diff --git a/test/cram/dune b/test/cram/dune index 5e020b6093..cba60c517c 100644 --- a/test/cram/dune +++ b/test/cram/dune @@ -1,6 +1,6 @@ (cram - (alias runexamples) (deps + (source_tree base_odocls) %{bin:odoc} %{bin:sherlodoc} %{bin:sherlodoc_index} From fa17340c41938ea005e3330bceb8a6a33e9118d6 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 15:42:59 +0100 Subject: [PATCH 201/285] restore menhir parser and handle _ -> int --- db/type_polarity.ml | 25 +++---- db/type_polarity.mli | 6 +- index/load_doc.ml | 2 +- query/dune | 4 ++ query/query.ml | 11 ++- query/query.mli | 5 +- query/query_parser.ml | 7 +- query/type_lexer.mll | 13 +--- query/type_parser.ml | 128 --------------------------------- query/type_parser.mly | 57 +++++++++++++++ review.md | 9 ++- test/cram/base_benchmark.t | 6 +- test/cram/base_web.t | 2 +- test/cram/cli.t/run.t | 1 - test/cram/query_syntax.t/run.t | 7 +- test/cram/simple.t/run.t | 2 +- 16 files changed, 113 insertions(+), 172 deletions(-) delete mode 100644 query/type_parser.ml create mode 100644 query/type_parser.mly diff --git a/db/type_polarity.ml b/db/type_polarity.ml index 94e288f6a3..55a22717e8 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -34,16 +34,16 @@ type t = string * int let all_type_names name = name |> String.split_on_char '.' |> tails |> List.map (String.concat ".") -let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function +let rec of_typ ~any_is_poly ~all_names ~prefix ~sgn = function | Poly _ -> [ Sign.to_string sgn :: "POLY" :: prefix ] | Any -> - if ignore_any - then [ prefix ] - else [ Sign.to_string sgn :: "POLY" :: prefix ] + if any_is_poly + then [ Sign.to_string sgn :: "POLY" :: prefix ] + else [ Sign.to_string sgn :: prefix ] | Arrow (a, b) -> List.rev_append - (of_typ ~ignore_any ~all_names ~prefix ~sgn:(Sign.not sgn) a) - (of_typ ~ignore_any ~all_names ~prefix ~sgn b) + (of_typ ~any_is_poly ~all_names ~prefix ~sgn:(Sign.not sgn) a) + (of_typ ~any_is_poly ~all_names ~prefix ~sgn b) | Constr (name, args) -> name |> (if all_names then all_type_names else fun name -> [ name ]) @@ -57,23 +57,18 @@ let rec of_typ ~ignore_any ~all_names ~prefix ~sgn = function @@ List.mapi (fun i arg -> let prefix = string_of_int i :: prefix in - of_typ ~ignore_any ~all_names ~prefix ~sgn arg) + of_typ ~any_is_poly ~all_names ~prefix ~sgn arg) args end) |> rev_concat | Tuple args -> rev_concat - @@ List.map (of_typ ~ignore_any ~all_names ~prefix ~sgn) + @@ List.map (of_typ ~any_is_poly ~all_names ~prefix ~sgn) @@ args | Unhandled -> [] -(** [of_typ ~ignore_any ~prefix ~sgn t] is a representation of [t] that - encodes the polarity of the elements of the type : in [string -> int] [int] - is positive and [string] negative. - It is registered in the database and search-base type uses this to obtain - results that fit the type asked for by the user. *) -let of_typ ~ignore_any ~all_names t = +let of_typ ~any_is_poly ~all_names t = t - |> of_typ ~ignore_any ~all_names ~prefix:[] ~sgn:Pos + |> of_typ ~any_is_poly ~all_names ~prefix:[] ~sgn:Pos |> List.map (String.concat "") |> regroup diff --git a/db/type_polarity.mli b/db/type_polarity.mli index 90e7ba90af..3f46d9c905 100644 --- a/db/type_polarity.mli +++ b/db/type_polarity.mli @@ -72,12 +72,12 @@ type t = string * int toplevel documentation of the module. *) -val of_typ : ignore_any:bool -> all_names:bool -> Typexpr.t -> t list +val of_typ : any_is_poly:bool -> all_names:bool -> Typexpr.t -> t list (** [of_typ ~ignore_any ~all_names typ] is the list of polarised types corresponding to [typ]. - - If [ignore_any] is true, the type [_] will be ignored, otherwise it will be - treated like a type variable ['a]. + - If [any_is_poly] is true, the type [_] will be treated like a type variable + ['a], other it will be represented solely by its sign ("+" or "-"). - If [all_names] is true, extra polarities are added for every "possible name" of each type constructor. For instance the possible names of diff --git a/index/load_doc.ml b/index/load_doc.ml index 7a0a02c489..12f5fab4fa 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -144,7 +144,7 @@ let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = let register_type_expr ~db elt type_ = let type_polarities = type_ |> typ_of_odoc_typ - |> Db.Type_polarity.of_typ ~ignore_any:false ~all_names:true + |> Db.Type_polarity.of_typ ~any_is_poly:true ~all_names:true in Db.store_type_polarities db elt type_polarities diff --git a/query/dune b/query/dune index 40292f5b99..bb7a30b20e 100644 --- a/query/dune +++ b/query/dune @@ -5,4 +5,8 @@ (name query) (libraries lwt re db)) +(menhir + (modules type_parser) + (flags --explain)) + (ocamllex type_lexer) diff --git a/query/query.ml b/query/query.ml index 08de5d4da5..7a54e4b211 100644 --- a/query/query.ml +++ b/query/query.ml @@ -8,7 +8,12 @@ module Occ = Db.Occ module Private = struct module Array_succ = Array_succ module Succ = Succ - module Type_parser = Type_parser + + module Type_parser = struct + let of_string str = + let lexbuf = Lexing.from_string str in + Ok (Type_parser.main Type_lexer.token lexbuf) + end end let collapse_occ ~count occs = @@ -26,10 +31,12 @@ let collapse_trie t = let polarities typ = List.filter (fun (word, _count) -> String.length word > 0) - (Db.Type_polarity.of_typ ~ignore_any:true ~all_names:false typ) + (Db.Type_polarity.of_typ ~any_is_poly:false ~all_names:false typ) let find_types ~shards typ = let polarities = polarities typ in + if polarities = [] + then failwith "Query.find_types : type with empty polarities" ; List.fold_left (fun acc shard -> let db = Db.(shard.db_types) in diff --git a/query/query.mli b/query/query.mli index e53d93fdca..468a4567cc 100644 --- a/query/query.mli +++ b/query/query.mli @@ -36,5 +36,8 @@ val pretty : t -> string module Private : sig module Array_succ = Array_succ module Succ = Succ - module Type_parser = Type_parser + + module Type_parser : sig + val of_string : string -> (Db.Typexpr.t, string) result + end end diff --git a/query/query_parser.ml b/query/query_parser.ml index 78ab7aa3e0..e9ba7072ff 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -1,4 +1,7 @@ -let parse str = Type_parser.of_string str +let type_of_string str = + let lexbuf = Lexing.from_string str in + try Ok (Type_parser.main Type_lexer.token lexbuf) + with Type_parser.Error -> Error "parse error" let naive_of_string str = List.filter (fun s -> String.length s > 0) (String.split_on_char ' ' str) @@ -18,7 +21,7 @@ let of_string str = let typ = Result.bind str_typ (fun str_typ -> - match parse str_typ with + match type_of_string str_typ with | Ok Any -> Error `any | Ok typ -> Ok typ | Error _ -> Error `parse) diff --git a/query/type_lexer.mll b/query/type_lexer.mll index e5e126b7b3..eb2d1f5ac9 100644 --- a/query/type_lexer.mll +++ b/query/type_lexer.mll @@ -1,16 +1,7 @@ -(* This is the lexer for the [parser.mly]. *) +(* This is the lexer for [type_parser.mly]. *) { - type token = - | ARROW - | PARENS_OPEN - | PARENS_CLOSE - | COMMA - | ANY - | STAR - | POLY of string - | WORD of string - | EOF +open Type_parser } rule token = parse diff --git a/query/type_parser.ml b/query/type_parser.ml deleted file mode 100644 index d9f8901c26..0000000000 --- a/query/type_parser.ml +++ /dev/null @@ -1,128 +0,0 @@ -exception Parse_error of string - -let error str = raise (Parse_error str) -let errorf a = Format.kasprintf error a - -open Type_lexer -open Db.Typexpr - -type a = int * float -> string - -let pp_token f t = - Format.pp_print_string f - (match t with - | ARROW -> "ARROW" - | PARENS_OPEN -> "PARENS_OPEN" - | PARENS_CLOSE -> "PARENS_CLOSE" - | COMMA -> "COMMA" - | ANY -> "ANY" - | STAR -> "STAR" - | POLY p -> Printf.sprintf "POLY %s" p - | WORD w -> Printf.sprintf "WORD %s" w - | EOF -> "EOF") - -module Tokens_gen = struct - type t = - { lexer : Lexing.lexbuf -> token - ; lexbuf : Lexing.lexbuf - ; mutable peeked : token option - } - - let get ({ lexer; lexbuf; peeked } as t) = - match peeked with - | None -> lexer lexbuf - | Some token -> - t.peeked <- None ; - token - - let discard t = ignore (get t) - - let peek t = - match t.peeked with - | Some token -> token - | None -> - let token = get t in - t.peeked <- Some token ; - token -end - -open Tokens_gen - -let rec typ tokens = - match peek tokens with - | EOF -> any - | ARROW -> - discard tokens ; - typ tokens - | _ -> ( - let typ_left = typ2 tokens in - match peek tokens with - | ARROW -> - discard tokens ; - let typ_right = typ tokens in - arrow typ_left typ_right - | EOF -> typ_left - | PARENS_CLOSE | COMMA -> typ_left - | _ -> error "typ") - -and typ2 tokens = - let typ = typ1 tokens in - let tups = tups tokens in - match tups with - | [] -> typ - | _ :: _ -> tuple (typ :: tups) - -and tups tokens = - match peek tokens with - | STAR -> - discard tokens ; - let typ = typ1 tokens in - typ :: tups tokens - | _ -> [] - -and parens tokens = - let typ = typ tokens in - match get tokens with - | COMMA -> ( - let params = typ :: params tokens in - match get tokens with - | WORD w -> constr w params - | _ -> error "parens 1") - | PARENS_CLOSE -> typ - | EOF -> typ - | _ -> error "parens 2" - -and params tokens = - let typ = typ tokens in - match get tokens with - | COMMA -> typ :: params tokens - | PARENS_CLOSE -> [ typ ] - | tok -> errorf "params %a" pp_token tok - -and constr_one_param tokens = - match peek tokens with - | WORD w -> - discard tokens ; - fun typ -> constr_one_param tokens @@ constr w [ typ ] - | _ -> Fun.id - -and typ1 tokens = - match peek tokens with - | EOF -> any - | _ -> - let typ = typ0 tokens in - constr_one_param tokens typ - -and typ0 tokens = - match get tokens with - | ANY -> any - | POLY w -> poly w - | WORD w -> constr w [] - | PARENS_OPEN -> parens tokens - | _ -> error "typ0" - -let of_string str = - let tokens = - { lexbuf = Lexing.from_string str; lexer = Type_lexer.token; peeked = None } - in - try Ok (typ tokens) with Parse_error msg -> Error msg diff --git a/query/type_parser.mly b/query/type_parser.mly new file mode 100644 index 0000000000..ab8b2056c2 --- /dev/null +++ b/query/type_parser.mly @@ -0,0 +1,57 @@ +(* This is a parser for type expressions. It is written in a weird style to + allow for incomplete queries to be reasonably answered. It also has conflicts + for the same reason. They are impossible to solve. + Its behaviour on correct types is tested in [query/test/test_type_parser.ml] + and its behaviour on incomplete types is tested in [test/cram/query_syntax.t/run.t] *) + +%{ + open Db.Typexpr +%} + +%token EOF +%token PARENS_OPEN PARENS_CLOSE +%token ARROW COMMA ANY STAR +%token WORD +%token POLY + +%start main +%type main + +%% + +main: + | t=typ EOF { t } + | EOF { any } + ; + +typ: + | a=typ1 ARROW b=typ { arrow a b } + | a=typ1 ARROW EOF { arrow a any } + | ARROW b=typ { arrow any b } + | ARROW EOF { arrow any any } + | t=typ1 { t } + ; + +typ1: + | x=typ0 xs=tups { match xs with [] -> x | xs -> tuple (x::xs) } + ; + +tups: + | STAR x=typ0 xs=tups { x::xs } + | STAR { [any] } + | EOF { [] } + | { [] } + ; + +typ0: + | ANY { any } + | w=POLY { poly w } + | w=WORD { constr w [] } + | t=typ0 w=WORD { constr w [t] } + | PARENS_OPEN ts=typ_list PARENS_CLOSE w=WORD { constr w ts } + | PARENS_OPEN t=typ PARENS_CLOSE { t } + | PARENS_OPEN t=typ EOF { t } + | PARENS_OPEN EOF { any } + ; + +typ_list: ts=separated_list(COMMA, typ) { ts } ; diff --git a/review.md b/review.md index 53f3abe89f..f87a14cd97 100644 --- a/review.md +++ b/review.md @@ -50,6 +50,13 @@ they are interpreted as relative to the `-o` option") - separate pretty_query from the api function +- Try to support `_ -> int` with dynamic cost ? +> Done, but with polarities. `_` in a query has polarity `"+"` or `"-"`. + Previously the two possibilities were `"+POLY"`/`"-POLY"` or nothing. + + +- Rewrite the type parser in a more flexible framework than menhir (combinator or recursive descent) +> Not needed in the end # TODO @@ -65,9 +72,7 @@ they are interpreted as relative to the `-o` option") -- Rewrite the type parser in a more flexible framework than menhir (combinator or recursive descent) -- Try to support `_ -> int` with dynamic cost ? # Explications commentée diff --git a/test/cram/base_benchmark.t b/test/cram/base_benchmark.t index baa8c07c88..ba41048acf 100644 --- a/test/cram/base_benchmark.t +++ b/test/cram/base_benchmark.t @@ -7,9 +7,9 @@ ./base_odocls/shadow_stdlib.odocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.449s - user 0m1.407s - sys 0m0.037s + real 0m1.488s + user 0m1.409s + sys 0m0.067s diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 5ba088f197..bd0ad3fc26 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -31,7 +31,7 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 5.1M html/sherlodoc.js + 264K html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 3853c3983a..96f6bcac6a 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -53,7 +53,6 @@ $ sherlodoc ":_ -> moo" val Main.produce : unit -> moo val Main.produce_2' : unit -> unit -> moo - val Main.value : moo $ sherlodoc ":moo -> _" val Main.consume : moo -> unit val Main.consume_2 : moo -> moo -> unit diff --git a/test/cram/query_syntax.t/run.t b/test/cram/query_syntax.t/run.t index 095ca01955..86d7bba763 100644 --- a/test/cram/query_syntax.t/run.t +++ b/test/cram/query_syntax.t/run.t @@ -6,9 +6,14 @@ $ sherlodoc --pretty-query ": int list option" : int list option [No results] - $ sherlodoc --pretty-query ": ->" + $ export OCAMLRUNPARAM=b + $ sherlodoc --pretty-query ": _" : _ [No results] + + $ sherlodoc --pretty-query ": ->" + : _ -> _ + [No results] $ sherlodoc --pretty-query ": int ->" : int -> _ [No results] diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index d5f7b7fd64..6c22d8dfa6 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 5.1M sherlodoc.js + 264K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html From a06ecb5b23a4594aa29329a34276eca992bf5bc5 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 15:49:36 +0100 Subject: [PATCH 202/285] improve tests --- query/type_parser.mly | 2 +- test/cram/base_benchmark.t | 11 +++++++---- test/cram/{query_syntax.t/run.t => query_syntax.t} | 12 ++++++++---- test/cram/query_syntax.t/main.mli | 0 4 files changed, 16 insertions(+), 9 deletions(-) rename test/cram/{query_syntax.t/run.t => query_syntax.t} (75%) delete mode 100644 test/cram/query_syntax.t/main.mli diff --git a/query/type_parser.mly b/query/type_parser.mly index ab8b2056c2..b8a5124ca3 100644 --- a/query/type_parser.mly +++ b/query/type_parser.mly @@ -2,7 +2,7 @@ allow for incomplete queries to be reasonably answered. It also has conflicts for the same reason. They are impossible to solve. Its behaviour on correct types is tested in [query/test/test_type_parser.ml] - and its behaviour on incomplete types is tested in [test/cram/query_syntax.t/run.t] *) + and its behaviour on incomplete types is tested in [test/cram/query_syntax.t] *) %{ open Db.Typexpr diff --git a/test/cram/base_benchmark.t b/test/cram/base_benchmark.t index ba41048acf..4307d39370 100644 --- a/test/cram/base_benchmark.t +++ b/test/cram/base_benchmark.t @@ -1,3 +1,5 @@ +This test will fail, it is not deterministic. Please just check that the values +are not crazy and discard the changes $ find . -name '*.odocl' | sort ./base_odocls/base.odocl ./base_odocls/base_internalhash_types.odocl @@ -6,10 +8,11 @@ ./base_odocls/page-index.odocl ./base_odocls/shadow_stdlib.odocl $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - - real 0m1.488s - user 0m1.409s - sys 0m0.067s + + real 0m1.272s + user 0m1.210s + sys 0m0.060s + diff --git a/test/cram/query_syntax.t/run.t b/test/cram/query_syntax.t similarity index 75% rename from test/cram/query_syntax.t/run.t rename to test/cram/query_syntax.t index 86d7bba763..6bda005193 100644 --- a/test/cram/query_syntax.t/run.t +++ b/test/cram/query_syntax.t @@ -1,7 +1,9 @@ +We need a dummy file because sherlodoc requires an odocl. + $ touch main.mli $ ocamlc -c main.mli -bin-annot -I . $ odoc compile -I . main.cmti $ odoc link -I . main.odoc - $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') + $ sherlodoc_index --format=marshal --db=db.bin main.odocl $ export SHERLODOC_DB=db.bin $ sherlodoc --pretty-query ": int list option" : int list option @@ -10,7 +12,7 @@ $ sherlodoc --pretty-query ": _" : _ [No results] - +Testing incomplete queries $ sherlodoc --pretty-query ": ->" : _ -> _ [No results] @@ -32,5 +34,7 @@ $ sherlodoc --pretty-query ": (int *" : int * _ [No results] - - +Testing syntax errors + $ sherlodoc --pretty-query ": )" + : + [No results] diff --git a/test/cram/query_syntax.t/main.mli b/test/cram/query_syntax.t/main.mli deleted file mode 100644 index e69de29bb2..0000000000 From bfd9a22a9d6f50e1f8330cad102541256c670dd6 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 16:11:07 +0100 Subject: [PATCH 203/285] review update --- review.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/review.md b/review.md index f87a14cd97..9d197f2c58 100644 --- a/review.md +++ b/review.md @@ -2,10 +2,6 @@ # To discuss -- Tester de virer la compression? - > Verifier si la double compression a de l'interet - > tester que gzip - - Type extensions: we might want to search for all extensions of a given extensible type. # done @@ -60,19 +56,28 @@ they are interpreted as relative to the `-o` option") # TODO +- Tester de virer la compression? + > Verifier si la double compression a de l'interet + > tester que gzip +> Not done before vacation. Important ! This one is blocking for a release. + - Have something more robust than sizes in tests. Remove them, and use current-bench or just a manual benchmark. + > Not done before vacation. I do not know how to do this, and I believe that + size is critical and size changes should make the tests fail. + A manual benchmark could be used for test/cram/base_benchmark.t were time to + build the db is tested. + +- Have a benchmark of the cli - la limitation sur le packages de query n'est plus vraiment fonctionelle +> demander a arthur, pas bloquant pour un release mais a nettoyer a un moment - `Index.Load_doc.with_tokenizer`: think of which character form a word - +> Not done before vacation. I agree that it could be expanded. - Maybe store all "arbitrary constants" relative to the cost function somewhere - - - - +> I think it is fine as is for now. # Explications commentée From abf85e8ffb3f244d0212437bf2c5ffe6c0550831 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 16:11:38 +0100 Subject: [PATCH 204/285] review : moving todo to top --- review.md | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/review.md b/review.md index 9d197f2c58..fd5a70f7e7 100644 --- a/review.md +++ b/review.md @@ -1,5 +1,31 @@ # review sherlodoc +# TODO + +- Tester de virer la compression? + > Verifier si la double compression a de l'interet + > tester que gzip +> Not done before vacation. Important ! This one is blocking for a release. + +- Have something more robust than sizes in tests. Remove them, and use + current-bench or just a manual benchmark. + > Not done before vacation. I do not know how to do this, and I believe that + size is critical and size changes should make the tests fail. + A manual benchmark could be used for test/cram/base_benchmark.t were time to + build the db is tested. + +- Have a benchmark of the cli + +- la limitation sur le packages de query n'est plus vraiment fonctionelle +> demander a arthur, pas bloquant pour un release mais a nettoyer a un moment + +- `Index.Load_doc.with_tokenizer`: think of which character form a word +> Not done before vacation. I agree that it could be expanded. + +- Maybe store all "arbitrary constants" relative to the cost function somewhere +> I think it is fine as is for now. + + # To discuss - Type extensions: we might want to search for all extensions of a given extensible type. @@ -54,31 +80,6 @@ they are interpreted as relative to the `-o` option") - Rewrite the type parser in a more flexible framework than menhir (combinator or recursive descent) > Not needed in the end -# TODO - -- Tester de virer la compression? - > Verifier si la double compression a de l'interet - > tester que gzip -> Not done before vacation. Important ! This one is blocking for a release. - -- Have something more robust than sizes in tests. Remove them, and use - current-bench or just a manual benchmark. - > Not done before vacation. I do not know how to do this, and I believe that - size is critical and size changes should make the tests fail. - A manual benchmark could be used for test/cram/base_benchmark.t were time to - build the db is tested. - -- Have a benchmark of the cli - -- la limitation sur le packages de query n'est plus vraiment fonctionelle -> demander a arthur, pas bloquant pour un release mais a nettoyer a un moment - -- `Index.Load_doc.with_tokenizer`: think of which character form a word -> Not done before vacation. I agree that it could be expanded. - -- Maybe store all "arbitrary constants" relative to the cost function somewhere -> I think it is fine as is for now. - # Explications commentée ## Index From d223d600a06c605326acaef541b2381bfb8bb8ab Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 19 Dec 2023 17:03:29 +0100 Subject: [PATCH 205/285] update readme and resotr compat with last dune rules commit --- README.md | 1 + jsoo/dune | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ce6b66f11e..31b39a3c40 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ and record fields. First, install sherlodoc : ```bash +opam pin add https://github.com/art-w/sherlodoc.git#jsoo opam install sherlodoc ``` diff --git a/jsoo/dune b/jsoo/dune index 590da45332..28529937b0 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -13,5 +13,8 @@ (install (files sherlodoc.js) - (section share) +; (section share) +; This ought to be in share, but for now I can only make it work in bin : I did +; not manage to fetch sherlodoc.js from share in the dune rules. +(section bin) (package sherlodoc)) From 514a67fe0c46151da6e4d0bea5a3df709ab958e6 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 21 Dec 2023 13:53:30 +0100 Subject: [PATCH 206/285] remove unused dependencies --- db/dune | 5 +---- index/dune | 3 --- store/dune | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/db/dune b/db/dune index 4899646a37..2f917f09e4 100644 --- a/db/dune +++ b/db/dune @@ -1,5 +1,2 @@ -; [db] is the database data-structure for sherlodoc. - (library - (name db) - (libraries unix dum)) + (name db)) diff --git a/index/dune b/index/dune index 77378ac342..85cd080c6a 100644 --- a/index/dune +++ b/index/dune @@ -14,11 +14,8 @@ db fpath tyxml - opam-core odoc.search - odoc.loader odoc.model - odoc.xref2 odoc.odoc cmdliner storage_marshal diff --git a/store/dune b/store/dune index e163916e18..7c7127987c 100644 --- a/store/dune +++ b/store/dune @@ -6,7 +6,7 @@ (name storage_ancient) (modules storage_ancient) (optional) - (libraries db ancient)) + (libraries db ancient unix)) (library (name storage_js) From b9bb6a2439fc385f75c738f2dd9739afb2b00a1b Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 21 Dec 2023 14:10:02 +0100 Subject: [PATCH 207/285] upgrade ocamlformat --- .ocamlformat | 12 +- cli/main.ml | 64 ++++--- db/db.ml | 3 +- db/db.mli | 17 +- db/entry.ml | 41 +++-- db/entry.mli | 4 +- db/occ.ml | 17 +- db/occ.mli | 109 ++++++------ db/suffix_tree.ml | 295 ++++++++++++++++----------------- db/suffix_tree.mli | 14 +- db/type_polarity.ml | 59 +++---- db/type_polarity.mli | 32 ++-- db/typexpr.ml | 4 +- index/index.ml | 55 +++--- index/load_doc.ml | 155 ++++++++--------- index/load_doc.mli | 6 +- index/typename.ml | 34 ++-- jsoo/dune | 8 +- jsoo/main.ml | 53 +++--- query/array_succ.ml | 22 +-- query/dynamic_cost.ml | 68 ++++---- query/query.ml | 29 ++-- query/query.mli | 4 +- query/query_parser.ml | 13 +- query/query_parser.mli | 3 +- query/succ.ml | 78 +++++---- query/test/test.ml | 3 +- query/test/test_array.ml | 32 ++-- query/test/test_succ.ml | 24 ++- query/test/test_type_parser.ml | 16 +- query/type_distance.ml | 279 +++++++++++++++---------------- www/packages.ml | 74 ++++----- www/ui.ml | 72 +++----- www/www.ml | 50 +++--- 34 files changed, 844 insertions(+), 905 deletions(-) diff --git a/.ocamlformat b/.ocamlformat index 17e03264a5..1db190a13b 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,17 +1,9 @@ -version = 0.25.1 +version = 0.26.1 +profile = janestreet let-binding-spacing = compact sequence-style = separator doc-comments = after-when-possible exp-grouping = preserve break-cases = toplevel -break-separators = before cases-exp-indent = 4 cases-matching-exp-indent = normal -if-then-else = keyword-first -parens-tuple = multi-line-only -type-decl = sparse -field-space = loose -space-around-arrays = true -space-around-lists = true -space-around-records = true -dock-collection-brackets = false diff --git a/cli/main.ml b/cli/main.ml index d6e78405d8..7ce46b3db7 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -20,22 +20,17 @@ let string_of_kind = | Field _ -> "field" | Val _ -> "val" -let print_result ~print_cost ~no_rhs - Db.Entry. - { name - ; rhs - ; url = _ - ; kind - ; cost - ; doc_html = _ - ; pkg = _ - ; is_from_module_type = _ - } = +let print_result + ~print_cost + ~no_rhs + Db.Entry. + { name; rhs; url = _; kind; cost; doc_html = _; pkg = _; is_from_module_type = _ } + = let cost = if print_cost then string_of_int cost ^ " " else "" in let typedecl_params = (match kind with - | Db.Entry.Kind.TypeDecl args -> args - | _ -> None) + | Db.Entry.Kind.TypeDecl args -> args + | _ -> None) |> Option.map (fun str -> str ^ " ") |> Option.value ~default:"" in @@ -54,31 +49,30 @@ let search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query = match Query.(search ~shards:db ~dynamic_sort:(not static_sort) query) with | [] -> print_endline "[No results]" | _ :: _ as results -> - List.iter (print_result ~print_cost ~no_rhs) results ; - flush stdout + List.iter (print_result ~print_cost ~no_rhs) results ; + flush stdout let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db = match In_channel.input_line stdin with | Some query -> - search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query ; - search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db + search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query ; + search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db | None -> print_endline "[Search session ended]" let main db query print_cost no_rhs static_sort limit pretty_query = match db with | None -> - output_string stderr - "No database provided. Provide one by exporting the SHERLODOC_DB \ - variable, or using the --db option\n" ; - exit 1 - | Some db -> ( - let db = Storage_marshal.load db in - match query with - | None -> - search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db - | Some query -> - search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db query - ) + output_string + stderr + "No database provided. Provide one by exporting the SHERLODOC_DB variable, or \ + using the --db option\n" ; + exit 1 + | Some db -> + let db = Storage_marshal.load db in + (match query with + | None -> search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db + | Some query -> + search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db query) open Cmdliner @@ -94,9 +88,7 @@ let limit = Arg.(value & opt int 50 & info [ "limit"; "n" ] ~docv:"N" ~doc) let query = - let doc = - "The query. If absent, sherlodoc will read queries in the standard input." - in + let doc = "The query. If absent, sherlodoc will read queries in the standard input." in Arg.(value & pos 0 (some string) None & info [] ~docv:"QUERY" ~doc) let print_cost = @@ -121,7 +113,13 @@ let pretty_query = let main = Term.( - const main $ db_filename $ query $ print_cost $ no_rhs $ static_sort $ limit + const main + $ db_filename + $ query + $ print_cost + $ no_rhs + $ static_sort + $ limit $ pretty_query) let cmd = diff --git a/db/db.ml b/db/db.ml index cb8400a2ed..a9d39eb404 100644 --- a/db/db.ml +++ b/db/db.ml @@ -30,5 +30,4 @@ let store db name elt ~count = let store_type_polarities db elt polarities = List.iter (fun (word, count) -> store db ~count word elt) polarities -let store_word db word elt = - Suffix_tree.With_elts.add_suffixes db.writer_names word elt +let store_word db word elt = Suffix_tree.With_elts.add_suffixes db.writer_names word elt diff --git a/db/db.mli b/db/db.mli index 0f6bfaf7ed..7f2ea301b0 100644 --- a/db/db.mli +++ b/db/db.mli @@ -11,16 +11,15 @@ type t = Db_typedef.t = } (** The type of a search database. -[db_names] is for text-based part of the query and [db_types] for the -type-based part. + [db_names] is for text-based part of the query and [db_types] for the + type-based part. -[db_types] has [Entry.t array Int_map.t] ([Occ.t]) as a payload because we want -the query [blabla : int -> int -> _] to return only entries that take at -least two ints as arguments, an entry of type [int -> string] is invalid. -The [Int_map.t] maps a number of occurences to a set of entries. See {!Occ}. -[db_types] still is a suffix tree, so you can search in it only for text. The -way we transform types into searchable text is in {!Type_polarity}. -*) + [db_types] has [Entry.t array Int_map.t] ([Occ.t]) as a payload because we want + the query [blabla : int -> int -> _] to return only entries that take at + least two ints as arguments, an entry of type [int -> string] is invalid. + The [Int_map.t] maps a number of occurences to a set of entries. See {!Occ}. + [db_types] still is a suffix tree, so you can search in it only for text. The + way we transform types into searchable text is in {!Type_polarity}. *) type writer (** The type that builds a database. You can use it to add things to it, but diff --git a/db/entry.ml b/db/entry.ml index 9da9340dca..b0252eabcc 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -60,27 +60,27 @@ module T = struct begin match Int.compare (String.length a.name) (String.length b.name) with | 0 -> begin - match String.compare a.name b.name with + match String.compare a.name b.name with + | 0 -> begin + match Option.compare compare_pkg a.pkg b.pkg with | 0 -> begin - match Option.compare compare_pkg a.pkg b.pkg with - | 0 -> begin - match Stdlib.compare a.kind b.kind with - | 0 -> Stdlib.compare a.url b.url - | c -> c - end - | c -> c - end + match Stdlib.compare a.kind b.kind with + | 0 -> Stdlib.compare a.url b.url + | c -> c + end | c -> c end + | c -> c + end | c -> c end let compare a b = if a == b then 0 - else + else ( let cmp = Int.compare a.cost b.cost in - if cmp = 0 then structural_compare a b else cmp + if cmp = 0 then structural_compare a b else cmp) end include T @@ -108,19 +108,18 @@ let pkg_link { pkg; _ } = match pkg with | None -> None | Some { name; version } -> - Some (Printf.sprintf "https://ocaml.org/p/%s/%s" name version) + Some (Printf.sprintf "https://ocaml.org/p/%s/%s" name version) let link t = match pkg_link t with | None -> None | Some pkg_link -> - let name, path = - match List.rev (String.split_on_char '.' t.name) with - | name :: path -> name, String.concat "/" (List.rev path) - | _ -> "", "" - in - Some (pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name) - -let v ~name ~kind ~cost ~rhs ~doc_html ~url ~is_from_module_type ?(pkg = None) - () = + let name, path = + match List.rev (String.split_on_char '.' t.name) with + | name :: path -> name, String.concat "/" (List.rev path) + | _ -> "", "" + in + Some (pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name) + +let v ~name ~kind ~cost ~rhs ~doc_html ~url ~is_from_module_type ?(pkg = None) () = { name; kind; url; cost; doc_html; pkg; rhs; is_from_module_type } diff --git a/db/entry.mli b/db/entry.mli index 38fdaa4a6e..c87777b3b0 100644 --- a/db/entry.mli +++ b/db/entry.mli @@ -69,8 +69,8 @@ end val pkg_link : t -> string option val link : t -> string option -val v : - name:string +val v + : name:string -> kind:Kind.t -> cost:int -> rhs:string option diff --git a/db/occ.ml b/db/occ.ml index bb9db288d8..70932fcabe 100644 --- a/db/occ.ml +++ b/db/occ.ml @@ -9,13 +9,13 @@ let is_empty = Int_map.is_empty let equal_elt (a_count, a) (b_count, b) = a_count = b_count && Entry.equal a b (* -let of_list li = - List.fold_left - (fun acc (count, elt) -> - let elts = try Int_map.find count acc with Not_found -> [] in - Int_map.add count (elt :: elts) acc) - Int_map.empty li - |> Int_map.map Entry.Array.of_list + let of_list li = + List.fold_left + (fun acc (count, elt) -> + let elts = try Int_map.find count acc with Not_found -> [] in + Int_map.add count (elt :: elts) acc) + Int_map.empty li + |> Int_map.map Entry.Array.of_list *) let of_list li = @@ -24,5 +24,6 @@ let of_list li = match Int_map.find_opt count acc with | None -> Int_map.add count (Entry.Set.singleton elt) acc | Some set -> Int_map.add count (Entry.Set.add elt set) acc) - Int_map.empty li + Int_map.empty + li |> Int_map.map (fun set -> set |> Entry.Set.to_seq |> Array.of_seq) diff --git a/db/occ.mli b/db/occ.mli index 7b4f2d0f6f..512f1b6e32 100644 --- a/db/occ.mli +++ b/db/occ.mli @@ -1,60 +1,57 @@ (** [Occ] stands for occurences. It associate sets of elements to the number of - time members of the set occurs. - -The list [[a, a, b, b, c]] would correspond to [[(2, [a; b]); (1, [c]) ]]. It is -used or type search : you want to be able to return every function that takes -two ints as an argument. Without this datastrucure, we would only be able to -search for functions that take ints, without specifying the amount. - -This datastructure is used at the leafs of the suffix tree : so when doing type -search, we first perform a type search ignoring occurences, and afterwards -filter the results according to them. - -I will give an example bellow, it is probably better to read {!Type_polarities} -first to understand it completely. - -If you have the following entries : - -{[ -val a : string -> int -val b : string -> string -> int -val c : string -> string -> (int * int) -val d : (string * string) -> float -> (int * int) - -]} - -Their polarities will be : - -{[ -val a : {(-string, 1); (+int, 1)} -val b : {(-string, 2); (+int, 1)} -val c : {(-string, 2); (+int, 2)} -val d : {(-string, 2); (+int, 2); (-float, 1)} -]} - -We can combine them into a database that will look like this : - -{[ -+int -> - { 1 -> {a; b} - 2 -> {c; d} - } --string -> - { 1 -> {a} - 2 -> {b; c; d} - } --float -> - { 1 -> {d} - } -]} - -If there is a query for type [string -> string -> (int * int)], the polarities -of the query are [(-string, 2)], [(+int, 2)]. - -The entries of [(-string, 2)] are [{b; c; d}], and the entries of [(+int, 2)] -are [{c; d}]. The intersection of the two is [{c; d}]. - -*) + time members of the set occurs. + + The list [[a, a, b, b, c]] would correspond to [[(2, [a; b]); (1, [c]) ]]. It is + used or type search : you want to be able to return every function that takes + two ints as an argument. Without this datastrucure, we would only be able to + search for functions that take ints, without specifying the amount. + + This datastructure is used at the leafs of the suffix tree : so when doing type + search, we first perform a type search ignoring occurences, and afterwards + filter the results according to them. + + I will give an example bellow, it is probably better to read {!Type_polarities} + first to understand it completely. + + If you have the following entries : + + {[ + val a : string -> int + val b : string -> string -> int + val c : string -> string -> int * int + val d : string * string -> float -> int * int + ]} + + Their polarities will be : + + {[ + val a : {(-string, 1); (+int, 1)} + val b : {(-string, 2); (+int, 1)} + val c : {(-string, 2); (+int, 2)} + val d : {(-string, 2); (+int, 2); (-float, 1)} + ]} + + We can combine them into a database that will look like this : + + {[ + +int -> + { 1 -> {a; b} + 2 -> {c; d} + } + -string -> + { 1 -> {a} + 2 -> {b; c; d} + } + -float -> + { 1 -> {d} + } + ]} + + If there is a query for type [string -> string -> (int * int)], the polarities + of the query are [(-string, 2)], [(+int, 2)]. + + The entries of [(-string, 2)] are [{b; c; d}], and the entries of [(+int, 2)] + are [{c; d}]. The intersection of the two is [{c; d}]. *) type t type elt = int * Entry.t diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index 6493e3b5a1..89a0b3a429 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -19,9 +19,7 @@ module Doc = struct | Terminal of 'a | Char of char - let get t i = - if i >= String.length t.text then Terminal t.uid else Char t.text.[i] - + let get t i = if i >= String.length t.text then Terminal t.uid else Char t.text.[i] let sub { text; _ } i = String.sub text i (String.length text - i) end @@ -30,11 +28,11 @@ module Buf = struct string twice, the second addition is not performed. *) module String_hashtbl = Hashtbl.Make (struct - type t = string + type t = string - let equal = String.equal - let hash = Hashtbl.hash - end) + let equal = String.equal + let hash = Hashtbl.hash + end) type t = { buffer : Buffer.t @@ -49,16 +47,17 @@ module Buf = struct match String_hashtbl.find_opt cache substr with | Some start -> start | None -> - let start = Buffer.length buffer in - Buffer.add_string buffer substr ; - let stop = Buffer.length buffer in - assert (stop - start = String.length substr) ; - for idx = 1 to String.length substr - 1 do - String_hashtbl.add cache - (String.sub substr idx (String.length substr - idx)) - (start + idx) - done ; - start + let start = Buffer.length buffer in + Buffer.add_string buffer substr ; + let stop = Buffer.length buffer in + assert (stop - start = String.length substr) ; + for idx = 1 to String.length substr - 1 do + String_hashtbl.add + cache + (String.sub substr idx (String.length substr - idx)) + (start + idx) + done ; + start end module Make (S : SET) = struct @@ -83,11 +82,11 @@ module Make (S : SET) = struct | _ -> false module Hashtbl = Hashtbl.Make (struct - type nonrec t = t + type nonrec t = t - let hash = hash - let equal = equal - end) + let hash = hash + let equal = equal + end) end module Char_map = Map.Make (Char) @@ -134,9 +133,9 @@ module Make (S : SET) = struct let rec go_lcp i j = if i >= String.length i_str || j >= j_stop then i - else + else ( let i_chr, j_chr = i_str.[i], Buf.get j_str j in - if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1) + if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1)) in let i' = go_lcp i j in i' - i @@ -145,12 +144,12 @@ module Make (S : SET) = struct let start = match prev_leaf with | None -> - let substr = Doc.sub doc (str_start - 1) in - let start = Buf.add buffer substr in - start + 1 + let substr = Doc.sub doc (str_start - 1) in + let start = Buf.add buffer substr in + start + 1 | Some (prev_leaf, _depth, _) -> - let doc_len = Doc.length doc in - prev_leaf.start + prev_leaf.len - (doc_len - str_start) + 1 + let doc_len = Doc.length doc in + prev_leaf.start + prev_leaf.len - (doc_len - str_start) + 1 in let len = Doc.length doc - str_start - 1 in assert (start > 0) ; @@ -164,12 +163,12 @@ module Make (S : SET) = struct let set_suffix_link ~prev ~depth node = match prev with | Some (prev, prev_depth) when depth = prev_depth -> - begin - match prev.suffix_link with - | None -> prev.suffix_link <- Some node - | Some node' -> assert (node == node') - end ; - None + begin + match prev.suffix_link with + | None -> prev.suffix_link <- Some node + | Some node' -> assert (node == node') + end ; + None | _ -> prev let add_document trie doc = @@ -182,12 +181,12 @@ module Make (S : SET) = struct match prev_leaf with | None -> () | Some (prev_leaf, prev_depth, _) -> - assert (prev_depth = depth) ; - begin - match prev_leaf.suffix_link with - | None -> prev_leaf.suffix_link <- Some node - | Some node' -> assert (node' == node) - end + assert (prev_depth = depth) ; + begin + match prev_leaf.suffix_link with + | None -> prev_leaf.suffix_link <- Some node + | Some node' -> assert (node' == node) + end end ; Some (node, depth - 1) end @@ -196,123 +195,113 @@ module Make (S : SET) = struct let prev = set_suffix_link ~prev ~depth node in if i >= Doc.length doc then assert (depth = 0) - else + else ( let chr = Doc.get doc i in let i, depth = i + 1, depth + 1 in match chr with | Terminal doc_uid -> - if not (Terminals.mem doc_uid node.terminals) - then begin - let hint = - Option.map - (fun (t, _, prev_terminals) -> prev_terminals, t.terminals) - prev_leaf - in - let prev_terminals = node.terminals in - node.terminals <- Terminals.add ~hint doc_uid node.terminals ; - let prev_leaf = - match set_leaf ~debug:"0" ~prev_leaf ~depth node with - | None -> None - | Some (t, depth) -> Some (t, depth, prev_terminals) - in - follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i - end - | Char chr -> begin - match Char_map.find chr node.children with - | child -> - assert (depth >= 0) ; - assert (i - depth >= 0) ; - assert (i < Doc.length doc) ; - let len = - lcp doc.Doc.text i trie.buffer child.start child.len - in - let i, depth = i + len, depth + len in - assert (i < Doc.length doc) ; - if len = child.len - then - if not (Char_map.is_empty child.children) - then go ~prev ~prev_leaf ~depth child i - else add_leaf ~prev_leaf ~node ~child ~depth ~i ~len - else begin - let new_child = split_at ~str:trie.buffer child len in - node.children <- Char_map.add chr new_child node.children ; - let prev = set_suffix_link ~prev ~depth new_child in - assert (prev = None) ; - add_leaf ~prev_leaf ~node ~child:new_child ~depth ~i ~len - end - | exception Not_found -> - let new_leaf = - make_leaf ~prev_leaf ~buffer:trie.buffer ~doc i - in - node.children <- Char_map.add chr new_leaf node.children ; - let prev_leaf = - set_leaf ~debug:"1" ~prev_leaf - ~depth:(depth + Doc.length doc - i) - new_leaf - in - let prev_leaf = - match prev_leaf with - | None -> None - | Some (t, depth) -> Some (t, depth, Terminals.empty) - in - follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i - end - and add_leaf ~prev_leaf ~node ~child ~depth ~i ~len = - match Doc.get doc i with - | Terminal doc_uid -> - if not (Terminals.mem doc_uid child.terminals) + if not (Terminals.mem doc_uid node.terminals) then begin let hint = Option.map (fun (t, _, prev_terminals) -> prev_terminals, t.terminals) prev_leaf in - let prev_terminals = child.terminals in - child.terminals <- Terminals.add ~hint doc_uid child.terminals ; + let prev_terminals = node.terminals in + node.terminals <- Terminals.add ~hint doc_uid node.terminals ; let prev_leaf = - match set_leaf ~debug:"2" ~prev_leaf ~depth:(depth + 1) child with + match set_leaf ~debug:"0" ~prev_leaf ~depth node with | None -> None | Some (t, depth) -> Some (t, depth, prev_terminals) in - assert (Doc.length doc - i = 1) ; - begin - match child.suffix_link with - | None -> - let i, depth = i - len, depth - len in - follow_suffix ~prev:None ~prev_leaf ~parent:node ~depth ~i - | Some next_child -> - let depth = depth - 1 in - go ~prev:None ~prev_leaf:None ~depth next_child i - end + follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i end - | Char new_chr -> - let new_leaf = - make_leaf ~prev_leaf ~buffer:trie.buffer ~doc (i + 1) - in - let prev_leaf = - set_leaf ~debug:"3" ~prev_leaf - ~depth:(depth + Doc.length doc - i) - new_leaf + | Char chr -> begin + match Char_map.find chr node.children with + | child -> + assert (depth >= 0) ; + assert (i - depth >= 0) ; + assert (i < Doc.length doc) ; + let len = lcp doc.Doc.text i trie.buffer child.start child.len in + let i, depth = i + len, depth + len in + assert (i < Doc.length doc) ; + if len = child.len + then + if not (Char_map.is_empty child.children) + then go ~prev ~prev_leaf ~depth child i + else add_leaf ~prev_leaf ~node ~child ~depth ~i ~len + else begin + let new_child = split_at ~str:trie.buffer child len in + node.children <- Char_map.add chr new_child node.children ; + let prev = set_suffix_link ~prev ~depth new_child in + assert (prev = None) ; + add_leaf ~prev_leaf ~node ~child:new_child ~depth ~i ~len + end + | exception Not_found -> + let new_leaf = make_leaf ~prev_leaf ~buffer:trie.buffer ~doc i in + node.children <- Char_map.add chr new_leaf node.children ; + let prev_leaf = + set_leaf ~debug:"1" ~prev_leaf ~depth:(depth + Doc.length doc - i) new_leaf + in + let prev_leaf = + match prev_leaf with + | None -> None + | Some (t, depth) -> Some (t, depth, Terminals.empty) + in + follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i + end) + and add_leaf ~prev_leaf ~node ~child ~depth ~i ~len = + match Doc.get doc i with + | Terminal doc_uid -> + if not (Terminals.mem doc_uid child.terminals) + then begin + let hint = + Option.map + (fun (t, _, prev_terminals) -> prev_terminals, t.terminals) + prev_leaf in + let prev_terminals = child.terminals in + child.terminals <- Terminals.add ~hint doc_uid child.terminals ; let prev_leaf = - match prev_leaf with + match set_leaf ~debug:"2" ~prev_leaf ~depth:(depth + 1) child with | None -> None - | Some (t, depth) -> Some (t, depth, Terminals.empty) + | Some (t, depth) -> Some (t, depth, prev_terminals) in - child.children <- Char_map.add new_chr new_leaf child.children ; - let prev = Some (child, depth - 1) in - let i, depth = i - len, depth - len in - follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i + assert (Doc.length doc - i = 1) ; + begin + match child.suffix_link with + | None -> + let i, depth = i - len, depth - len in + follow_suffix ~prev:None ~prev_leaf ~parent:node ~depth ~i + | Some next_child -> + let depth = depth - 1 in + go ~prev:None ~prev_leaf:None ~depth next_child i + end + end + | Char new_chr -> + let new_leaf = make_leaf ~prev_leaf ~buffer:trie.buffer ~doc (i + 1) in + let prev_leaf = + set_leaf ~debug:"3" ~prev_leaf ~depth:(depth + Doc.length doc - i) new_leaf + in + let prev_leaf = + match prev_leaf with + | None -> None + | Some (t, depth) -> Some (t, depth, Terminals.empty) + in + child.children <- Char_map.add new_chr new_leaf child.children ; + let prev = Some (child, depth - 1) in + let i, depth = i - len, depth - len in + follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i and follow_suffix ~prev ~prev_leaf ~parent ~depth ~i = match parent.suffix_link with | None -> begin - let i = i - depth + 1 in - go ~prev:None ~prev_leaf ~depth:0 root i - end + let i = i - depth + 1 in + go ~prev:None ~prev_leaf ~depth:0 root i + end | Some next -> - assert (depth >= 2) ; - assert (next != root) ; - go ~prev ~prev_leaf ~depth:(depth - 2) next (i - 1) + assert (depth >= 2) ; + assert (next != root) ; + go ~prev ~prev_leaf ~depth:(depth - 2) next (i - 1) in go ~prev:None ~prev_leaf:None ~depth:0 root 0 @@ -349,9 +338,9 @@ module Make (S : SET) = struct let rec go i = if i >= Array.length arr then raise Not_found - else + else ( let node = arr.(i) in - if chr = str.[node.start - 1] then node else go (i + 1) + if chr = str.[node.start - 1] then node else go (i + 1)) in go 0 @@ -360,9 +349,9 @@ module Make (S : SET) = struct let rec go_lcp i j = if i >= String.length i_str || j >= j_stop then i - else + else ( let i_chr, j_chr = i_str.[i], j_str.[j] in - if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1) + if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1)) in let i' = go_lcp i j in i' - i @@ -370,10 +359,10 @@ module Make (S : SET) = struct let rec find ~str node pattern i = if i >= String.length pattern then node - else + else ( let chr = pattern.[i] in let child = array_find ~str chr node.children in - find_lcp ~str child pattern (i + 1) + find_lcp ~str child pattern (i + 1)) and find_lcp ~str child pattern i = let n = lcp pattern i str child.start child.len in @@ -387,7 +376,9 @@ module Make (S : SET) = struct let child = find ~str:t.str t.t pattern 0 in { str = t.str; t = child } - let find t pattern = try Some (find t pattern) with Not_found -> None + let find t pattern = + try Some (find t pattern) with + | Not_found -> None let rec collapse acc t = let acc = if S.is_empty t.terminals then acc else t.terminals :: acc in @@ -396,7 +387,8 @@ module Make (S : SET) = struct let collapse t = collapse [] t.t let rec sets_tree ~union ~terminal ~union_of_array t = - union (terminal t.terminals) + union + (terminal t.terminals) (union_of_array (Array.map (sets_tree ~union ~terminal ~union_of_array) t.children)) @@ -405,30 +397,25 @@ module Make (S : SET) = struct end let export_terminals ~cache_term ts = - try Terminals.Hashtbl.find cache_term ts - with Not_found -> + try Terminals.Hashtbl.find cache_term ts with + | Not_found -> let result = Uid.make (), S.of_list ts in Terminals.Hashtbl.add cache_term ts result ; result let rec export ~cache ~cache_term node = - let terminals_uid, terminals = - export_terminals ~cache_term node.terminals - in + let terminals_uid, terminals = export_terminals ~cache_term node.terminals in let children = - Char_map.bindings - @@ Char_map.map (export ~cache ~cache_term) node.children + Char_map.bindings @@ Char_map.map (export ~cache ~cache_term) node.children in let children_uids = List.map (fun (chr, (uid, _)) -> chr, uid) children in let key = node.start, node.len, terminals_uid, children_uids in - try Hashtbl.find cache key - with Not_found -> + try Hashtbl.find cache key with + | Not_found -> let children = Array.of_list @@ List.map (fun (_, (_, child)) -> child) children in - let node = - { T.start = node.start; len = node.len; terminals; children } - in + let node = { T.start = node.start; len = node.len; terminals; children } in let result = Uid.make (), node in Hashtbl.add cache key result ; result diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index ca1cf54ead..d5017babbe 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -1,8 +1,8 @@ (** The suffix tree datastructure. This datastructure allows to efficiently - search for strings suffixes. + search for strings suffixes. -You need to provide a datastructure for the sets of elements at the leafs of the -tree. *) + You need to provide a datastructure for the sets of elements at the leafs of the + tree. *) module type SET = sig type t @@ -29,8 +29,8 @@ module Make (S : SET) : sig val find : reader -> string -> reader option val to_sets : reader -> S.t list - val sets_tree : - union:('a -> 'a -> 'a) + val sets_tree + : union:('a -> 'a -> 'a) -> terminal:(S.t -> 'a) -> union_of_array:('a array -> 'a) -> reader @@ -39,8 +39,8 @@ end module With_elts : module type of Make (Entry.Array) (** [With_elts] is a suffix tree with array of entries at the leafs. It is used - for the text-based part of the database. *) + for the text-based part of the database. *) module With_occ : module type of Make (Occ) (** [With_occ] is a suffix tree with occurence annotated arrays of entries at - the leafs. It is used for the type-based part of the database. *) + the leafs. It is used for the type-based part of the database. *) diff --git a/db/type_polarity.ml b/db/type_polarity.ml index 55a22717e8..7bfc307df4 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -4,9 +4,13 @@ let regroup lst = String_map.bindings @@ List.fold_left (fun acc s -> - let count = try String_map.find s acc with Not_found -> 0 in + let count = + try String_map.find s acc with + | Not_found -> 0 + in String_map.add s (count + 1) acc) - String_map.empty lst + String_map.empty + lst module Sign = struct type t = @@ -22,8 +26,7 @@ module Sign = struct | Neg -> Pos end -let rev_concat lst = - List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst +let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst let rec tails = function | [] -> [] @@ -37,34 +40,32 @@ let all_type_names name = let rec of_typ ~any_is_poly ~all_names ~prefix ~sgn = function | Poly _ -> [ Sign.to_string sgn :: "POLY" :: prefix ] | Any -> - if any_is_poly - then [ Sign.to_string sgn :: "POLY" :: prefix ] - else [ Sign.to_string sgn :: prefix ] + if any_is_poly + then [ Sign.to_string sgn :: "POLY" :: prefix ] + else [ Sign.to_string sgn :: prefix ] | Arrow (a, b) -> - List.rev_append - (of_typ ~any_is_poly ~all_names ~prefix ~sgn:(Sign.not sgn) a) - (of_typ ~any_is_poly ~all_names ~prefix ~sgn b) + List.rev_append + (of_typ ~any_is_poly ~all_names ~prefix ~sgn:(Sign.not sgn) a) + (of_typ ~any_is_poly ~all_names ~prefix ~sgn b) | Constr (name, args) -> - name - |> (if all_names then all_type_names else fun name -> [ name ]) - |> List.map (fun name -> - let prefix = Sign.to_string sgn :: name :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - of_typ ~any_is_poly ~all_names ~prefix ~sgn arg) - args - end) - |> rev_concat + name + |> (if all_names then all_type_names else fun name -> [ name ]) + |> List.map (fun name -> + let prefix = Sign.to_string sgn :: name :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + of_typ ~any_is_poly ~all_names ~prefix ~sgn arg) + args + end) + |> rev_concat | Tuple args -> - rev_concat - @@ List.map (of_typ ~any_is_poly ~all_names ~prefix ~sgn) - @@ args + rev_concat @@ List.map (of_typ ~any_is_poly ~all_names ~prefix ~sgn) @@ args | Unhandled -> [] let of_typ ~any_is_poly ~all_names t = diff --git a/db/type_polarity.mli b/db/type_polarity.mli index 3f46d9c905..e22c005825 100644 --- a/db/type_polarity.mli +++ b/db/type_polarity.mli @@ -61,28 +61,26 @@ type t = string * int {!Suffix_tree}. It is a solely text-based datastructure. Therefore, we need a text represention for the polarities. - The polarity [+t] is represented by ["+t"], and the polarity [-t] is - represented by ["-t"]. + The polarity [+t] is represented by ["+t"], and the polarity [-t] is + represented by ["-t"]. - The fact that the sign is in the front is important : ["+flo"] is a prefix of - ["+float"], but ["flo+"] is not a prefix nor a suffix of ["float+"]. This - allows to answer incomplete queries. + The fact that the sign is in the front is important : ["+flo"] is a prefix of + ["+float"], but ["flo+"] is not a prefix nor a suffix of ["float+"]. This + allows to answer incomplete queries. - The integer represents the occurences of the polarity, as explained in the - toplevel documentation of the module. -*) + The integer represents the occurences of the polarity, as explained in the + toplevel documentation of the module. *) val of_typ : any_is_poly:bool -> all_names:bool -> Typexpr.t -> t list (** [of_typ ~ignore_any ~all_names typ] is the list of polarised types corresponding to [typ]. - - If [any_is_poly] is true, the type [_] will be treated like a type variable - ['a], other it will be represented solely by its sign ("+" or "-"). + - If [any_is_poly] is true, the type [_] will be treated like a type variable + ['a], other it will be represented solely by its sign ("+" or "-"). - - If [all_names] is true, extra polarities are added for every "possible name" - of each type constructor. For instance the possible names of - [Stdlib.Int64.t] are ["t"], ["Int64.t"] and ["Stdlib.Int64.t"]. This allows - for the user to use any of the possible name. It is important to set this - when registering entries in the database, but you not need it when computing - the polarities of a query. - *) + - If [all_names] is true, extra polarities are added for every "possible name" + of each type constructor. For instance the possible names of + [Stdlib.Int64.t] are ["t"], ["Int64.t"] and ["Stdlib.Int64.t"]. This allows + for the user to use any of the possible name. It is important to set this + when registering entries in the database, but you not need it when computing + the polarities of a query. *) diff --git a/db/typexpr.ml b/db/typexpr.ml index e02c9a638e..c9249e022d 100644 --- a/db/typexpr.ml +++ b/db/typexpr.ml @@ -12,8 +12,8 @@ let cache t = match Hashtbl.find_opt table t with | Some t -> t | None -> - Hashtbl.add table t t ; - t + Hashtbl.add table t t ; + t let arrow a b = cache (Arrow (a, b)) let constr name args = cache (Constr (name, args)) diff --git a/index/index.ml b/index/index.ml index d1e6b28169..508aeb3b21 100644 --- a/index/index.ml +++ b/index/index.ml @@ -1,25 +1,23 @@ 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 - | Ok result -> result - | Error (`Msg msg) -> - Format.printf "Odoc warning or 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 + | Ok result -> result + | Error (`Msg msg) -> Format.printf "Odoc warning or error %s: %s@." filename msg) let storage_module = Ancient.storage_module -let main files file_list index_docstring index_name type_search db_filename - db_format = +let main files file_list index_docstring index_name type_search db_filename db_format = let module Storage = (val storage_module db_format) in let db = Db.make () in let register id () item = @@ -32,8 +30,8 @@ let main files file_list index_docstring index_name type_search db_filename match file_list with | None -> files | Some file_list -> - let file_list = open_in file_list in - files @ (file_list |> In_channel.input_all |> String.split_on_char '\n') + let file_list = open_in file_list in + files @ (file_list |> In_channel.input_all |> String.split_on_char '\n') in List.iter (index_file register) files ; let t = Db.export db in @@ -57,21 +55,16 @@ let type_search = let db_format = let doc = "Database format" in let kind = Arg.enum (Ancient.arg_enum @ [ "marshal", `marshal; "js", `js ]) in - Arg.( - required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) + Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) let db_filename = let doc = "Output filename" in - Arg.( - required - & opt (some string) None - & info [ "db"; "output"; "o" ] ~docv:"DB" ~doc) + Arg.(required & opt (some string) None & info [ "db"; "output"; "o" ] ~docv:"DB" ~doc) let file_list = let doc = "File containing a list of .odocl files.\n\ - Useful for system where there is a limit on the number of arguments to a \ - command." + Useful for system where there is a limit on the number of arguments to a command." in Arg.(value & opt (some file) None & info [ "file-list" ] ~doc) @@ -81,8 +74,14 @@ let odoc_files = let index = Term.( - const main $ odoc_files $ file_list $ index_docstring $ index_name - $ type_search $ db_filename $ db_format) + const main + $ odoc_files + $ file_list + $ index_docstring + $ index_name + $ type_search + $ db_filename + $ db_format) let cmd = let doc = "Index odocl files" in diff --git a/index/load_doc.ml b/index/load_doc.ml index 12f5fab4fa..c5af61f968 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -30,19 +30,18 @@ let cost ~name ~kind ~doc_html = generic_cost ~ignore_no_doc name has_doc + kind_cost kind (* - - todo : check usefulness - let rec type_size = function - | Odoc_model.Lang.TypeExpr.Var _ -> 1 - | Any -> 1 - | Arrow (lbl, a, b) -> - (match lbl with - | None -> 0 - | Some _ -> 1) - + type_size a + type_size b - | Constr (_, args) -> List.fold_left (fun acc t -> acc + type_size t) 1 args - | Tuple args -> List.fold_left (fun acc t -> acc + type_size t) 1 args - | _ -> 100 + todo : check usefulness + let rec type_size = function + | Odoc_model.Lang.TypeExpr.Var _ -> 1 + | Any -> 1 + | Arrow (lbl, a, b) -> + (match lbl with + | None -> 0 + | Some _ -> 1) + + type_size a + type_size b + | Constr (_, args) -> List.fold_left (fun acc t -> acc + type_size t) 1 args + | Tuple args -> List.fold_left (fun acc t -> acc + type_size t) 1 args + | _ -> 100 *) let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) @@ -52,10 +51,9 @@ let rec typ_of_odoc_typ otyp = match otyp with | Odoc_model.Lang.TypeExpr.Var str -> poly str | Any -> any - | Arrow (_lbl, left, right) -> - arrow (typ_of_odoc_typ left) (typ_of_odoc_typ right) + | Arrow (_lbl, left, right) -> arrow (typ_of_odoc_typ left) (typ_of_odoc_typ right) | Constr (name, args) -> - constr (Typename.to_string name) (List.map typ_of_odoc_typ args) + constr (Typename.to_string name) (List.map typ_of_odoc_typ args) | Tuple li -> tuple (List.map typ_of_odoc_typ li) | _ -> unhandled @@ -70,14 +68,15 @@ let with_tokenizer str fn = let rec go i = if i >= String.length str then flush () - else + else ( let chr = str.[i] in if (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9') - || chr = '_' || chr = '@' + || chr = '_' + || chr = '@' then Buffer.add_char buf chr else flush () ; - go (i + 1) + go (i + 1)) in go 0 @@ -91,18 +90,19 @@ let register_full_name ~db name elt = let searchable_type_of_constructor args res = let open Odoc_model.Lang in match args with - | TypeDecl.Constructor.Tuple args -> ( - match args with - | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) - | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) - | _ -> res) + | TypeDecl.Constructor.Tuple args -> + (match args with + | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) + | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) + | _ -> res) | TypeDecl.Constructor.Record fields -> - List.fold_left - (fun res field -> - let open TypeDecl.Field in - let field_name = Odoc_model.Paths.Identifier.name field.id in - TypeExpr.Arrow (Some (Label field_name), field.type_, res)) - res fields + List.fold_left + (fun res field -> + let open TypeDecl.Field in + let field_name = Odoc_model.Paths.Identifier.name field.id in + TypeExpr.Arrow (Some (Label field_name), field.type_, res)) + res + fields let searchable_type_of_record parent_type type_ = let open Odoc_model.Lang in @@ -111,40 +111,36 @@ let searchable_type_of_record parent_type type_ = let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = let open Odoc_search.Entry in match kind with - | TypeDecl _ -> - Entry.Kind.TypeDecl (Odoc_search.Html.typedecl_params_of_entry entry) + | TypeDecl _ -> Entry.Kind.TypeDecl (Odoc_search.Html.typedecl_params_of_entry entry) | Module -> Entry.Kind.Module | Value { value = _; type_ } -> - let typ = typ_of_odoc_typ type_ in - Entry.Kind.val_ typ + let typ = typ_of_odoc_typ type_ in + Entry.Kind.val_ typ | Constructor { args; res } -> - let searchable_type = searchable_type_of_constructor args res in - let typ = typ_of_odoc_typ searchable_type in - Entry.Kind.constructor typ + let searchable_type = searchable_type_of_constructor args res in + let typ = typ_of_odoc_typ searchable_type in + Entry.Kind.constructor typ | Field { mutable_ = _; parent_type; type_ } -> - let typ = - type_ |> searchable_type_of_record parent_type |> typ_of_odoc_typ - in - Entry.Kind.field typ + let typ = type_ |> searchable_type_of_record parent_type |> typ_of_odoc_typ in + Entry.Kind.field typ | Doc _ -> Doc | Exception { args; res } -> - let searchable_type = searchable_type_of_constructor args res in - let typ = typ_of_odoc_typ searchable_type in - Entry.Kind.exception_ typ + let searchable_type = searchable_type_of_constructor args res in + let typ = typ_of_odoc_typ searchable_type in + Entry.Kind.exception_ typ | Class_type _ -> Class_type | Method _ -> Method | Class _ -> Class | TypeExtension _ -> TypeExtension | ExtensionConstructor { args; res } -> - let searchable_type = searchable_type_of_constructor args res in - let typ = typ_of_odoc_typ searchable_type in - Entry.Kind.extension_constructor typ + let searchable_type = searchable_type_of_constructor args res in + let typ = typ_of_odoc_typ searchable_type in + Entry.Kind.extension_constructor typ | ModuleType -> ModuleType let register_type_expr ~db elt type_ = let type_polarities = - type_ |> typ_of_odoc_typ - |> Db.Type_polarity.of_typ ~any_is_poly:true ~all_names:true + type_ |> typ_of_odoc_typ |> Db.Type_polarity.of_typ ~any_is_poly:true ~all_names:true in Db.store_type_polarities db elt type_polarities @@ -152,7 +148,7 @@ let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.kind) = let open Odoc_search.Entry in let open Odoc_model.Lang in if type_search - then + then ( match kind with | TypeDecl _ -> () | Module -> () @@ -166,11 +162,11 @@ let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.kind) = | ExtensionConstructor { args; res } | Constructor { args; res } | Exception { args; res } -> - let type_ = searchable_type_of_constructor args res in - register_type_expr ~db elt type_ + let type_ = searchable_type_of_constructor args res in + register_type_expr ~db elt type_ | Field { mutable_ = _; parent_type; type_ } -> - let type_ = TypeExpr.Arrow (None, parent_type, type_) in - register_type_expr ~db elt type_ + let type_ = TypeExpr.Arrow (None, parent_type, type_) in + register_type_expr ~db elt type_) let rec is_from_module_type (id : Odoc_model.Paths.Identifier.Any.t) = let open Odoc_model.Paths in @@ -178,28 +174,34 @@ let rec is_from_module_type (id : Odoc_model.Paths.Identifier.Any.t) = | `CoreType _ | `CoreException _ | `Root _ | `Page _ | `LeafPage _ -> false | `ModuleType _ -> true | #Identifier.NonSrc.t_pv as x -> - let parent = Identifier.label_parent { id with iv = x } in - is_from_module_type (parent :> Identifier.Any.t) + let parent = Identifier.label_parent { id with iv = x } in + is_from_module_type (parent :> Identifier.Any.t) | _ -> false let is_from_module_type Odoc_search.Entry.{ id; _ } = match id.iv with | `ModuleType (parent, _) -> - (* A module type itself is not *from* a module type, but it might be if one - of its parents is a module type. *) - is_from_module_type (parent :> Odoc_model.Paths.Identifier.Any.t) + (* A module type itself is not *from* a module type, but it might be if one + of its parents is a module type. *) + is_from_module_type (parent :> Odoc_model.Paths.Identifier.Any.t) | _ -> is_from_module_type id let prefixname n = match (n :> Odoc_model.Paths.Identifier.t) - |> Odoc_model.Paths.Identifier.fullname |> List.rev + |> Odoc_model.Paths.Identifier.fullname + |> List.rev with | [] -> "" | _ :: q -> q |> List.rev |> String.concat "." -let register_entry ~db ~index_name ~type_search ~index_docstring - (Odoc_search.Entry.{ id; doc; kind } as entry) = +let register_entry + ~db + ~index_name + ~type_search + ~index_docstring + (Odoc_search.Entry.{ id; doc; kind } as entry) + = let module Sherlodoc_entry = Entry in let open Odoc_search in let open Odoc_search.Entry in @@ -210,10 +212,8 @@ let register_entry ~db ~index_name ~type_search ~index_docstring in if Odoc_model.Paths.Identifier.is_internal id || is_type_extension then () - else - let full_name = - id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." - in + else ( + let full_name = id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." in let doc_txt = Text.of_doc doc in let doc_html = match doc_txt with @@ -232,13 +232,20 @@ let register_entry ~db ~index_name ~type_search ~index_docstring let url = Result.get_ok url in let is_from_module_type = is_from_module_type entry in let elt = - Sherlodoc_entry.v ~name ~kind:kind' ~rhs ~doc_html ~cost ~url - ~is_from_module_type () + Sherlodoc_entry.v + ~name + ~kind:kind' + ~rhs + ~doc_html + ~cost + ~url + ~is_from_module_type + () in if index_docstring then register_doc ~db elt doc_txt ; - (if index_name - then - match kind with - | Doc _ -> () - | _ -> register_full_name ~db full_name elt) ; - register_kind ~db ~type_search elt kind + if index_name + then ( + match kind with + | Doc _ -> () + | _ -> register_full_name ~db full_name elt) ; + register_kind ~db ~type_search elt kind) diff --git a/index/load_doc.mli b/index/load_doc.mli index f7f5ad898c..f9c855d4b4 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -1,9 +1,9 @@ -val register_entry : - db:Db.writer +val register_entry + : db:Db.writer -> index_name:bool -> type_search:bool -> index_docstring:bool -> Odoc_search.Entry.t -> unit (** [register_entry ~db ~index_name ~type_search ~index_docstring e] register - the entry [e] in [db]. *) + the entry [e] in [db]. *) diff --git a/index/typename.ml b/index/typename.ml index cd5fcb0649..d2c4c1be0f 100644 --- a/index/typename.ml +++ b/index/typename.ml @@ -11,37 +11,33 @@ let rec show_ident_long h (r : Paths.Identifier.t_pv Paths.Identifier.id) = match r.Paths.Identifier.iv with | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) | `Type (md, n) -> - Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) - | _ -> - Format.fprintf h "%S" (r |> Paths.Identifier.fullname |> String.concat ".") + Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) + | _ -> Format.fprintf h "%S" (r |> Paths.Identifier.fullname |> String.concat ".") and show_module_t h p = - Format.fprintf h "%s" + Format.fprintf + h + "%s" (Odoc_document.Url.render_path (p : Paths.Path.Module.t :> Paths.Path.t)) and show_signature h sig_ = match sig_.iv with - | `Root (_, name) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) - | `Module (pt, mdl) -> - Format.fprintf h "%a.%a" show_signature pt show_module_name mdl - | `Parameter (_, p) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string p) + | `Root (_, name) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) + | `Module (pt, mdl) -> Format.fprintf h "%a.%a" show_signature pt show_module_name mdl + | `Parameter (_, p) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string p) | `Result t -> Format.fprintf h "%a" show_signature t | `ModuleType (_, p) -> - Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) + Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) let show_type_name_verbose h : Paths.Path.Type.t -> _ = function | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_ident_long - (Resolved.identifier (t :> Resolved.t)) + let open Paths.Path in + Format.fprintf h "%a" show_ident_long (Resolved.identifier (t :> Resolved.t)) | `Identifier (path, _hidden) -> - let name = - (path :> Paths.Identifier.t) - |> Paths.Identifier.fullname |> String.concat "." - in - Format.fprintf h "%s" name + let name = + (path :> Paths.Identifier.t) |> Paths.Identifier.fullname |> String.concat "." + in + Format.fprintf h "%s" name | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x let to_string t = Format.asprintf "%a" show_type_name_verbose t diff --git a/jsoo/dune b/jsoo/dune index 28529937b0..1b1dc9fd13 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -13,8 +13,8 @@ (install (files sherlodoc.js) -; (section share) -; This ought to be in share, but for now I can only make it work in bin : I did -; not manage to fetch sherlodoc.js from share in the dune rules. -(section bin) + ; (section share) + ; This ought to be in share, but for now I can only make it work in bin : I did + ; not manage to fetch sherlodoc.js from share in the dune rules. + (section bin) (package sherlodoc)) diff --git a/jsoo/main.ml b/jsoo/main.ml index 63a4abc898..810de7068d 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -1,6 +1,7 @@ let print_error e = let open Jv.Error in - Printf.eprintf "Error : %s %s\n%s%!" + Printf.eprintf + "Error : %s %s\n%s%!" (Jstr.to_string @@ name e) (Jstr.to_string @@ message e) (Jstr.to_string @@ stack e) @@ -8,18 +9,17 @@ let print_error e = let new_ cl = Jv.(new' (get global cl)) let stream_of_string str = - let str = - str |> Brr.Tarray.of_binary_jstr |> Result.get_ok |> Brr.Tarray.to_jv - in + let str = str |> Brr.Tarray.of_binary_jstr |> Result.get_ok |> Brr.Tarray.to_jv in let stream = - new_ "ReadableStream" + new_ + "ReadableStream" Jv. [| obj [| ( "start" , callback ~arity:1 (fun controller -> - let _ = call controller "enqueue" [| str |] in - let _ = call controller "close" [||] in - ()) ) + let _ = call controller "enqueue" [| str |] in + let _ = call controller "close" [||] in + ()) ) |] |] in @@ -39,7 +39,6 @@ module Decompress_browser = struct in let open Jv in let reader = call stream "getReader" [||] in - let open Fut.Syntax in let rec read_step obj = let done_ = get obj "done" |> to_bool in @@ -55,18 +54,16 @@ module Decompress_browser = struct Fut.bind promise (function | Ok v -> read_step v | Error e -> - print_endline "error in string_of_stream" ; - print_error e ; - Fut.return ()) + print_endline "error in string_of_stream" ; + print_error e ; + Fut.return ()) in let+ () = read () in let r = Buffer.contents buffer in r let inflate str = - let dekompressor = - Jv.(new_ "DecompressionStream" [| of_string "deflate" |]) - in + let dekompressor = Jv.(new_ "DecompressionStream" [| of_string "deflate" |]) in let str = Jv.(call global "atob" [| str |]) |> Jv.to_jstr in let stream = stream_of_string str in let decompressed_stream = Jv.call stream "pipeThrough" [| dekompressor |] in @@ -98,9 +95,7 @@ let string_of_kind = let search message db = let query = Jv.get message "data" in let query = query |> Jv.to_jstr |> Jstr.to_string in - let results = - Query.(search ~shards:db { query; packages = []; limit = 50 }) - in + let results = Query.(search ~shards:db { query; packages = []; limit = 50 }) in let _ = Jv.(apply (get global "postMessage")) [| Jv.of_list @@ -114,18 +109,19 @@ let search message db = match kind with | Db.Entry.Kind.Doc -> None, None | _ -> - let rev_name = - name |> String.split_on_char '.' |> List.rev - in - ( rev_name |> List.tl |> List.rev |> String.concat "." - |> Option.some - , rev_name |> List.hd |> Option.some ) + let rev_name = name |> String.split_on_char '.' |> List.rev in + ( rev_name |> List.tl |> List.rev |> String.concat "." |> Option.some + , rev_name |> List.hd |> Option.some ) in let kind = string_of_kind kind in - let html = - Odoc_html_frontend.of_strings ~kind ~prefix_name ~name - ~typedecl_params ~rhs ~doc:doc_html + Odoc_html_frontend.of_strings + ~kind + ~prefix_name + ~name + ~typedecl_params + ~rhs + ~doc:doc_html |> List.map (Format.asprintf "%a" (Tyxml.Html.pp_elt ())) |> String.concat "\n" in @@ -142,7 +138,8 @@ let search message = let+ db = db in (* Here we catch any exception and print it. This allows us to keep running and answer requests that do not trigger exceptions. *) - try Printexc.print (search message) db with _ -> () + try Printexc.print (search message) db with + | _ -> () let main () = let module J' = Jstr in diff --git a/query/array_succ.ml b/query/array_succ.ml index 8f2cab26b8..a0eb3106db 100644 --- a/query/array_succ.ml +++ b/query/array_succ.ml @@ -16,7 +16,7 @@ let rec succ_ge ~compare elt arr lo hi = let elt_hi = get arr hi in assert (compare elt_hi elt >= 0) ; elt_hi) - else + else ( let mid = (lo + hi) / 2 in let elt' = get arr mid in let comp = compare elt' elt in @@ -24,16 +24,17 @@ let rec succ_ge ~compare elt arr lo hi = then elt' else if comp > 0 then succ_ge ~compare elt arr lo mid - else succ_ge ~compare elt arr mid hi + else succ_ge ~compare elt arr mid hi) let succ_ge ~compare elt arr = if Array.length arr = 0 then None - else - let lo = 0 and hi = Array.length arr in + else ( + let lo = 0 + and hi = Array.length arr in if not (compare (get arr (hi - 1)) elt >= 0) then None - else Some (succ_ge ~compare elt arr lo hi) + else Some (succ_ge ~compare elt arr lo hi)) let rec succ_gt ~compare elt arr lo hi = let elt_lo = get arr lo in @@ -48,7 +49,7 @@ let rec succ_gt ~compare elt arr lo hi = let elt_hi = get arr hi in assert (compare elt_hi elt > 0) ; elt_hi) - else + else ( let mid = (lo + hi) / 2 in let elt' = get arr mid in let comp = compare elt' elt in @@ -56,16 +57,17 @@ let rec succ_gt ~compare elt arr lo hi = then get arr (mid + 1) else if comp > 0 then succ_gt ~compare elt arr lo mid - else succ_gt ~compare elt arr mid hi + else succ_gt ~compare elt arr mid hi) let succ_gt ~compare elt arr = if Array.length arr = 0 then None - else - let lo = 0 and hi = Array.length arr in + else ( + let lo = 0 + and hi = Array.length arr in if not (compare (get arr (hi - 1)) elt > 0) then None - else Some (succ_gt ~compare elt arr lo hi) + else Some (succ_gt ~compare elt arr lo hi)) let succ_gt_exn ~compare elt arr = match succ_gt ~compare elt arr with diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 20e396cc66..691c872545 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -25,8 +25,7 @@ module Reasoning = struct let low_query_word = String.lowercase_ascii query_word in let has_case = low_query_word <> query_word in let name = if not has_case then String.lowercase_ascii name else name in - if String.equal query_word name - || String.ends_with ~suffix:("." ^ query_word) name + if String.equal query_word name || String.ends_with ~suffix:("." ^ query_word) name then DotSuffix else if String.starts_with ~prefix:query_word name || String.ends_with ~suffix:query_word name @@ -42,8 +41,7 @@ module Reasoning = struct then SubUnderscore else if is_substring ~sub:query_word name then Sub - else if has_case - && is_substring ~sub:low_query_word (String.lowercase_ascii name) + else if has_case && is_substring ~sub:low_query_word (String.lowercase_ascii name) then Lowercase else (* Matches only in the docstring are always worse *) Doc @@ -92,22 +90,21 @@ module Reasoning = struct | Field entry_type | Val entry_type | Exception entry_type )) ) -> - Some (Type_distance.v ~query:query_type ~entry:entry_type) + Some (Type_distance.v ~query:query_type ~entry:entry_type) | ( _ - , ( Doc | TypeDecl _ | Module | Class_type | Method | Class - | TypeExtension | ModuleType ) ) -> - None + , ( Doc | TypeDecl _ | Module | Class_type | Method | Class | TypeExtension + | ModuleType ) ) -> + None let type_in_query query_type = Result.is_ok query_type let type_in_entry entry = let open Entry in match entry.kind with - | ExtensionConstructor _ | Constructor _ | Field _ | Val _ | Exception _ -> - true - | Doc | TypeDecl _ | Module | Class_type | Method | Class | TypeExtension - | ModuleType -> - false + | ExtensionConstructor _ | Constructor _ | Field _ | Val _ | Exception _ -> true + | Doc | TypeDecl _ | Module | Class_type | Method | Class | TypeExtension | ModuleType + -> + false let is_stdlib entry = let open Entry in @@ -149,17 +146,18 @@ end (** [cost_of_reasoning r] is the cost of a entry according to the reasons contained in [r]. *) let cost_of_reasoning - Reasoning. - { is_stdlib - ; has_doc - ; name_matches - ; type_distance - ; type_in_entry - ; type_in_query - ; kind - ; name_length - ; is_from_module_type - } = + Reasoning. + { is_stdlib + ; has_doc + ; name_matches + ; type_distance + ; type_in_entry + ; type_in_query + ; kind + ; name_length + ; is_from_module_type + } + = let ignore_no_doc = match kind with | Module | ModuleType -> true @@ -176,13 +174,13 @@ let cost_of_reasoning let open Reasoning.Name_match in name_matches |> List.map (function - | DotSuffix -> 0 - | PrefixSuffix -> 103 - | SubDot -> 104 - | SubUnderscore -> 105 - | Sub -> 106 - | Lowercase -> 107 - | Doc -> 1000) + | DotSuffix -> 0 + | PrefixSuffix -> 103 + | SubDot -> 104 + | SubUnderscore -> 105 + | Sub -> 106 + | Lowercase -> 107 + | Doc -> 1000) |> List.fold_left ( + ) 0 in let type_cost = @@ -200,12 +198,16 @@ let cost_of_reasoning let is_from_module_type_cost = if is_from_module_type then 400 else 0 in (if is_stdlib then 0 else 100) + (if has_doc || ignore_no_doc then 0 else 100) - + name_matches + type_cost + kind + name_length + is_from_module_type_cost + + name_matches + + type_cost + + kind + + name_length + + is_from_module_type_cost let cost_of_entry ~query_name ~query_type entry = cost_of_reasoning (Reasoning.v query_name query_type entry) (** [update_entry ~query_name ~query_type e] updates [e.cost] to take into - account the query described by [query_name] and [query_type]. *) + account the query described by [query_name] and [query_type]. *) let update_entry ~query_name ~query_type entry = Entry.{ entry with cost = cost_of_entry ~query_name ~query_type entry } diff --git a/query/query.ml b/query/query.ml index 7a54e4b211..5282e9e570 100644 --- a/query/query.ml +++ b/query/query.ml @@ -19,14 +19,13 @@ end let collapse_occ ~count occs = Occ.fold (fun k x acc -> if k < count then acc else Succ.union (Succ.of_array x) acc) - occs Succ.empty + occs + Succ.empty let collapse_trie_occ ~count t = - Succ.( - Tree_occ.sets_tree ~union ~terminal:(collapse_occ ~count) ~union_of_array t) + Succ.(Tree_occ.sets_tree ~union ~terminal:(collapse_occ ~count) ~union_of_array t) -let collapse_trie t = - Succ.(Tree.sets_tree ~union ~terminal:of_array ~union_of_array t) +let collapse_trie t = Succ.(Tree.sets_tree ~union ~terminal:of_array ~union_of_array t) let polarities typ = List.filter @@ -35,8 +34,7 @@ let polarities typ = let find_types ~shards typ = let polarities = polarities typ in - if polarities = [] - then failwith "Query.find_types : type with empty polarities" ; + if polarities = [] then failwith "Query.find_types : type with empty polarities" ; List.fold_left (fun acc shard -> let db = Db.(shard.db_types) in @@ -50,7 +48,8 @@ let find_types ~shards typ = polarities in Succ.union acc r) - Succ.empty shards + Succ.empty + shards let find_names ~(shards : Db.t list) names = let names = List.map String.lowercase_ascii names in @@ -67,7 +66,8 @@ let find_names ~(shards : Db.t list) names = in let candidates = Succ.inter_of_list candidates in Succ.union acc candidates) - Succ.empty shards + Succ.empty + shards type t = { query : string @@ -81,9 +81,9 @@ let search ~(shards : Db.t list) query_name query_typ = | _ :: _, Error _ -> find_names ~shards query_name | [], Ok query_typ -> find_types ~shards query_typ | _ :: _, Ok query_typ -> - let results_name = find_names ~shards query_name in - let results_typ = find_types ~shards query_typ in - Succ.inter results_name results_typ + let results_name = find_names ~shards query_name in + let results_typ = find_types ~shards query_typ in + Succ.inter results_name results_typ let match_packages ~packages { Db.Entry.pkg; _ } = match pkg with @@ -103,10 +103,7 @@ let search ~(shards : Db.t list) ?(dynamic_sort = true) params = let results = List.of_seq @@ Seq.take params.limit results in let results = if dynamic_sort - then - List.map - (Dynamic_cost.update_entry ~query_name:words ~query_type:typ) - results + then List.map (Dynamic_cost.update_entry ~query_name:words ~query_type:typ) results else results in let results = List.sort Db.Entry.compare results in diff --git a/query/query.mli b/query/query.mli index 468a4567cc..f81141e058 100644 --- a/query/query.mli +++ b/query/query.mli @@ -7,8 +7,8 @@ type t = val search : shards:Db.t list -> ?dynamic_sort:bool -> t -> Db.Entry.t list (** [search ~shard ~dynamic_sort {query; packages; limit}] returns [(pretty_query, results)] where [pretty_query] is a re-printed version of [query] and - [results] is the list of results corresponding to the query and the - various parameters. + [results] is the list of results corresponding to the query and the + various parameters. - [shards] is a list of databases. [results] is the union of the results of each database of the list [shards]. If [shards] is a very long list, [api] diff --git a/query/query_parser.ml b/query/query_parser.ml index e9ba7072ff..4570bae6c0 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -1,7 +1,7 @@ let type_of_string str = let lexbuf = Lexing.from_string str in - try Ok (Type_parser.main Type_lexer.token lexbuf) - with Type_parser.Error -> Error "parse error" + try Ok (Type_parser.main Type_lexer.token lexbuf) with + | Type_parser.Error -> Error "parse error" let naive_of_string str = List.filter (fun s -> String.length s > 0) (String.split_on_char ' ' str) @@ -18,13 +18,12 @@ let of_string str = | _ when guess_type_search str -> "", Ok str | _ -> str, Error `empty in - let typ = Result.bind str_typ (fun str_typ -> - match type_of_string str_typ with - | Ok Any -> Error `any - | Ok typ -> Ok typ - | Error _ -> Error `parse) + match type_of_string str_typ with + | Ok Any -> Error `any + | Ok typ -> Ok typ + | Error _ -> Error `parse) in let words = naive_of_string str_name in words, typ diff --git a/query/query_parser.mli b/query/query_parser.mli index 9d53e92ef3..c4acfa5a7b 100644 --- a/query/query_parser.mli +++ b/query/query_parser.mli @@ -1,2 +1 @@ -val of_string : - string -> string list * (Db.Typexpr.t, [> `any | `parse | `empty ]) result +val of_string : string -> string list * (Db.Typexpr.t, [> `any | `parse | `empty ]) result diff --git a/query/succ.ml b/query/succ.ml index e43bbea6d9..8312b81df4 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -10,21 +10,21 @@ let rec print_node a ~depth s = match s with | Empty -> print_endline "Empty" | Inter (l, r) -> - print_endline "Inter" ; - print_node a ~depth l ; - print_node a ~depth r + print_endline "Inter" ; + print_node a ~depth l ; + print_node a ~depth r | Union (l, r) -> - print_endline "Union" ; - print_node a ~depth l ; - print_node a ~depth r + print_endline "Union" ; + print_node a ~depth l ; + print_node a ~depth r | Array arr -> - print_string "{ " ; - Array.iter - (fun elt -> - a elt ; - print_string " ") - arr ; - print_endline "}" + print_string "{ " ; + Array.iter + (fun elt -> + a elt ; + print_string " ") + arr ; + print_endline "}" let print_node a s = print_node a ~depth:0 s @@ -56,30 +56,30 @@ let rec succ ~compare ~strictness t elt = | Empty -> None | Array arr -> array_succ ~strictness ~compare elt arr | Union (l, r) -> - let elt_r = succ ~compare ~strictness r elt in - let elt_l = succ ~compare ~strictness l elt in - best_opt ~compare elt_l elt_r + let elt_r = succ ~compare ~strictness r elt in + let elt_l = succ ~compare ~strictness l elt in + best_opt ~compare elt_l elt_r | Inter (l, r) -> - let rec loop elt_r = - let* elt_l = succ ~compare ~strictness:Ge l elt_r in - let* elt_r = succ ~compare ~strictness:Ge r elt_l in - if compare elt_l elt_r = 0 then Some elt_l else loop elt_r - in - let* elt_l = succ ~compare ~strictness l elt in - loop elt_l + let rec loop elt_r = + let* elt_l = succ ~compare ~strictness:Ge l elt_r in + let* elt_r = succ ~compare ~strictness:Ge r elt_l in + if compare elt_l elt_r = 0 then Some elt_l else loop elt_r + in + let* elt_l = succ ~compare ~strictness l elt in + loop elt_l let rec first ~compare t = match t with | Empty -> None | Array s -> Some s.(0) | Inter (l, _) -> - let* elt = first ~compare l in - succ ~strictness:Ge ~compare t elt + let* elt = first ~compare l in + succ ~strictness:Ge ~compare t elt | Union (l, r) -> begin - let elt_l = first ~compare l in - let elt_r = first ~compare r in - best_opt ~compare elt_l elt_r - end + let elt_l = first ~compare l in + let elt_r = first ~compare r in + best_opt ~compare elt_l elt_r + end type 'a t = { cardinal : int @@ -104,17 +104,15 @@ let to_seq ~compare { s; _ } = let empty = { cardinal = 0; s = Empty } let of_array arr = - if Array.length arr = 0 - then empty - else { cardinal = Array.length arr; s = Array arr } + if Array.length arr = 0 then empty else { cardinal = Array.length arr; s = Array arr } let inter a b = match a.s, b.s with | Empty, _ | _, Empty -> empty | x, y when x == y -> a | x, y -> - let x, y = if a.cardinal < b.cardinal then x, y else y, x in - { cardinal = min a.cardinal b.cardinal; s = Inter (x, y) } + let x, y = if a.cardinal < b.cardinal then x, y else y, x in + { cardinal = min a.cardinal b.cardinal; s = Inter (x, y) } let union a b = match a.s, b.s with @@ -122,8 +120,8 @@ let union a b = | _, Empty -> a | x, y when x == y -> a | x, y -> - let x, y = if a.cardinal < b.cardinal then x, y else y, x in - { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } + let x, y = if a.cardinal < b.cardinal then x, y else y, x in + { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } (** This does a dychotomy to avoid building a comb, which would have poor performance. *) @@ -133,10 +131,10 @@ let union_of_array arr = | 0 -> empty | 1 -> arr.(lo) | dist -> - let mid = lo + (dist / 2) in - let left = loop lo mid in - let right = loop mid hi in - union left right + let mid = lo + (dist / 2) in + let left = loop lo mid in + let right = loop mid hi in + union left right in loop 0 (Array.length arr) diff --git a/query/test/test.ml b/query/test/test.ml index 374859a2f0..8a45d3e7ac 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -1,6 +1,7 @@ let () = let open Alcotest in - run "Query" + run + "Query" [ "Array_succ", Test_array.tests_succ_ge @ Test_array.tests_succ_gt ; "Succ", Test_succ.tests_to_seq ; "Type_parser", Test_type_parser.tests diff --git a/query/test/test_array.ml b/query/test/test_array.ml index 64a7d72086..280dfdf51c 100644 --- a/query/test/test_array.ml +++ b/query/test/test_array.ml @@ -37,27 +37,27 @@ let () = Random.init 123 let random_array size = let r = List.init size (fun _ -> Random.full_int (size * 2)) - |> List.sort_uniq Int.compare |> Array.of_list + |> List.sort_uniq Int.compare + |> Array.of_list in - r let tests_arr name test = List.init 50 (fun i -> - let elt = Random.full_int ((i * 2) + 1) in - let arr = random_array i in - let arr_string = - if i <= 5 - then - "[|" - ^ (arr |> Array.to_list |> List.map string_of_int - |> String.concat "; ") - ^ "|]" - else "[|...|]" - in - Alcotest.test_case - (Printf.sprintf "%s %i %s " name elt arr_string) - `Quick (test elt arr)) + let elt = Random.full_int ((i * 2) + 1) in + let arr = random_array i in + let arr_string = + if i <= 5 + then + "[|" + ^ (arr |> Array.to_list |> List.map string_of_int |> String.concat "; ") + ^ "|]" + else "[|...|]" + in + Alcotest.test_case + (Printf.sprintf "%s %i %s " name elt arr_string) + `Quick + (test elt arr)) let tests_succ_ge = tests_arr "succ_ge" test_succ_ge let tests_succ_gt = tests_arr "succ_gt" test_succ_gt diff --git a/query/test/test_succ.ml b/query/test/test_succ.ml index 9341f7f9b2..be71c31801 100644 --- a/query/test/test_succ.ml +++ b/query/test/test_succ.ml @@ -1,7 +1,7 @@ open Query.Private (** This module does the same thing as Succ, but its correctness is obvious - and its performance terrible. *) + and its performance terrible. *) module Reference = struct include Set.Make (Int) @@ -10,7 +10,7 @@ module Reference = struct end (** This module is used to construct a pair of a "set array" using [Reference] - and a Succ that are exactly the same. *) + and a Succ that are exactly the same. *) module Both = struct let empty = Reference.empty, Succ.empty let union (l, l') (r, r') = Reference.union l r, Succ.union l' r' @@ -19,7 +19,7 @@ module Both = struct end (** This is a problematic exemple that was found randomly. It is saved here - to check for regressions. *) + to check for regressions. *) let extra_succ = Both.( union @@ -30,15 +30,15 @@ let rec random_set ~empty ~union ~inter ~of_array size = let random_set = random_set ~empty ~union ~inter ~of_array in if size = 0 then empty - else + else ( match Random.int 3 with | 0 -> - let arr = Test_array.random_array size in - Array.sort Int.compare arr ; - of_array arr + let arr = Test_array.random_array size in + Array.sort Int.compare arr ; + of_array arr | 1 -> inter (random_set (size / 2)) (random_set (size / 2)) | 2 -> union (random_set (size / 2)) (random_set (size / 2)) - | _ -> assert false + | _ -> assert false) let test_to_seq tree () = let ref = fst tree |> Reference.to_seq ~compare:Int.compare |> List.of_seq in @@ -48,8 +48,6 @@ let test_to_seq tree () = let tests_to_seq = [ Alcotest.test_case "Succ.to_seq extra" `Quick (test_to_seq extra_succ) ] @ List.init 50 (fun i -> - let i = i * 7 in - let succ = i |> Both.(random_set ~empty ~union ~inter ~of_array) in - Alcotest.test_case - (Printf.sprintf "Succ.to_seq size %i" i) - `Quick (test_to_seq succ)) + let i = i * 7 in + let succ = i |> Both.(random_set ~empty ~union ~inter ~of_array) in + Alcotest.test_case (Printf.sprintf "Succ.to_seq size %i" i) `Quick (test_to_seq succ)) diff --git a/query/test/test_type_parser.ml b/query/test/test_type_parser.ml index 4bdf103480..02b62fcc58 100644 --- a/query/test/test_type_parser.ml +++ b/query/test/test_type_parser.ml @@ -11,12 +11,12 @@ let rec random_type size = | 0 | 1 -> random_elt [| random_poly; random_constr; (fun () -> any) |] () | (2 | 3 | 4) when Random.bool () -> random_constr_params size | _ when Random.int 100 < 20 -> - let n = 2 + Random.int 3 in - tuple (List.init n (fun _i -> random_type (size / n))) + let n = 2 + Random.int 3 in + tuple (List.init n (fun _i -> random_type (size / n))) | _ when Random.int 100 < 5 -> random_constr_params size | _ -> - let size = size / 2 in - arrow (random_type size) (random_type size) + let size = size / 2 in + arrow (random_type size) (random_type size) and random_constr_params size = let n_params = 1 + Random.int 3 in @@ -34,8 +34,6 @@ let test_parser typ () = let tests = List.init 50 (fun i -> - let i = i * 5 in - let typ = random_type i in - Alcotest.test_case - (Printf.sprintf "Type_parser size %i" i) - `Quick (test_parser typ)) + let i = i * 5 in + let typ = random_type i in + Alcotest.test_case (Printf.sprintf "Type_parser size %i" i) `Quick (test_parser typ)) diff --git a/query/type_distance.ml b/query/type_distance.ml index 0175ef0814..06b7e9065c 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -1,30 +1,32 @@ module Type_path : sig (** This module contains the transformation that make it possible to compute the - distance between types.. - -A type can viewed as a tree. [a -> b -> c * d] is the following tree : -{[ -> - |- a - |- -> - |- b - |- * - |- c - |- d -]} -We consider the list of paths from root to leaf in the tree of the type. - -Here the paths would be : [ [[-> a]; [-> -> b]; [-> -> * c ]; [-> -> * d]] ] - -We encode slightly more information than that. In the above, it not possible by -looking at a type path to know the child position relative to its parent : In -the path [[-> a]]; [a] is the first child of [->], and in [[-> -> b]]; [[-> b]] -is the second child of [->]. This information is not possible to recover without -the whole tree, so we add it in the list, ass a number after the arrow. - -This makes the type path of the example type look like this : - -{[ [[-> 1 a]; [-> 2 -> 1 b]; [-> 2 -> 2 * 1 c ]; [-> 2 -> 2 * 2 d]] ]} -*) + distance between types.. + + A type can viewed as a tree. [a -> b -> c * d] is the following tree : + {[ + -> + |- a + |- -> + |- b + |- * + |- c + |- d + ]} + We consider the list of paths from root to leaf in the tree of the type. + + Here the paths would be : [ [[-> a]; [-> -> b]; [-> -> * c ]; [-> -> * d]] ] + + We encode slightly more information than that. In the above, it not possible by + looking at a type path to know the child position relative to its parent : In + the path [[-> a]]; [a] is the first child of [->], and in [[-> -> b]]; [[-> b]] + is the second child of [->]. This information is not possible to recover without + the whole tree, so we add it in the list, ass a number after the arrow. + + This makes the type path of the example type look like this : + + {[ + [[-> 1 a]; [-> 2 -> 1 b]; [-> 2 -> 2 * 1 c ]; [-> 2 -> 2 * 2 d]] + ]} *) type t = string list list @@ -37,45 +39,44 @@ end = struct type t = string list list - let rev_concat lst = - List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst + let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst let rec of_typ ~ignore_any ~prefix ~sgn t = match t with | Db.Typexpr.Poly _ -> - let poly = "POLY" in - [ poly :: Sign.to_string sgn :: prefix ] + let poly = "POLY" in + [ poly :: Sign.to_string sgn :: prefix ] | Any -> - if ignore_any - then [ prefix ] - else - let poly = "POLY" in - [ poly :: Sign.to_string sgn :: prefix ] + if ignore_any + then [ prefix ] + else ( + let poly = "POLY" in + [ poly :: Sign.to_string sgn :: prefix ]) | Arrow (a, b) -> - let prefix_left = "->0" :: prefix in - let prefix_right = "->1" :: prefix in - List.rev_append - (of_typ ~ignore_any ~prefix:prefix_left ~sgn:(Sign.not sgn) a) - (of_typ ~ignore_any ~prefix:prefix_right ~sgn b) + let prefix_left = "->0" :: prefix in + let prefix_right = "->1" :: prefix in + List.rev_append + (of_typ ~ignore_any ~prefix:prefix_left ~sgn:(Sign.not sgn) a) + (of_typ ~ignore_any ~prefix:prefix_right ~sgn b) | Constr (name, args) -> - let prefix = name :: Sign.to_string sgn :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - of_typ ~ignore_any ~prefix ~sgn arg) - args - end + let prefix = name :: Sign.to_string sgn :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + of_typ ~ignore_any ~prefix ~sgn arg) + args + end | Tuple args -> - rev_concat - @@ List.mapi (fun i arg -> - let prefix = (string_of_int i ^ "*") :: prefix in - of_typ ~ignore_any ~prefix ~sgn arg) - @@ args + rev_concat + @@ List.mapi (fun i arg -> + let prefix = (string_of_int i ^ "*") :: prefix in + of_typ ~ignore_any ~prefix ~sgn arg) + @@ args | Unhandled -> [] let hcons_tbl = Hashtbl.create 16 @@ -83,20 +84,20 @@ end = struct let rec hcons = function | [] -> -1, [] - | x :: xs -> ( - let uid_xs, xs = hcons xs in - match Hashtbl.find hcons_tbl (uid_xs, x) with - | xxs -> xxs - | exception Not_found -> - let uid = !uid_generator in - uid_generator := uid + 1 ; - let result = uid, x :: xs in - Hashtbl.add hcons_tbl (uid_xs, x) result ; - result) + | x :: xs -> + let uid_xs, xs = hcons xs in + (match Hashtbl.find hcons_tbl (uid_xs, x) with + | xxs -> xxs + | exception Not_found -> + let uid = !uid_generator in + uid_generator := uid + 1 ; + let result = uid, x :: xs in + Hashtbl.add hcons_tbl (uid_xs, x) result ; + result) (** [of_typ t] is a [string list list] representing - the type [t]. It allows to compute the distance between two types. It is - stored in the database to sort results once they are obtained. *) + the type [t]. It allows to compute the distance between two types. It is + stored in the database to sort results once they are obtained. *) let of_typ ~ignore_any typ = List.map (fun xs -> @@ -123,80 +124,76 @@ let distance xs ys = | [], _ -> 0 | [ "_" ], _ -> 0 | _, [] -> List.length xs - | x :: xs, y :: ys when String.ends_with ~suffix:x y -> - memo (i + 1) (j + 1) xs ys + | x :: xs, y :: ys when String.ends_with ~suffix:x y -> memo (i + 1) (j + 1) xs ys | _, "->1" :: ys -> memo i (j + 1) xs ys | "->1" :: xs, _ -> 1 + memo (i + 1) j xs ys | _ :: xs', _ :: ys' -> - 7 - + min - (memo (i + 1) (j + 1) xs' ys') - (min (memo (i + 1) j xs' ys) (memo i (j + 1) xs ys')) + 7 + + min + (memo (i + 1) (j + 1) xs' ys') + (min (memo (i + 1) j xs' ys) (memo i (j + 1) xs ys')) in go 0 0 xs ys let minimize = function | [] -> 0 | arr -> - let used = Array.make (List.length (List.hd arr)) false in - let arr = - Array.map (fun lst -> - let lst = (1, None) :: List.mapi (fun i x -> x, Some i) lst in - List.sort Stdlib.compare lst) - @@ Array.of_list arr - in - Array.sort (fun xs ys -> Stdlib.compare xs ys) arr ; - let heuristics = Array.make (Array.length arr + 1) 0 in - for i = Array.length heuristics - 2 downto 0 do - let best = fst (List.hd arr.(i)) in - heuristics.(i) <- heuristics.(i + 1) + best - done ; - let best = ref 1000 in - let limit = ref 0 in - let rec go rem acc i = - incr limit ; - if !limit > 10_000 - then false - else if rem <= 0 - then begin - let score = acc + (1 * (Array.length arr - i)) in - best := min score !best ; - true - end - else if i >= Array.length arr - then begin - best := min !best (acc + (100 * rem)) ; - true - end - else if acc + heuristics.(i) >= !best - then true - else - let rec find = function - | [] -> true - | (cost, j) :: rest -> - let ok = - match j with - | None -> - go rem - (acc + cost - + if rem > Array.length arr - i then 100 else 0) - (i + 1) - | Some j -> - if used.(j) - then true - else begin - used.(j) <- true ; - let ok = go (rem - 1) (acc + cost) (i + 1) in - used.(j) <- false ; - ok - end - in - if ok then find rest else false - in - find arr.(i) - in - let _ = go (Array.length used) 0 0 in - !best + let used = Array.make (List.length (List.hd arr)) false in + let arr = + Array.map (fun lst -> + let lst = (1, None) :: List.mapi (fun i x -> x, Some i) lst in + List.sort Stdlib.compare lst) + @@ Array.of_list arr + in + Array.sort (fun xs ys -> Stdlib.compare xs ys) arr ; + let heuristics = Array.make (Array.length arr + 1) 0 in + for i = Array.length heuristics - 2 downto 0 do + let best = fst (List.hd arr.(i)) in + heuristics.(i) <- heuristics.(i + 1) + best + done ; + let best = ref 1000 in + let limit = ref 0 in + let rec go rem acc i = + incr limit ; + if !limit > 10_000 + then false + else if rem <= 0 + then begin + let score = acc + (1 * (Array.length arr - i)) in + best := min score !best ; + true + end + else if i >= Array.length arr + then begin + best := min !best (acc + (100 * rem)) ; + true + end + else if acc + heuristics.(i) >= !best + then true + else ( + let rec find = function + | [] -> true + | (cost, j) :: rest -> + let ok = + match j with + | None -> + go rem (acc + cost + if rem > Array.length arr - i then 100 else 0) (i + 1) + | Some j -> + if used.(j) + then true + else begin + used.(j) <- true ; + let ok = go (rem - 1) (acc + cost) (i + 1) in + used.(j) <- false ; + ok + end + in + if ok then find rest else false + in + find arr.(i)) + in + let _ = go (Array.length used) 0 0 in + !best let v ~query ~entry = let query_paths = Type_path.of_typ ~ignore_any:false query in @@ -204,11 +201,11 @@ let v ~query ~entry = match entry_paths, query_paths with | _, [] | [], _ -> 0 | _ -> - let arr = - List.map - (fun p -> - let p = List.rev p in - List.map (fun q -> distance (List.rev q) p) query_paths) - entry_paths - in - minimize arr + let arr = + List.map + (fun p -> + let p = List.rev p in + List.map (fun q -> distance (List.rev q) p) query_paths) + entry_paths + in + minimize arr diff --git a/www/packages.ml b/www/packages.ml index 8b2b97cb67..fcff8b0dda 100644 --- a/www/packages.ml +++ b/www/packages.ml @@ -7,13 +7,11 @@ type package = module M = Map.Make (String) module S = Set.Make (struct - type t = package + type t = package - let compare a b = - String.compare - (String.lowercase_ascii a.name) - (String.lowercase_ascii b.name) -end) + let compare a b = + String.compare (String.lowercase_ascii a.name) (String.lowercase_ascii b.name) + end) let pretty = function | "ai" -> "Sciences" @@ -95,8 +93,8 @@ let pretty = function | "xml" -> "Formats: Xml" | "" -> "--- TODO ---" | other -> - Format.printf "TODO: missing category name %S@." other ; - other + Format.printf "TODO: missing category name %S@." other ; + other let unescape str = let str = String.trim str in @@ -113,21 +111,21 @@ let load filename = match input_line h with | exception End_of_file -> acc | line -> - let package = - match String.split_on_char '\t' line with - | [ category; name; description ] -> - { category = pretty category - ; name - ; description = unescape description - } - | [ name; description ] -> - { category = pretty ""; name; description = unescape description } - | _ -> failwith (Printf.sprintf "invalid package: %S" line) - in - let set = try M.find package.category acc with Not_found -> S.empty in - let set = S.add package set in - let acc = M.add package.category set acc in - go acc + let package = + match String.split_on_char '\t' line with + | [ category; name; description ] -> + { category = pretty category; name; description = unescape description } + | [ name; description ] -> + { category = pretty ""; name; description = unescape description } + | _ -> failwith (Printf.sprintf "invalid package: %S" line) + in + let set = + try M.find package.category acc with + | Not_found -> S.empty + in + let set = S.add package set in + let acc = M.add package.category set acc in + go acc in let result = go M.empty in close_in h ; @@ -145,18 +143,18 @@ let html = div ~a:[ a_class [ "categories" ] ] (M.bindings packages - |> List.map (fun (category, packages) -> - div - ~a:[ a_class [ "category" ] ] - [ h3 [ txt (if category = "" then "Not classified" else category) ] - ; div - ~a:[ a_class [ "packages" ] ] - (S.elements packages - |> List.map (fun package -> - a - ~a: - [ a_href ("https://ocaml.org/p/" ^ package.name) - ; a_title package.description - ] - [ txt package.name ])) - ])) + |> List.map (fun (category, packages) -> + div + ~a:[ a_class [ "category" ] ] + [ h3 [ txt (if category = "" then "Not classified" else category) ] + ; div + ~a:[ a_class [ "packages" ] ] + (S.elements packages + |> List.map (fun package -> + a + ~a: + [ a_href ("https://ocaml.org/p/" ^ package.name) + ; a_title package.description + ] + [ txt package.name ])) + ])) diff --git a/www/ui.ml b/www/ui.ml index 7753e9e102..b94037152d 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -43,17 +43,14 @@ let render_pkg elt = let open Db.Entry in match elt.pkg with | Some { name; version } -> - let link = elt |> pkg_link |> Option.get in - [ div - ~a:[ a_class [ "pkg" ] ] - [ a - ~a:[ a_href link ] - [ txt name - ; txt " " - ; span ~a:[ a_class [ "version" ] ] [ txt version ] - ] - ] - ] + let link = elt |> pkg_link |> Option.get in + [ div + ~a:[ a_class [ "pkg" ] ] + [ a + ~a:[ a_href link ] + [ txt name; txt " "; span ~a:[ a_class [ "version" ] ] [ txt version ] ] + ] + ] | None -> [] let render_result elt = @@ -62,16 +59,12 @@ let render_result elt = let render ~pretty results = match results with - | [] -> - div ~a:[ a_class [ "query" ] ] [ txt "No results! "; code [ txt pretty ] ] + | [] -> div ~a:[ a_class [ "query" ] ] [ txt "No results! "; code [ txt pretty ] ] | _ -> - div - [ div - ~a:[ a_class [ "query" ] ] - [ txt "Results for "; code [ txt pretty ] ] - ; ul ~a:[ a_class [ "found" ] ] - @@ List.map (fun r -> li (render_result r)) results - ] + div + [ div ~a:[ a_class [ "query" ] ] [ txt "Results for "; code [ txt pretty ] ] + ; ul ~a:[ a_class [ "found" ] ] @@ List.map (fun r -> li (render_result r)) results + ] let ajax_reload = {js| @@ -122,12 +115,7 @@ let template query contents = (head (title (txt "Sherlodoc")) [ meta ~a:[ a_charset "UTF-8" ] () - ; meta - ~a: - [ a_name "viewport" - ; a_content "width=device-width, initial-scale=1" - ] - () + ; meta ~a:[ a_name "viewport"; a_content "width=device-width, initial-scale=1" ] () ; link ~rel:[ `Stylesheet ] ~href:"/s.css" () ]) @@ body [ search_form query; div ~a:[ a_id "results" ] [ contents ] ] @@ -135,25 +123,19 @@ let template query contents = let github_icon = let open Tyxml.Svg in Tyxml.Html.svg - ~a: - [ a_width (16., None) - ; a_height (16.0, None) - ; a_viewBox (0., 0., 16., 16.) - ] + ~a:[ a_width (16., None); a_height (16.0, None); a_viewBox (0., 0., 16., 16.) ] [ path ~a: [ a_d - "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 \ - 7.59.4.07.55-.17.55-.38 \ + "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 \ 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 \ 1.08.58 1.23.82.72 1.21 1.87.87 \ 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 \ - 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 \ - 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 \ - 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 \ - 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 \ - 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 \ - 8c0-4.42-3.58-8-8-8z" + 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 \ + 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 \ + 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 \ + 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 \ + 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z" ] [] ] @@ -176,18 +158,10 @@ let explain = [ h1 [ txt "Sherlodoc" ] ; p ~a:[ a_class [ "doc" ] ] - [ txt - "Fuzzy search in OCaml's documentation for almost all opam \ - packages." - ] + [ txt "Fuzzy search in OCaml's documentation for almost all opam packages." ] ; ul ~a:[ a_class [ "doc" ] ] - [ li - [ txt "Search by name: " - ; link "concat map" - ; txt " and " - ; link "Lwt pool" - ] + [ li [ txt "Search by name: "; link "concat map"; txt " and "; link "Lwt pool" ] ; li [ txt "Search by type with a colon: "; link ": list list -> list" ] ; li [ txt "Search on name and type with a colon separator: " diff --git a/www/www.ml b/www/www.ml index 1c8ce82566..eec10f6c25 100644 --- a/www/www.ml +++ b/www/www.ml @@ -24,8 +24,9 @@ let get_limit params = let default = 100 in match Dream.query params "limit" with | None -> default - | Some str -> ( - try max 1 (min default (int_of_string str)) with _ -> default) + | Some str -> + (try max 1 (min default (int_of_string str)) with + | _ -> default) let get_params params = { Query.query = get_query params @@ -42,24 +43,26 @@ let string_of_tyxml' html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) html let root fn params = let params = get_params params in - try root fn params - with err -> + try root fn params with + | err -> Format.printf "ERROR: %S@." (Printexc.to_string err) ; Dream.html (string_of_tyxml @@ Ui.template params.query Ui.explain) let root fn params = - try root fn params - with _ -> Dream.html (string_of_tyxml @@ Ui.template "" Ui.explain) + try root fn params with + | _ -> Dream.html (string_of_tyxml @@ Ui.template "" Ui.explain) let cache_header : int option -> Dream.middleware = - fun max_age f req -> + fun max_age f req -> let+ response = f req in begin match max_age with | None -> () | Some max_age -> - Dream.add_header response "Cache-Control" - ("public, max-age=" ^ string_of_int max_age) + Dream.add_header + response + "Cache-Control" + ("public, max-age=" ^ string_of_int max_age) end ; response @@ -70,10 +73,10 @@ let cors_header f req = let cors_options = Dream.options "**" (fun _ -> - let+ response = Dream.empty `No_Content in - Dream.add_header response "Access-Control-Allow-Methods" "GET, OPTIONS" ; - Dream.add_header response "Access-Control-Allow-Headers" "*" ; - response) + let+ response = Dream.empty `No_Content in + Dream.add_header response "Access-Control-Allow-Methods" "GET, OPTIONS" ; + Dream.add_header response "Access-Control-Allow-Headers" "*" ; + response) let main db_format db_filename cache_max_age = let storage = @@ -84,16 +87,20 @@ let main db_format db_filename cache_max_age = let module Storage = (val storage) in let shards = Storage.load db_filename in Dream.run ~interface:"127.0.0.1" ~port:1234 - @@ Dream.logger @@ cache_header cache_max_age @@ cors_header + @@ Dream.logger + @@ cache_header cache_max_age + @@ cors_header @@ Dream.router - [ Dream.get "/" + [ Dream.get + "/" (root (fun params -> - let+ result = api ~shards params in - string_of_tyxml @@ Ui.template params.query result)) - ; Dream.get "/api" + let+ result = api ~shards params in + string_of_tyxml @@ Ui.template params.query result)) + ; Dream.get + "/api" (root (fun params -> - let+ result = api ~shards params in - string_of_tyxml' result)) + let+ result = api ~shards params in + string_of_tyxml' result)) ; Dream.get "/s.css" (Dream.from_filesystem "static" "style.css") ; Dream.get "/robots.txt" (Dream.from_filesystem "static" "robots.txt") ; Dream.get "/favicon.ico" (Dream.from_filesystem "static" "favicon.ico") @@ -106,8 +113,7 @@ open Cmdliner let db_format = let doc = "Database format" in let kind = Arg.enum [ "ancient", `ancient; "marshal", `marshal ] in - Arg.( - required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) + Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) let db_path = let doc = "Database filename" in From 96f325bb67a760341f422a2a1b1d2a3a94d36d47 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 21 Dec 2023 14:43:18 +0100 Subject: [PATCH 208/285] refactor db storage with/without ancient dependency --- index/dune | 10 ++-------- index/index.ml | 6 ++---- .../db_store.default.ml | 2 +- .../db_store.with_ancient.ml | 2 +- store/dune | 14 +++++++++++--- www/dune | 2 +- www/www.ml | 9 ++------- 7 files changed, 20 insertions(+), 25 deletions(-) rename index/ancient.unavailable.ml => store/db_store.default.ml (68%) rename index/ancient.available.ml => store/db_store.with_ancient.ml (70%) diff --git a/index/dune b/index/dune index 85cd080c6a..1088dc6ea1 100644 --- a/index/dune +++ b/index/dune @@ -6,17 +6,11 @@ (name index) (package sherlodoc) (libraries - (select - ancient.ml - from - (storage_ancient -> ancient.available.ml) - (!storage_ancient -> ancient.unavailable.ml)) db + db_store fpath tyxml odoc.search odoc.model odoc.odoc - cmdliner - storage_marshal - storage_js)) + cmdliner)) diff --git a/index/index.ml b/index/index.ml index 508aeb3b21..9efd565b90 100644 --- a/index/index.ml +++ b/index/index.ml @@ -15,10 +15,8 @@ let index_file register filename = | Ok result -> result | Error (`Msg msg) -> Format.printf "Odoc warning or error %s: %s@." filename msg) -let storage_module = Ancient.storage_module - let main files file_list index_docstring index_name type_search db_filename db_format = - let module Storage = (val storage_module db_format) in + let module Storage = (val Db_store.storage_module db_format) in let db = Db.make () in let register id () item = List.iter @@ -54,7 +52,7 @@ let type_search = let db_format = let doc = "Database format" in - let kind = Arg.enum (Ancient.arg_enum @ [ "marshal", `marshal; "js", `js ]) in + let kind = Arg.enum Db_store.available_backends in Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) let db_filename = diff --git a/index/ancient.unavailable.ml b/store/db_store.default.ml similarity index 68% rename from index/ancient.unavailable.ml rename to store/db_store.default.ml index 403368f8d0..588bf32ddd 100644 --- a/index/ancient.unavailable.ml +++ b/store/db_store.default.ml @@ -1,4 +1,4 @@ -let arg_enum = [] +let available_backends = [ "marshal", `marshal; "js", `js ] let storage_module = function | `marshal -> (module Storage_marshal : Db.Storage.S) diff --git a/index/ancient.available.ml b/store/db_store.with_ancient.ml similarity index 70% rename from index/ancient.available.ml rename to store/db_store.with_ancient.ml index b5a09fc550..7e475fdaad 100644 --- a/index/ancient.available.ml +++ b/store/db_store.with_ancient.ml @@ -1,4 +1,4 @@ -let arg_enum = [ "ancient", `ancient ] +let available_backends = [ "ancient", `ancient; "marshal", `marshal; "js", `js ] let storage_module = function | `ancient -> (module Storage_ancient : Db.Storage.S) diff --git a/store/dune b/store/dune index 7c7127987c..d138d9cc78 100644 --- a/store/dune +++ b/store/dune @@ -1,6 +1,14 @@ -; This directory contains modules for storing search databases. The -; datastructure itself is the same each time, but the serialisation format is -; different. +(library + (name db_store) + (modules db_store) + (libraries + storage_marshal + storage_js + (select + db_store.ml + from + (storage_ancient -> db_store.with_ancient.ml) + (!storage_ancient -> db_store.default.ml)))) (library (name storage_ancient) diff --git a/www/dune b/www/dune index e3fa5b90bd..738c903fa5 100644 --- a/www/dune +++ b/www/dune @@ -5,4 +5,4 @@ (public_name sherlodoc-www) (name www) (package sherlodoc-www) - (libraries cmdliner dream tyxml db query storage_ancient storage_marshal)) + (libraries cmdliner dream tyxml db db_store query)) diff --git a/www/www.ml b/www/www.ml index eec10f6c25..d221e5de8f 100644 --- a/www/www.ml +++ b/www/www.ml @@ -79,12 +79,7 @@ let cors_options = response) let main db_format db_filename cache_max_age = - let storage = - match db_format with - | `ancient -> (module Storage_ancient : Db.Storage.S) - | `marshal -> (module Storage_marshal : Db.Storage.S) - in - let module Storage = (val storage) in + let module Storage = (val Db_store.storage_module db_format) in let shards = Storage.load db_filename in Dream.run ~interface:"127.0.0.1" ~port:1234 @@ Dream.logger @@ -112,7 +107,7 @@ open Cmdliner let db_format = let doc = "Database format" in - let kind = Arg.enum [ "ancient", `ancient; "marshal", `marshal ] in + let kind = Arg.enum Db_store.available_backends in Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) let db_path = From 412a1d7e255e3f80f9af5c416ea41b5d65ce8186 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 21 Dec 2023 17:49:45 +0100 Subject: [PATCH 209/285] simplify Db.Entry --- cli/main.ml | 10 ++-- db/entry.ml | 105 +++++++++++++++++------------------------- db/entry.mli | 70 +++++++++++----------------- db/string_map.ml | 1 - db/type_polarity.ml | 1 + index/index.ml | 3 +- index/load_doc.ml | 31 ++++++------- index/load_doc.mli | 1 + jsoo/main.ml | 10 ++-- query/dynamic_cost.ml | 69 ++++++--------------------- query/query.ml | 4 +- www/ui.ml | 34 ++++++-------- 12 files changed, 127 insertions(+), 212 deletions(-) delete mode 100644 db/string_map.ml diff --git a/cli/main.ml b/cli/main.ml index 7ce46b3db7..a0a4dc0856 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -7,15 +7,15 @@ let string_of_kind = let open Db.Entry.Kind in function | Doc -> "doc" - | TypeDecl _ -> "type" + | Type_decl _ -> "type" | Module -> "mod" | Exception _ -> "exn" | Class_type -> "class" | Method -> "meth" | Class -> "class" - | TypeExtension -> "type" - | ExtensionConstructor _ -> "cons" - | ModuleType -> "sig" + | Type_extension -> "type" + | Extension_constructor _ -> "cons" + | Module_type -> "sig" | Constructor _ -> "cons" | Field _ -> "field" | Val _ -> "val" @@ -29,7 +29,7 @@ let print_result let cost = if print_cost then string_of_int cost ^ " " else "" in let typedecl_params = (match kind with - | Db.Entry.Kind.TypeDecl args -> args + | Db.Entry.Kind.Type_decl args -> args | _ -> None) |> Option.map (fun str -> str ^ " ") |> Option.value ~default:"" diff --git a/db/entry.ml b/db/entry.ml index b0252eabcc..ee5a14053b 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -1,35 +1,27 @@ module Kind = struct - type 'a abstract = + type t = | Doc - | TypeDecl of string option | Module - | Exception of 'a + | Module_type + | Class | Class_type | Method - | Class - | TypeExtension - | ExtensionConstructor of 'a - | ModuleType - | Constructor of 'a - | Field of 'a - | Val of 'a - - type t = Typexpr.t abstract + | Val of Typexpr.t + | Type_decl of string option + | Type_extension + | Extension_constructor of Typexpr.t + | Exception of Typexpr.t + | Constructor of Typexpr.t + | Field of Typexpr.t let equal = ( = ) - let doc = Doc - let type_decl args = TypeDecl args - let module_ = Module - let exception_ typ = Exception typ - let class_type = Class_type - let method_ = Method - let class_ = Class - let type_extension = TypeExtension - let extension_constructor typ = ExtensionConstructor typ - let module_type = ModuleType - let constructor typ = Constructor typ - let field typ = Field typ - let val_ typ = Val typ + + let get_type = function + | Val typ | Extension_constructor typ | Exception typ | Constructor typ | Field typ -> + Some typ + | Doc | Module | Module_type | Class | Class_type | Method | Type_decl _ + | Type_extension -> + None end module Package = struct @@ -38,7 +30,8 @@ module Package = struct ; version : string } - let v ~name ~version = { name; version } + let compare a b = String.compare a.name b.name + let link { name; version } = Printf.sprintf "https://ocaml.org/p/%s/%s" name version end module T = struct @@ -49,44 +42,40 @@ module T = struct ; kind : Kind.t ; cost : int ; doc_html : string - ; pkg : Package.t option + ; pkg : Package.t ; is_from_module_type : bool } - let compare_pkg Package.{ name; version = _ } (b : Package.t) = - String.compare name b.name - let structural_compare a b = - begin - match Int.compare (String.length a.name) (String.length b.name) with + match Int.compare (String.length a.name) (String.length b.name) with + | 0 -> begin + match String.compare a.name b.name with | 0 -> begin - match String.compare a.name b.name with + match Package.compare a.pkg b.pkg with | 0 -> begin - match Option.compare compare_pkg a.pkg b.pkg with - | 0 -> begin - match Stdlib.compare a.kind b.kind with - | 0 -> Stdlib.compare a.url b.url - | c -> c - end + match Stdlib.compare a.kind b.kind with + | 0 -> String.compare a.url b.url | c -> c end | c -> c end | c -> c end + | c -> c let compare a b = if a == b then 0 - else ( - let cmp = Int.compare a.cost b.cost in - if cmp = 0 then structural_compare a b else cmp) + else begin + match Int.compare a.cost b.cost with + | 0 -> structural_compare a b + | cmp -> cmp + end + + let equal a b = compare a b = 0 end include T - -let equal a b = compare a b = 0 - module Set = Set.Make (T) (** Array of elts. For use in functors that require a type [t] and not ['a t].*) @@ -104,22 +93,14 @@ module Array = struct let equal_elt = equal end -let pkg_link { pkg; _ } = - match pkg with - | None -> None - | Some { name; version } -> - Some (Printf.sprintf "https://ocaml.org/p/%s/%s" name version) - let link t = - match pkg_link t with - | None -> None - | Some pkg_link -> - let name, path = - match List.rev (String.split_on_char '.' t.name) with - | name :: path -> name, String.concat "/" (List.rev path) - | _ -> "", "" - in - Some (pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name) - -let v ~name ~kind ~cost ~rhs ~doc_html ~url ~is_from_module_type ?(pkg = None) () = + let pkg_link = Package.link t.pkg in + let name, path = + match List.rev (String.split_on_char '.' t.name) with + | name :: path -> name, String.concat "/" (List.rev path) + | _ -> "", "" + in + pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name + +let v ~name ~kind ~cost ~rhs ~doc_html ~url ~is_from_module_type ~pkg () = { name; kind; url; cost; doc_html; pkg; rhs; is_from_module_type } diff --git a/db/entry.mli b/db/entry.mli index c87777b3b0..8fd6df97a2 100644 --- a/db/entry.mli +++ b/db/entry.mli @@ -1,35 +1,21 @@ module Kind : sig - type 'a abstract = + type t = | Doc - | TypeDecl of string option | Module - | Exception of 'a + | Module_type + | Class | Class_type | Method - | Class - | TypeExtension - | ExtensionConstructor of 'a - | ModuleType - | Constructor of 'a - | Field of 'a - | Val of 'a - - type t = Typexpr.t abstract + | Val of Typexpr.t + | Type_decl of string option + | Type_extension + | Extension_constructor of Typexpr.t + | Exception of Typexpr.t + | Constructor of Typexpr.t + | Field of Typexpr.t - val equal : 'a -> 'a -> bool - val doc : 'a abstract - val type_decl : string option -> 'a abstract - val module_ : 'a abstract - val exception_ : 'a -> 'a abstract - val class_type : 'a abstract - val method_ : 'a abstract - val class_ : 'a abstract - val type_extension : 'a abstract - val extension_constructor : 'a -> 'a abstract - val module_type : 'a abstract - val constructor : 'a -> 'a abstract - val field : 'a -> 'a abstract - val val_ : 'a -> 'a abstract + val equal : t -> t -> bool + val get_type : t -> Typexpr.t option end module Package : sig @@ -38,7 +24,7 @@ module Package : sig ; version : string } - val v : name:string -> version:string -> t + val link : t -> string end type t = @@ -48,10 +34,23 @@ type t = ; kind : Kind.t ; cost : int ; doc_html : string - ; pkg : Package.t option + ; pkg : Package.t ; is_from_module_type : bool } +val v + : name:string + -> kind:Kind.t + -> cost:int + -> rhs:string option + -> doc_html:string + -> url:string + -> is_from_module_type:bool + -> pkg:Package.t + -> unit + -> t + +val link : t -> string val compare : t -> t -> int val equal : t -> t -> bool @@ -65,18 +64,3 @@ module Array : sig val of_list : elt list -> t val equal_elt : elt -> elt -> bool end - -val pkg_link : t -> string option -val link : t -> string option - -val v - : name:string - -> kind:Kind.t - -> cost:int - -> rhs:string option - -> doc_html:string - -> url:string - -> is_from_module_type:bool - -> ?pkg:Package.t option - -> unit - -> t diff --git a/db/string_map.ml b/db/string_map.ml deleted file mode 100644 index 99d658088e..0000000000 --- a/db/string_map.ml +++ /dev/null @@ -1 +0,0 @@ -include Map.Make (String) diff --git a/db/type_polarity.ml b/db/type_polarity.ml index 7bfc307df4..12ed04b72f 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -1,3 +1,4 @@ +module String_map = Map.Make (String) open Typexpr let regroup lst = diff --git a/index/index.ml b/index/index.ml index 9efd565b90..e0be37113a 100644 --- a/index/index.ml +++ b/index/index.ml @@ -18,9 +18,10 @@ let index_file register filename = let main files file_list index_docstring index_name type_search db_filename db_format = let module Storage = (val Db_store.storage_module db_format) in let db = Db.make () in + let pkg = { Db.Entry.Package.name = ""; version = "" } in let register id () item = List.iter - (Load_doc.register_entry ~db ~index_docstring ~index_name ~type_search) + (Load_doc.register_entry ~db ~index_docstring ~index_name ~type_search ~pkg) (Odoc_search.Entry.entries_of_item id item) in let h = Storage.open_out db_filename in diff --git a/index/load_doc.ml b/index/load_doc.ml index c5af61f968..5f8575824a 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -12,18 +12,15 @@ let generic_cost ~ignore_no_doc name has_doc = + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 let kind_cost (kind : Entry.Kind.t) = - match kind with - | Constructor typ | Field typ | Val typ -> Db.Typexpr.size typ - | Doc -> 400 - | TypeDecl _ | Module -> 0 - | Exception _ | Class_type | Method | Class -> 10 - | TypeExtension -> 1000 - | ExtensionConstructor _ | ModuleType -> 10 + match kind, Entry.Kind.get_type kind with + | _, Some typ -> Db.Typexpr.size typ + | Doc, _ -> 400 + | _ -> 0 let cost ~name ~kind ~doc_html = let ignore_no_doc = match kind with - | Entry.Kind.Module | ModuleType -> true + | Entry.Kind.Module | Module_type -> true | _ -> false in let has_doc = doc_html <> "" in @@ -111,32 +108,32 @@ let searchable_type_of_record parent_type type_ = let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = let open Odoc_search.Entry in match kind with - | TypeDecl _ -> Entry.Kind.TypeDecl (Odoc_search.Html.typedecl_params_of_entry entry) + | TypeDecl _ -> Entry.Kind.Type_decl (Odoc_search.Html.typedecl_params_of_entry entry) | Module -> Entry.Kind.Module | Value { value = _; type_ } -> let typ = typ_of_odoc_typ type_ in - Entry.Kind.val_ typ + Entry.Kind.Val typ | Constructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in let typ = typ_of_odoc_typ searchable_type in - Entry.Kind.constructor typ + Entry.Kind.Constructor typ | Field { mutable_ = _; parent_type; type_ } -> let typ = type_ |> searchable_type_of_record parent_type |> typ_of_odoc_typ in - Entry.Kind.field typ + Entry.Kind.Field typ | Doc _ -> Doc | Exception { args; res } -> let searchable_type = searchable_type_of_constructor args res in let typ = typ_of_odoc_typ searchable_type in - Entry.Kind.exception_ typ + Entry.Kind.Exception typ | Class_type _ -> Class_type | Method _ -> Method | Class _ -> Class - | TypeExtension _ -> TypeExtension + | TypeExtension _ -> Type_extension | ExtensionConstructor { args; res } -> let searchable_type = searchable_type_of_constructor args res in let typ = typ_of_odoc_typ searchable_type in - Entry.Kind.extension_constructor typ - | ModuleType -> ModuleType + Entry.Kind.Extension_constructor typ + | ModuleType -> Module_type let register_type_expr ~db elt type_ = let type_polarities = @@ -200,6 +197,7 @@ let register_entry ~index_name ~type_search ~index_docstring + ~pkg (Odoc_search.Entry.{ id; doc; kind } as entry) = let module Sherlodoc_entry = Entry in @@ -240,6 +238,7 @@ let register_entry ~cost ~url ~is_from_module_type + ~pkg () in if index_docstring then register_doc ~db elt doc_txt ; diff --git a/index/load_doc.mli b/index/load_doc.mli index f9c855d4b4..5b1591005b 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -3,6 +3,7 @@ val register_entry -> index_name:bool -> type_search:bool -> index_docstring:bool + -> pkg:Db.Entry.Package.t -> Odoc_search.Entry.t -> unit (** [register_entry ~db ~index_name ~type_search ~index_docstring e] register diff --git a/jsoo/main.ml b/jsoo/main.ml index 810de7068d..0b672f438b 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -79,15 +79,15 @@ let string_of_kind = let open Odoc_html_frontend in function | Db.Entry.Kind.Doc -> kind_doc - | TypeDecl _ -> kind_typedecl + | Type_decl _ -> kind_typedecl | Module -> kind_module | Exception _ -> kind_exception | Class_type -> kind_class_type | Method -> kind_method | Class -> kind_class - | TypeExtension -> kind_extension - | ExtensionConstructor _ -> kind_extension_constructor - | ModuleType -> kind_module_type + | Type_extension -> kind_extension + | Extension_constructor _ -> kind_extension_constructor + | Module_type -> kind_module_type | Constructor _ -> kind_constructor | Field _ -> kind_field | Val _ -> kind_value @@ -102,7 +102,7 @@ let search message db = (fun Db.Entry.{ name; rhs; doc_html; kind; url; _ } -> let typedecl_params = match kind with - | Db.Entry.Kind.TypeDecl args -> args + | Db.Entry.Kind.Type_decl args -> args | _ -> None in let prefix_name, name = diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 691c872545..3f1d732eb3 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -51,22 +51,6 @@ module Reasoning = struct | _ -> List.map (fun word -> with_word word entry.Entry.name) query_words end - (** The kind of the entry is used to rank it, but the payload is not needed. *) - type kind = - | Doc - | TypeDecl - | Module - | Exception - | Class_type - | Method - | Class - | TypeExtension - | ExtensionConstructor - | ModuleType - | Constructor - | Field - | Val - type t = { is_stdlib : bool ; name_length : int @@ -75,57 +59,30 @@ module Reasoning = struct ; type_distance : int option ; type_in_query : bool ; type_in_entry : bool - ; kind : kind + ; kind : Entry.Kind.t ; is_from_module_type : bool } let type_distance query_type entry = let open Entry in - match query_type, entry.kind with + match query_type, Entry.Kind.get_type entry.kind with | Error _, _ -> None - | ( Ok query_type - , Entry.Kind.( - ( ExtensionConstructor entry_type - | Constructor entry_type - | Field entry_type - | Val entry_type - | Exception entry_type )) ) -> + | Ok query_type, Some entry_type -> Some (Type_distance.v ~query:query_type ~entry:entry_type) - | ( _ - , ( Doc | TypeDecl _ | Module | Class_type | Method | Class | TypeExtension - | ModuleType ) ) -> - None + | _, None -> None let type_in_query query_type = Result.is_ok query_type let type_in_entry entry = let open Entry in - match entry.kind with - | ExtensionConstructor _ | Constructor _ | Field _ | Val _ | Exception _ -> true - | Doc | TypeDecl _ | Module | Class_type | Method | Class | TypeExtension | ModuleType - -> - false + match Entry.Kind.get_type entry.kind with + | Some _ -> true + | None -> false let is_stdlib entry = let open Entry in String.starts_with ~prefix:"Stdlib." entry.name - let kind entry = - match entry.Entry.kind with - | Entry.Kind.Doc -> Doc - | Entry.Kind.TypeDecl _ -> TypeDecl - | Entry.Kind.Module -> Module - | Entry.Kind.Exception _ -> Exception - | Entry.Kind.Class_type -> Class_type - | Entry.Kind.Method -> Method - | Entry.Kind.Class -> Class - | Entry.Kind.TypeExtension -> TypeExtension - | Entry.Kind.ExtensionConstructor _ -> ExtensionConstructor - | Entry.Kind.ModuleType -> ModuleType - | Entry.Kind.Constructor _ -> Constructor - | Entry.Kind.Field _ -> Field - | Entry.Kind.Val _ -> Val - let name_length entry = String.length entry.Entry.name let is_from_module_type entry = entry.Entry.is_from_module_type @@ -137,7 +94,7 @@ module Reasoning = struct ; type_distance = type_distance query_type entry ; type_in_entry = type_in_entry entry ; type_in_query = type_in_query query_type - ; kind = kind entry + ; kind = entry.kind ; name_length = name_length entry ; is_from_module_type = is_from_module_type entry } @@ -160,15 +117,15 @@ let cost_of_reasoning = let ignore_no_doc = match kind with - | Module | ModuleType -> true + | Module | Module_type -> true | _ -> false in let kind = match kind with - | Val | Module | ModuleType | Constructor | Field | TypeDecl -> 0 - | Exception -> 30 - | Class_type | Class | TypeExtension -> 40 - | ExtensionConstructor | Method | Doc -> 50 + | Val _ | Module | Module_type | Constructor _ | Field _ | Type_decl _ -> 0 + | Exception _ -> 30 + | Class_type | Class | Type_extension -> 40 + | Extension_constructor _ | Method | Doc -> 50 in let name_matches = let open Reasoning.Name_match in diff --git a/query/query.ml b/query/query.ml index 5282e9e570..71c6ecc304 100644 --- a/query/query.ml +++ b/query/query.ml @@ -86,9 +86,7 @@ let search ~(shards : Db.t list) query_name query_typ = Succ.inter results_name results_typ let match_packages ~packages { Db.Entry.pkg; _ } = - match pkg with - | Some { name; version = _ } -> List.exists (String.equal name) packages - | None -> false + List.exists (String.equal pkg.name) packages let match_packages ~packages results = match packages with diff --git a/www/ui.ml b/www/ui.ml index b94037152d..e61fc7bd14 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -4,25 +4,21 @@ let list_of_option = function | None -> [] | Some x -> [ x ] -let render_link elt = - let open Db.Entry in - match link elt with - | Some link -> [ a_href link ] - | None -> [] +let render_link elt = [ a_href (Db.Entry.link elt) ] let string_of_kind = let open Db.Entry.Kind in function | Doc -> "doc" - | TypeDecl _ -> "type" + | Type_decl _ -> "type" | Module -> "mod" | Exception _ -> "exn" | Class_type -> "class" | Method -> "meth" | Class -> "class" - | TypeExtension -> "type" - | ExtensionConstructor _ -> "cons" - | ModuleType -> "sig" + | Type_extension -> "type" + | Extension_constructor _ -> "cons" + | Module_type -> "sig" | Constructor _ -> "cons" | Field _ -> "field" | Val _ -> "val" @@ -41,17 +37,15 @@ let render_elt elt = let render_pkg elt = let open Db.Entry in - match elt.pkg with - | Some { name; version } -> - let link = elt |> pkg_link |> Option.get in - [ div - ~a:[ a_class [ "pkg" ] ] - [ a - ~a:[ a_href link ] - [ txt name; txt " "; span ~a:[ a_class [ "version" ] ] [ txt version ] ] - ] - ] - | None -> [] + let { Package.name; version } = elt.pkg in + let link = Package.link elt.pkg in + [ div + ~a:[ a_class [ "pkg" ] ] + [ a + ~a:[ a_href link ] + [ txt name; txt " "; span ~a:[ a_class [ "version" ] ] [ txt version ] ] + ] + ] let render_result elt = let open Db.Entry in From cdfb34da59d55a9fe2ac0cee2d723107ba93bdc2 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 21 Dec 2023 18:29:13 +0100 Subject: [PATCH 210/285] simplify index typename --- index/typename.ml | 46 +++++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/index/typename.ml b/index/typename.ml index d2c4c1be0f..3f052927e4 100644 --- a/index/typename.ml +++ b/index/typename.ml @@ -1,43 +1,31 @@ -(* This might be hard to maintain but it is useful *) - -open Odoc_model +module Path = Odoc_model.Paths.Path +module Identifier = Odoc_model.Paths.Identifier +module TypeName = Odoc_model.Names.TypeName module ModuleName = Odoc_model.Names.ModuleName -module H = Tyxml.Html - -let show_module_name h md = - Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string md) - -let rec show_ident_long h (r : Paths.Identifier.t_pv Paths.Identifier.id) = - match r.Paths.Identifier.iv with - | `CoreType n -> Format.fprintf h "Stdlib.%s" (Names.TypeName.to_string n) - | `Type (md, n) -> - Format.fprintf h "%a.%s" show_signature md (Names.TypeName.to_string n) - | _ -> Format.fprintf h "%S" (r |> Paths.Identifier.fullname |> String.concat ".") -and show_module_t h p = - Format.fprintf - h - "%s" - (Odoc_document.Url.render_path (p : Paths.Path.Module.t :> Paths.Path.t)) +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 ".") and show_signature h sig_ = match sig_.iv with - | `Root (_, name) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string name) - | `Module (pt, mdl) -> Format.fprintf h "%a.%a" show_signature pt show_module_name mdl - | `Parameter (_, p) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleName.to_string p) + | `Root (_, name) -> Format.fprintf h "%s" (ModuleName.to_string name) + | `Module (pt, mdl) -> + Format.fprintf h "%a.%s" show_signature pt (ModuleName.to_string mdl) + | `Parameter (_, p) -> Format.fprintf h "%s" (ModuleName.to_string p) | `Result t -> Format.fprintf h "%a" show_signature t | `ModuleType (_, p) -> Format.fprintf h "%s" (Odoc_model.Names.ModuleTypeName.to_string p) -let show_type_name_verbose h : Paths.Path.Type.t -> _ = function +let show_type_name_verbose h : Path.Type.t -> _ = function | `Resolved t -> - let open Paths.Path in - Format.fprintf h "%a" show_ident_long (Resolved.identifier (t :> Resolved.t)) + Format.fprintf h "%a" show_ident_long Path.Resolved.(identifier (t :> t)) | `Identifier (path, _hidden) -> - let name = - (path :> Paths.Identifier.t) |> Paths.Identifier.fullname |> String.concat "." - in + let name = String.concat "." @@ Identifier.fullname path in Format.fprintf h "%s" name - | `Dot (mdl, x) -> Format.fprintf h "%a.%s" show_module_t mdl x + | `Dot (mdl, x) -> + Format.fprintf h "%s.%s" (Odoc_document.Url.render_path (mdl :> Path.t)) x let to_string t = Format.asprintf "%a" show_type_name_verbose t From 194a4f53724b7f813913113724a72aef062a4751 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 29 Dec 2023 12:15:03 +0100 Subject: [PATCH 211/285] fix ancient segfaults on empty strings / arrays --- cli/dune | 2 +- cli/main.ml | 14 ++++++++++++-- db/entry.ml | 31 +++++++++++++++++++++++++----- db/entry.mli | 6 ++++-- db/occ.ml | 2 +- db/suffix_tree.ml | 23 ++++++++++++++++------ index/index.ml | 16 ++++++++++----- query/dynamic_cost.ml | 3 ++- query/query.ml | 3 ++- query/succ.ml | 4 ++++ query/succ.mli | 3 ++- test/cram/base_cli.t | 20 ++++++++++--------- test/cram/cli.t/run.t | 3 ++- test/cram/cli_poly.t/run.t | 3 ++- test/cram/cli_small.t/run.t | 3 ++- test/cram/module_type_cost.t/run.t | 3 ++- test/cram/query_syntax.t | 3 ++- 17 files changed, 103 insertions(+), 39 deletions(-) diff --git a/cli/dune b/cli/dune index a7f4ccdbed..be779407bd 100644 --- a/cli/dune +++ b/cli/dune @@ -7,4 +7,4 @@ (name main) (public_name sherlodoc) (package sherlodoc) - (libraries cmdliner query storage_marshal)) + (libraries cmdliner query db_store)) diff --git a/cli/main.ml b/cli/main.ml index a0a4dc0856..cb0b880d96 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -59,7 +59,7 @@ let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db = search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db | None -> print_endline "[Search session ended]" -let main db query print_cost no_rhs static_sort limit pretty_query = +let main db_format db query print_cost no_rhs static_sort limit pretty_query = match db with | None -> output_string @@ -68,7 +68,8 @@ let main db query print_cost no_rhs static_sort limit pretty_query = using the --db option\n" ; exit 1 | Some db -> - let db = Storage_marshal.load db in + let module Storage = (val Db_store.storage_module db_format) in + let db = Storage.load db in (match query with | None -> search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db | Some query -> @@ -76,6 +77,14 @@ let main db query print_cost no_rhs static_sort limit pretty_query = open Cmdliner +let db_format = + let env = + let doc = "Database format" in + Cmd.Env.info "SHERLODOC_FORMAT" ~doc + in + let kind = Arg.enum Db_store.available_backends in + Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~env) + let db_filename = let env = let doc = "The database to query" in @@ -114,6 +123,7 @@ let pretty_query = let main = Term.( const main + $ db_format $ db_filename $ query $ print_cost diff --git a/db/entry.ml b/db/entry.ml index ee5a14053b..406b178093 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -1,3 +1,6 @@ +let empty_string = String.make 0 '_' +let non_empty_string s = if s = "" then empty_string else s + module Kind = struct type t = | Doc @@ -16,7 +19,8 @@ module Kind = struct let equal = ( = ) - let get_type = function + let get_type t = + 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 _ @@ -30,6 +34,9 @@ module Package = struct ; version : string } + let v ~name ~version = + { name = non_empty_string name; version = non_empty_string version } + let compare a b = String.compare a.name b.name let link { name; version } = Printf.sprintf "https://ocaml.org/p/%s/%s" name version end @@ -81,14 +88,20 @@ module Set = Set.Make (T) (** Array of elts. For use in functors that require a type [t] and not ['a t].*) module Array = struct type elt = t - type nonrec t = t array + type t = elt array option + + let is_empty = function + | None -> true + | Some arr -> + assert (Array.length arr > 0) ; + false - let is_empty arr = Array.length arr = 0 + let empty = None let of_list arr = let arr = Array.of_list arr in Array.sort compare arr ; - arr + if Array.length arr = 0 then empty else Some arr let equal_elt = equal end @@ -103,4 +116,12 @@ let link t = pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name let v ~name ~kind ~cost ~rhs ~doc_html ~url ~is_from_module_type ~pkg () = - { name; kind; url; cost; doc_html; pkg; rhs; is_from_module_type } + { name = non_empty_string name + ; kind + ; url = non_empty_string url + ; cost + ; doc_html = non_empty_string doc_html + ; pkg + ; rhs = Option.map non_empty_string rhs + ; is_from_module_type + } diff --git a/db/entry.mli b/db/entry.mli index 8fd6df97a2..7e107574d3 100644 --- a/db/entry.mli +++ b/db/entry.mli @@ -19,11 +19,12 @@ module Kind : sig end module Package : sig - type t = + type t = private { name : string ; version : string } + val v : name:string -> version:string -> t val link : t -> string end @@ -58,8 +59,9 @@ module Set : Set.S with type elt = t module Array : sig type elt = t - type nonrec t = t array + type t = elt array option + val empty : t val is_empty : t -> bool val of_list : elt list -> t val equal_elt : elt -> elt -> bool diff --git a/db/occ.ml b/db/occ.ml index 70932fcabe..9d657cc347 100644 --- a/db/occ.ml +++ b/db/occ.ml @@ -1,6 +1,6 @@ module Int_map = Map.Make (Int) -type t = Entry.Array.t Int_map.t +type t = Entry.t array Int_map.t type elt = int * Entry.t let find = Int_map.find_opt diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index 89a0b3a429..dc1f97344c 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -326,7 +326,7 @@ module Make (S : SET) = struct { start : int ; len : int ; terminals : S.t - ; children : node array + ; children : node array option } type t = @@ -344,6 +344,10 @@ module Make (S : SET) = struct in go 0 + let array_find ~str chr = function + | None -> raise Not_found + | Some arr -> array_find ~str chr arr + let lcp i_str i j_str j j_len = let j_stop = j + j_len in let rec go_lcp i j = @@ -382,15 +386,21 @@ module Make (S : SET) = struct let rec collapse acc t = let acc = if S.is_empty t.terminals then acc else t.terminals :: acc in - Array.fold_left collapse acc t.children + match t.children with + | None -> acc + | Some children -> Array.fold_left collapse acc children let collapse t = collapse [] t.t let rec sets_tree ~union ~terminal ~union_of_array t = - union - (terminal t.terminals) - (union_of_array - (Array.map (sets_tree ~union ~terminal ~union_of_array) t.children)) + let ts = terminal t.terminals in + let cs = + match t.children with + | None -> [||] + | Some children -> + Array.map (sets_tree ~union ~terminal ~union_of_array) children + in + union ts (union_of_array cs) let sets_tree ~union ~terminal ~union_of_array t = sets_tree ~union ~terminal ~union_of_array t.t @@ -415,6 +425,7 @@ module Make (S : SET) = struct let children = Array.of_list @@ List.map (fun (_, (_, child)) -> child) children in + let children = if Array.length children = 0 then None else Some children in let node = { T.start = node.start; len = node.len; terminals; children } in let result = Uid.make (), node in Hashtbl.add cache key result ; diff --git a/index/index.ml b/index/index.ml index e0be37113a..f4af9103f0 100644 --- a/index/index.ml +++ b/index/index.ml @@ -18,7 +18,7 @@ let index_file register filename = let main files file_list index_docstring index_name type_search db_filename db_format = let module Storage = (val Db_store.storage_module db_format) in let db = Db.make () in - let pkg = { Db.Entry.Package.name = ""; version = "" } in + let pkg = Db.Entry.Package.v ~name:"" ~version:"" in let register id () item = List.iter (Load_doc.register_entry ~db ~index_docstring ~index_name ~type_search ~pkg) @@ -52,13 +52,19 @@ let type_search = Arg.(value & opt bool true & info ~doc [ "type-search" ]) let db_format = - let doc = "Database format" in + let env = + let doc = "Database format" in + Cmd.Env.info "SHERLODOC_FORMAT" ~doc + in let kind = Arg.enum Db_store.available_backends in - Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) + Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~env) let db_filename = - let doc = "Output filename" in - Arg.(required & opt (some string) None & info [ "db"; "output"; "o" ] ~docv:"DB" ~doc) + let env = + let doc = "The database to create" in + Cmd.Env.info "SHERLODOC_DB" ~doc + in + Arg.(required & opt (some string) None & info [ "db"; "output"; "o" ] ~docv:"DB" ~env) let file_list = let doc = diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 3f1d732eb3..a2b7a62869 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -85,11 +85,12 @@ module Reasoning = struct let name_length entry = String.length entry.Entry.name let is_from_module_type entry = entry.Entry.is_from_module_type + let has_doc e = e.Entry.doc_html <> "" (** Compute the reasoning for the cost of an entry *) let v query_words query_type entry = { is_stdlib = is_stdlib entry - ; has_doc = entry.Entry.doc_html <> "" + ; has_doc = has_doc entry ; name_matches = Name_match.with_words query_words entry ; type_distance = type_distance query_type entry ; type_in_entry = type_in_entry entry diff --git a/query/query.ml b/query/query.ml index 71c6ecc304..fe3aa9fb13 100644 --- a/query/query.ml +++ b/query/query.ml @@ -25,7 +25,8 @@ let collapse_occ ~count occs = let collapse_trie_occ ~count t = Succ.(Tree_occ.sets_tree ~union ~terminal:(collapse_occ ~count) ~union_of_array t) -let collapse_trie t = Succ.(Tree.sets_tree ~union ~terminal:of_array ~union_of_array t) +let collapse_trie t = + Succ.(Tree.sets_tree ~union ~terminal:of_array_opt ~union_of_array t) let polarities typ = List.filter diff --git a/query/succ.ml b/query/succ.ml index 8312b81df4..3a878a18c7 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -106,6 +106,10 @@ let empty = { cardinal = 0; s = Empty } let of_array arr = if Array.length arr = 0 then empty else { cardinal = Array.length arr; s = Array arr } +let of_array_opt = function + | None -> empty + | Some arr -> of_array arr + let inter a b = match a.s, b.s with | Empty, _ | _, Empty -> empty diff --git a/query/succ.mli b/query/succ.mli index 6ae7940f07..fb367717ce 100644 --- a/query/succ.mli +++ b/query/succ.mli @@ -9,8 +9,9 @@ val to_seq : compare:('a -> 'a -> int) -> 'a t -> 'a Seq.t (** Functions to build a succ tree *) val empty : 'a t - val of_array : 'a array -> 'a t + +val of_array_opt : 'a array option -> 'a t (** Warning : only provide a sorted array, this is not checked ! It has to be sorted according to the [compare] function that you will eventually pass to [to_seq]. *) diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index ab1f454d49..3ee6f74091 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -5,8 +5,10 @@ ./base_odocls/md5_lib.odocl ./base_odocls/page-index.odocl ./base_odocls/shadow_stdlib.odocl - $ sherlodoc_index --format=marshal --index-docstring=false --db=db_marshal.bin $(find . -name '*.odocl') 2> /dev/null - $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin --limit 100 "S_poly" + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=ancient + $ sherlodoc_index --index-docstring=false $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc --print-cost --no-rhs --limit 100 "S_poly" 115 sig Base.Map.S_poly 115 sig Base.Set.S_poly 119 sig Base.Hashtbl.S_poly @@ -107,7 +109,7 @@ 731 val Base.Set.S_poly.max_elt_exn 731 val Base.Set.S_poly.min_elt_exn 732 val Base.Hashtbl.S_poly.hashable - $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin "group b" + $ sherlodoc --print-cost --no-rhs "group b" 218 val Base.List.group 221 val Base.Hashtbl.group 222 val Base.Sequence.group @@ -127,7 +129,7 @@ 831 val Base.Set.S_poly.group_by 842 val Base.Set.Accessors_generic.group_by 855 val Base.Set.Creators_and_accessors_generic.group_by - $ sherlodoc --no-rhs --db=db_marshal.bin "group by" + $ sherlodoc --no-rhs "group by" val Base.Set.group_by val Base.Set.Poly.group_by val Base.Set.Using_comparator.group_by @@ -135,7 +137,7 @@ val Base.Set.S_poly.group_by val Base.Set.Accessors_generic.group_by val Base.Set.Creators_and_accessors_generic.group_by - $ sherlodoc --print-cost --db=db_marshal.bin "map2" + $ sherlodoc --print-cost "map2" 214 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t 216 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 218 val Base.Or_error.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t @@ -188,16 +190,16 @@ 742 val Base.Applicative.Basic2_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] 742 val Base.Applicative.Basic3_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - $ sherlodoc --print-cost --no-rhs --db=db_marshal.bin --static-sort "List map2" + $ sherlodoc --print-cost --no-rhs --static-sort "List map2" 202 val Base.List.rev_map2_exn 208 val Base.List.map2_exn 215 val Base.List.map2 239 val Base.List.rev_map2 292 val Base.List.Cartesian_product.map2 - $ sherlodoc --no-rhs --db=db_marshal.bin "Base.Hashtbl.S_without_submodules.group" + $ sherlodoc --no-rhs "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group - $ sherlodoc --print-cost --db=db_marshal.bin "list" + $ sherlodoc --print-cost "list" 109 mod Base.List 109 mod Caml.List 118 mod Shadow_stdlib.List @@ -251,7 +253,7 @@ 322 val Base.hash_fold_list : 'a. (Hash.state -> 'a -> Hash.state) -> Hash.state -> 'a list -> Hash.state 623 val Base.Queue.S.of_list : 'a list -> 'a t 623 val Base.Stack.S.of_list : 'a list -> 'a t - $ sherlodoc --print-cost --db=db_marshal.bin ": list" + $ sherlodoc --print-cost ": list" 116 val Base.Map.data : (_, 'v, _) t -> 'v list 116 val Base.Map.keys : ('k, _, _) t -> 'k list 118 val Base.Set.to_list : ('a, _) t -> 'a list diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 96f6bcac6a..53c5ccdb64 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -6,8 +6,9 @@ $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 8.0K megaodocl - $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=ancient + $ sherlodoc_index $(find . -name '*.odocl') $ sherlodoc "unique_name" val Main.unique_name : foo $ sherlodoc "multiple_hit" diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index 4a48da8e4c..44c16a93e1 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -6,8 +6,9 @@ $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 4.0K megaodocl - $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=ancient + $ sherlodoc_index $(find . -name '*.odocl') TODO : get a result for the query bellow $ sherlodoc ":'a" val Main.poly_1 : 'a -> 'b -> 'c diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 0cdf843a34..8337565d25 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -4,8 +4,9 @@ $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 4.0K megaodocl - $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=ancient + $ sherlodoc_index $(find . -name '*.odocl') $ sherlodoc --print-cost "list" 109 mod Main.List 209 type 'a Main.list diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t index 5875a365ea..9115565c67 100644 --- a/test/cram/module_type_cost.t/run.t +++ b/test/cram/module_type_cost.t/run.t @@ -4,8 +4,9 @@ $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 4.0K megaodocl - $ sherlodoc_index --format=marshal --db=db.bin $(find . -name '*.odocl') $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=ancient + $ sherlodoc_index $(find . -name '*.odocl') Here we expect to have the `my_function` from the module be above the one from the module type. $ sherlodoc --print-cost --no-rhs "my_function" diff --git a/test/cram/query_syntax.t b/test/cram/query_syntax.t index 6bda005193..b86d2aa4fd 100644 --- a/test/cram/query_syntax.t +++ b/test/cram/query_syntax.t @@ -3,8 +3,9 @@ We need a dummy file because sherlodoc requires an odocl. $ ocamlc -c main.mli -bin-annot -I . $ odoc compile -I . main.cmti $ odoc link -I . main.odoc - $ sherlodoc_index --format=marshal --db=db.bin main.odocl + $ export SHERLODOC_FORMAT=marshal $ export SHERLODOC_DB=db.bin + $ sherlodoc_index main.odocl $ sherlodoc --pretty-query ": int list option" : int list option [No results] From a4f017318b81b95b594b43e98cae08fb0a5f1840 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 29 Dec 2023 12:28:49 +0100 Subject: [PATCH 212/285] remove db_typedef --- db/db.ml | 15 ++++++++------- db/db.mli | 2 +- db/db_typedef.ml | 6 ------ db/storage.ml | 5 ++++- 4 files changed, 13 insertions(+), 15 deletions(-) delete mode 100644 db/db_typedef.ml diff --git a/db/db.ml b/db/db.ml index a9d39eb404..fe5b0d880c 100644 --- a/db/db.ml +++ b/db/db.ml @@ -4,7 +4,11 @@ module Occ = Occ module Storage = Storage module Type_polarity = Type_polarity module Typexpr = Typexpr -include Db_typedef + +type t = Storage.db = + { db_names : Suffix_tree.With_elts.reader + ; db_types : Suffix_tree.With_occ.reader + } type writer = { writer_names : Suffix_tree.With_elts.writer @@ -17,12 +21,9 @@ let make () = } let export db = - let db = - { db_names = Suffix_tree.With_elts.export db.writer_names - ; db_types = Suffix_tree.With_occ.export db.writer_types - } - in - db + { Storage.db_names = Suffix_tree.With_elts.export db.writer_names + ; db_types = Suffix_tree.With_occ.export db.writer_types + } let store db name elt ~count = Suffix_tree.With_occ.add_suffixes db.writer_types name (count, elt) diff --git a/db/db.mli b/db/db.mli index 7f2ea301b0..6d85214fb6 100644 --- a/db/db.mli +++ b/db/db.mli @@ -5,7 +5,7 @@ module Occ = Occ module Type_polarity = Type_polarity module Typexpr = Typexpr -type t = Db_typedef.t = +type t = Storage.db = { db_names : Suffix_tree.With_elts.reader ; db_types : Suffix_tree.With_occ.reader } diff --git a/db/db_typedef.ml b/db/db_typedef.ml deleted file mode 100644 index 58617e2778..0000000000 --- a/db/db_typedef.ml +++ /dev/null @@ -1,6 +0,0 @@ -(* This is defined in a standalone file to avoid dependency cycles*) - -type t = - { db_names : Suffix_tree.With_elts.reader - ; db_types : Suffix_tree.With_occ.reader - } diff --git a/db/storage.ml b/db/storage.ml index 0cde8d2c2c..9e9c151591 100644 --- a/db/storage.ml +++ b/db/storage.ml @@ -1,4 +1,7 @@ -type db = Db_typedef.t +type db = + { db_names : Suffix_tree.With_elts.reader + ; db_types : Suffix_tree.With_occ.reader + } module type S = sig type writer From b38af8a7b088173963507fc1d839523114784370 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 30 Dec 2023 11:25:56 +0100 Subject: [PATCH 213/285] fix menhir conflicts --- db/typexpr.ml | 10 ++++++--- query/dune | 3 --- query/query_parser.ml | 15 +++++++++++++ query/type_lexer.mll | 7 ++---- query/type_parser.mly | 44 +++++++++++++++++--------------------- test/cram/base_benchmark.t | 5 +---- test/cram/base_web.t | 8 +++---- test/cram/query_syntax.t | 26 +++++++++++++++++++++- test/cram/simple.t/run.t | 2 +- 9 files changed, 75 insertions(+), 45 deletions(-) diff --git a/db/typexpr.ml b/db/typexpr.ml index c9249e022d..34f0052c00 100644 --- a/db/typexpr.ml +++ b/db/typexpr.ml @@ -15,12 +15,16 @@ let cache t = Hashtbl.add table t t ; t +let any = Any +let unhandled = Unhandled let arrow a b = cache (Arrow (a, b)) let constr name args = cache (Constr (name, args)) -let tuple args = cache (Tuple args) let poly name = cache (Poly name) -let any = Any -let unhandled = Unhandled + +let tuple = function + | [] -> any + | [ x ] -> x + | xs -> cache (Tuple xs) let rec show = function | Arrow (a, b) -> show_parens a ^ " -> " ^ show b diff --git a/query/dune b/query/dune index bb7a30b20e..1be6efc5e8 100644 --- a/query/dune +++ b/query/dune @@ -1,6 +1,3 @@ -; This library give functions to meaningfully query the database datastructure -; defined in `db`. - (library (name query) (libraries lwt re db)) diff --git a/query/query_parser.ml b/query/query_parser.ml index 4570bae6c0..8268495c8a 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -1,4 +1,19 @@ +let balance_parens str = + let rec go i open_parens close_parens = + if i >= String.length str + then open_parens, close_parens + else ( + match str.[i] with + | '(' -> go (i + 1) (open_parens + 1) close_parens + | ')' when open_parens > 0 -> go (i + 1) (open_parens - 1) close_parens + | ')' -> go (i + 1) open_parens (close_parens + 1) + | _ -> go (i + 1) open_parens close_parens) + in + let open_parens, close_parens = go 0 0 0 in + String.make close_parens '(' ^ str ^ String.make open_parens ')' + let type_of_string str = + let str = balance_parens str in let lexbuf = Lexing.from_string str in try Ok (Type_parser.main Type_lexer.token lexbuf) with | Type_parser.Error -> Error "parse error" diff --git a/query/type_lexer.mll b/query/type_lexer.mll index eb2d1f5ac9..e0d197ae85 100644 --- a/query/type_lexer.mll +++ b/query/type_lexer.mll @@ -1,13 +1,10 @@ -(* This is the lexer for [type_parser.mly]. *) - { -open Type_parser + open Type_parser } rule token = parse | ' ' { token lexbuf } -(* "-" is treated as "->" because we assume it is an incomplete "->" *) -| "-" | "->" { ARROW } +| "-" | "->" { ARROW } (* minus sign is interpreted as an arrow to support partially written queries *) | "(" { PARENS_OPEN } | ")" { PARENS_CLOSE } | "," { COMMA } diff --git a/query/type_parser.mly b/query/type_parser.mly index b8a5124ca3..f06836daf3 100644 --- a/query/type_parser.mly +++ b/query/type_parser.mly @@ -1,8 +1,4 @@ -(* This is a parser for type expressions. It is written in a weird style to - allow for incomplete queries to be reasonably answered. It also has conflicts - for the same reason. They are impossible to solve. - Its behaviour on correct types is tested in [query/test/test_type_parser.ml] - and its behaviour on incomplete types is tested in [test/cram/query_syntax.t] *) +(* Type expressions parser, with error correction to support partially written queries. *) %{ open Db.Typexpr @@ -21,37 +17,37 @@ main: | t=typ EOF { t } - | EOF { any } ; typ: - | a=typ1 ARROW b=typ { arrow a b } - | a=typ1 ARROW EOF { arrow a any } - | ARROW b=typ { arrow any b } - | ARROW EOF { arrow any any } - | t=typ1 { t } + | t=typ2 { t } + | a=typ2 ARROW b=typ { arrow a b } ; -typ1: - | x=typ0 xs=tups { match xs with [] -> x | xs -> tuple (x::xs) } +typ2: + | xs=list1(typ1, STAR) { tuple xs } ; -tups: - | STAR x=typ0 xs=tups { x::xs } - | STAR { [any] } - | EOF { [] } - | { [] } +typ1: + | { any } + | ts=typs { tuple ts } + | ts=typs w=WORD ws=list(WORD) { + List.fold_left (fun acc w -> constr w [acc]) (constr w ts) ws + } ; typ0: | ANY { any } | w=POLY { poly w } | w=WORD { constr w [] } - | t=typ0 w=WORD { constr w [t] } - | PARENS_OPEN ts=typ_list PARENS_CLOSE w=WORD { constr w ts } - | PARENS_OPEN t=typ PARENS_CLOSE { t } - | PARENS_OPEN t=typ EOF { t } - | PARENS_OPEN EOF { any } ; -typ_list: ts=separated_list(COMMA, typ) { ts } ; +typs: + | t=typ0 { [t] } + | PARENS_OPEN ts=list1(typ, COMMA) PARENS_CLOSE { ts } + ; + +list1(term, separator): + | x=term { [x] } + | x=term separator xs=list1(term, separator) { x::xs } + ; diff --git a/test/cram/base_benchmark.t b/test/cram/base_benchmark.t index 4307d39370..e31bf53db2 100644 --- a/test/cram/base_benchmark.t +++ b/test/cram/base_benchmark.t @@ -7,11 +7,8 @@ are not crazy and discard the changes ./base_odocls/md5_lib.odocl ./base_odocls/page-index.odocl ./base_odocls/shadow_stdlib.odocl - $ time sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') - real 0m1.272s - user 0m1.210s - sys 0m0.060s diff --git a/test/cram/base_web.t b/test/cram/base_web.t index bd0ad3fc26..f51350f3cd 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -18,9 +18,9 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2644 db.js - 1996 db.js.gz - 1544 megaodocl.gz + 2700 db.js + 2036 db.js.gz + 1548 megaodocl.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f @@ -31,7 +31,7 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 264K html/sherlodoc.js + 216K html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/query_syntax.t b/test/cram/query_syntax.t index b86d2aa4fd..3dd0b1618a 100644 --- a/test/cram/query_syntax.t +++ b/test/cram/query_syntax.t @@ -35,7 +35,31 @@ Testing incomplete queries $ sherlodoc --pretty-query ": (int *" : int * _ [No results] -Testing syntax errors + $ sherlodoc --pretty-query ": foo bar qux" + : foo bar qux + [No results] + $ sherlodoc --pretty-query ": ()" + : _ + [No results] $ sherlodoc --pretty-query ": )" + : _ + [No results] + $ sherlodoc --pretty-query ": (int," + : int * _ + [No results] + $ sherlodoc --pretty-query ": (int,string" + : int * string + [No results] + $ sherlodoc --pretty-query ": 'a, 'b) result -" + : ('a, 'b) result -> _ + [No results] + $ sherlodoc --pretty-query ": 'a * 'b) list" + : ('a * 'b) list + [No results] + $ sherlodoc --pretty-query ": - ,'a * 'b, 'c) result -) - ( -" + : ((_ -> _, 'a * 'b, 'c) result -> _) -> _ -> _ + [No results] +Testing syntax errors + $ sherlodoc --pretty-query ": )(" : [No results] diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 6c22d8dfa6..6297d0a37a 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 264K sherlodoc.js + 216K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html From 53c96b13f124a3c70d398a3eb5a1032d84baf978 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 2 Jan 2024 10:36:22 +0100 Subject: [PATCH 214/285] fix candidate sorting --- query/dynamic_cost.ml | 6 ++---- query/type_distance.ml | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index a2b7a62869..93549f9543 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -18,7 +18,7 @@ module Reasoning = struct | Doc let is_substring ~sub s = - let re = Re.(compile (seq [ rep any; str sub ])) in + let re = Re.(compile (str sub)) in Re.execp re s let with_word query_word name = @@ -165,7 +165,5 @@ let cost_of_reasoning let cost_of_entry ~query_name ~query_type entry = cost_of_reasoning (Reasoning.v query_name query_type entry) -(** [update_entry ~query_name ~query_type e] updates [e.cost] to take into - account the query described by [query_name] and [query_type]. *) let update_entry ~query_name ~query_type entry = - Entry.{ entry with cost = cost_of_entry ~query_name ~query_type entry } + Entry.{ entry with cost = entry.cost + cost_of_entry ~query_name ~query_type entry } diff --git a/query/type_distance.ml b/query/type_distance.ml index 06b7e9065c..266b7c6f19 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -197,7 +197,7 @@ let minimize = function let v ~query ~entry = let query_paths = Type_path.of_typ ~ignore_any:false query in - let entry_paths = Type_path.of_typ ~ignore_any:false entry in + let entry_paths = Type_path.of_typ ~ignore_any:true entry in match entry_paths, query_paths with | _, [] | [], _ -> 0 | _ -> From 12b029668012ff214e14b2dd8ac4e2a6aa678aa7 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 2 Jan 2024 10:36:36 +0100 Subject: [PATCH 215/285] simplify indexing --- index/load_doc.ml | 115 +++++++++++++--------------------------------- 1 file changed, 33 insertions(+), 82 deletions(-) diff --git a/index/load_doc.ml b/index/load_doc.ml index 5f8575824a..28e6c5838f 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -8,45 +8,30 @@ let generic_cost ~ignore_no_doc name has_doc = the suffix tree does not return results shorter than the query*) (String.length name * 6) (* + (5 * List.length path) TODO : restore depth based ordering *) - + (if ignore_no_doc || has_doc then 0 else 30) - + if String.starts_with ~prefix:"Stdlib." name then -100 else 0 + + (if ignore_no_doc || has_doc then 0 else 400) + + if String.starts_with ~prefix:"Stdlib." name then 0 else 100 -let kind_cost (kind : Entry.Kind.t) = - match kind, Entry.Kind.get_type kind with - | _, Some typ -> Db.Typexpr.size typ - | Doc, _ -> 400 +let kind_cost = function + | Entry.Kind.Doc -> 400 | _ -> 0 -let cost ~name ~kind ~doc_html = +let cost ~name ~kind ~doc_html ~rhs = let ignore_no_doc = match kind with | Entry.Kind.Module | Module_type -> true | _ -> false in let has_doc = doc_html <> "" in - generic_cost ~ignore_no_doc name has_doc + kind_cost kind - -(* - todo : check usefulness - let rec type_size = function - | Odoc_model.Lang.TypeExpr.Var _ -> 1 - | Any -> 1 - | Arrow (lbl, a, b) -> - (match lbl with - | None -> 0 - | Some _ -> 1) - + type_size a + type_size b - | Constr (_, args) -> List.fold_left (fun acc t -> acc + type_size t) 1 args - | Tuple args -> List.fold_left (fun acc t -> acc + type_size t) 1 args - | _ -> 100 -*) + generic_cost ~ignore_no_doc name has_doc + + kind_cost kind + + String.length (Option.value ~default:"" rhs) let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) let rec typ_of_odoc_typ otyp = let open Db.Typexpr in match otyp with - | Odoc_model.Lang.TypeExpr.Var str -> poly str + | Odoc_model.Lang.TypeExpr.Var _str -> any | Any -> any | Arrow (_lbl, left, right) -> arrow (typ_of_odoc_typ left) (typ_of_odoc_typ right) | Constr (name, args) -> @@ -80,8 +65,8 @@ let with_tokenizer str fn = let register_doc ~db elt doc_txt = with_tokenizer doc_txt @@ fun word -> Db.store_word db word elt -let register_full_name ~db name elt = - let name = String.lowercase_ascii name in +let register_full_name ~db (elt : Db.Entry.t) = + let name = String.lowercase_ascii elt.name in Db.store_word db name elt let searchable_type_of_constructor args res = @@ -135,35 +120,15 @@ let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = Entry.Kind.Extension_constructor typ | ModuleType -> Module_type -let register_type_expr ~db elt type_ = - let type_polarities = - type_ |> typ_of_odoc_typ |> Db.Type_polarity.of_typ ~any_is_poly:true ~all_names:true - in +let register_type_expr ~db elt typ = + let type_polarities = Db.Type_polarity.of_typ ~any_is_poly:true ~all_names:true typ in Db.store_type_polarities db elt type_polarities -let register_kind ~db ~type_search elt (kind : Odoc_search.Entry.kind) = - let open Odoc_search.Entry in - let open Odoc_model.Lang in - if type_search - then ( - match kind with - | TypeDecl _ -> () - | Module -> () - | Value { value = _; type_ } -> register_type_expr ~db elt type_ - | Doc _ -> () - | Class_type _ -> () - | Method _ -> () - | Class _ -> () - | TypeExtension _ -> () - | ModuleType -> () - | ExtensionConstructor { args; res } - | Constructor { args; res } - | Exception { args; res } -> - let type_ = searchable_type_of_constructor args res in - register_type_expr ~db elt type_ - | Field { mutable_ = _; parent_type; type_ } -> - let type_ = TypeExpr.Arrow (None, parent_type, type_) in - register_type_expr ~db elt type_) +let register_kind ~db elt = + let open Db.Entry in + match Kind.get_type elt.kind with + | None -> () + | Some typ -> register_type_expr ~db elt typ let rec is_from_module_type (id : Odoc_model.Paths.Identifier.Any.t) = let open Odoc_model.Paths in @@ -183,14 +148,11 @@ let is_from_module_type Odoc_search.Entry.{ id; _ } = is_from_module_type (parent :> Odoc_model.Paths.Identifier.Any.t) | _ -> is_from_module_type id -let prefixname n = - match - (n :> Odoc_model.Paths.Identifier.t) - |> Odoc_model.Paths.Identifier.fullname - |> List.rev - with +let prefixname id = + let parts = Odoc_model.Paths.Identifier.fullname id in + match List.rev parts with | [] -> "" - | _ :: q -> q |> List.rev |> String.concat "." + | _ :: prefix -> String.concat "." (List.rev prefix) let register_entry ~db @@ -210,41 +172,30 @@ let register_entry in if Odoc_model.Paths.Identifier.is_internal id || is_type_extension then () - else ( + else begin let full_name = id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." in let doc_txt = Text.of_doc doc in + let doc_html = doc |> Html.of_doc |> string_of_html in let doc_html = match doc_txt with | "" -> "" - | _ -> doc |> Html.of_doc |> string_of_html + | _ -> doc_html in - let kind' = convert_kind entry in + let rhs = Html.rhs_of_kind kind in + let kind = convert_kind entry in let name = match kind with - | Doc _ -> prefixname id + | Doc -> prefixname id | _ -> full_name in - let cost = cost ~name ~kind:kind' ~doc_html in - let rhs = Html.rhs_of_kind kind in + let cost = cost ~name ~kind ~doc_html ~rhs in let url = Html.url id in let url = Result.get_ok url in let is_from_module_type = is_from_module_type entry in let elt = - Sherlodoc_entry.v - ~name - ~kind:kind' - ~rhs - ~doc_html - ~cost - ~url - ~is_from_module_type - ~pkg - () + Sherlodoc_entry.v ~name ~kind ~rhs ~doc_html ~cost ~url ~is_from_module_type ~pkg () in if index_docstring then register_doc ~db elt doc_txt ; - if index_name - then ( - match kind with - | Doc _ -> () - | _ -> register_full_name ~db full_name elt) ; - register_kind ~db ~type_search elt kind) + if index_name && kind <> Doc then register_full_name ~db elt ; + if type_search then register_kind ~db elt + end From 11102a34f498ef24cfec5727b0fa42dc59f7577b Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 2 Jan 2024 14:03:38 +0100 Subject: [PATCH 216/285] single command --- cli/dune | 5 +- cli/main.ml | 37 +- dune-project | 49 +-- index/dune | 7 +- index/index.ml | 9 +- sherlodoc-www.opam | 34 -- sherlodoc.opam | 13 +- test/cram/base_benchmark.t | 2 +- test/cram/base_cli.t | 604 +++++++++++++++-------------- test/cram/base_web.t | 6 +- test/cram/cli.t/run.t | 76 ++-- test/cram/cli_poly.t/run.t | 6 +- test/cram/cli_small.t/run.t | 17 +- test/cram/dune | 1 - test/cram/module_type_cost.t/run.t | 18 +- test/cram/query_syntax.t | 38 +- test/cram/simple.t/run.t | 2 +- www/dune | 7 +- www/packages.ml | 9 +- www/ui.ml | 7 +- www/www.ml | 15 +- 21 files changed, 461 insertions(+), 501 deletions(-) delete mode 100644 sherlodoc-www.opam diff --git a/cli/dune b/cli/dune index be779407bd..4445803ceb 100644 --- a/cli/dune +++ b/cli/dune @@ -1,10 +1,7 @@ -; This binary is usef to perform searches on the command line. It needs a -; database and a query as input, and print results on the command line. - (ocamllex unescape) (executable (name main) (public_name sherlodoc) (package sherlodoc) - (libraries cmdliner query db_store)) + (libraries index www cmdliner query db_store)) diff --git a/cli/main.ml b/cli/main.ml index cb0b880d96..dcc0329de4 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -20,28 +20,23 @@ let string_of_kind = | Field _ -> "field" | Val _ -> "val" -let print_result - ~print_cost - ~no_rhs - Db.Entry. - { name; rhs; url = _; kind; cost; doc_html = _; pkg = _; is_from_module_type = _ } - = - let cost = if print_cost then string_of_int cost ^ " " else "" in +let print_result ~print_cost ~no_rhs (elt : Db.Entry.t) = + let cost = if print_cost then string_of_int elt.cost ^ " " else "" in let typedecl_params = - (match kind with - | Db.Entry.Kind.Type_decl args -> args + (match elt.kind with + | Type_decl args -> args | _ -> None) |> Option.map (fun str -> str ^ " ") |> Option.value ~default:"" in - let kind = kind |> string_of_kind |> Unescape.string in - let name = Unescape.string name in + let kind = elt.kind |> string_of_kind |> Unescape.string in + let name = Unescape.string elt.name in let pp_rhs h = function | None -> () | Some _ when no_rhs -> () | Some rhs -> Format.fprintf h "%s" (Unescape.string rhs) in - Format.printf "%s%s %s%s%a\n" cost kind typedecl_params name pp_rhs rhs + Format.printf "%s%s %s%s%a@." cost kind typedecl_params name pp_rhs elt.rhs let search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query = let query = Query.{ query; packages = []; limit } in @@ -132,9 +127,23 @@ let main = $ limit $ pretty_query) +let cmd_search = + let info = Cmd.info "search" ~doc:"Search" in + Cmd.v info main + +let cmd_index = + let doc = "Index odocl files to create a Sherlodoc database" in + let info = Cmd.info "index" ~doc in + Cmd.v info Index.term + +let cmd_serve = + let doc = "Webserver interface" in + let info = Cmd.info "serve" ~doc in + Cmd.v info Www.term + let cmd = - let doc = "CLI interface to query sherlodoc" in + let doc = "Sherlodoc" in let info = Cmd.info "sherlodoc" ~doc in - Cmd.v info main + Cmd.group info [ cmd_search; cmd_index; cmd_serve ] let () = exit (Cmd.eval cmd) diff --git a/dune-project b/dune-project index 37dffb80be..208b0ec135 100644 --- a/dune-project +++ b/dune-project @@ -21,40 +21,17 @@ (name sherlodoc) (synopsis "Fuzzy search in OCaml documentation") (depends - (ocaml - (>= 4.14.0)) - dune - (decompress - (>= 1.5.3)) - (bigstringaf - (>= 0.9.1)) - (base64 - (>= 3.5.1)) - (lwt - (>= 5.7.0)) - (fpath - (>= 0.7.3)) - (odoc - (>= 2.4.0)) - (opam-core - (>= 2.1.5)) - (tyxml - (>= 4.6.0)) - (brr - (>= 0.0.6)) + (ocaml (>= 4.14.0)) + (cmdliner (>= 1.2.0)) + (decompress (>= 1.5.3)) + (base64 (>= 3.5.1)) + (fpath (>= 0.7.3)) + (lwt (>= 5.7.0)) + (menhir (>= 20230608)) + (odoc (>= 2.4.0)) + (tyxml (>= 4.6.0)) + (brr (>= 0.0.6)) (alcotest :with-test)) - (depopts ancient)) - -(package - (name sherlodoc-www) - (synopsis "Website for fuzzy search in OCaml documentation") - (depends - (ocaml - (>= 4.14.0)) - dune - sherlodoc - (ancient - (>= 0.9.1)) - (dream - (>= 1.0.0~alpha5)) - (alcotest :with-test))) + (depopts + (dream (>= 1.0.0~alpha5)) + (ancient (>= 0.9.1)))) diff --git a/index/dune b/index/dune index 1088dc6ea1..da8f2264db 100644 --- a/index/dune +++ b/index/dune @@ -1,10 +1,5 @@ -; `sherlodoc_index` is an executable that build a database for sherlodoc taking -; odocl files as input. - -(executable - (public_name sherlodoc_index) +(library (name index) - (package sherlodoc) (libraries db db_store diff --git a/index/index.ml b/index/index.ml index f4af9103f0..2238f7eb45 100644 --- a/index/index.ml +++ b/index/index.ml @@ -77,7 +77,7 @@ let odoc_files = let doc = "Path to a .odocl file" in Arg.(non_empty & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) -let index = +let term = Term.( const main $ odoc_files @@ -87,10 +87,3 @@ let index = $ type_search $ db_filename $ db_format) - -let cmd = - let doc = "Index odocl files" in - let info = Cmd.info "index" ~doc in - Cmd.v info index - -let () = exit (Cmd.eval cmd) diff --git a/sherlodoc-www.opam b/sherlodoc-www.opam deleted file mode 100644 index 9894aab933..0000000000 --- a/sherlodoc-www.opam +++ /dev/null @@ -1,34 +0,0 @@ -# This file is generated by dune, edit dune-project instead -opam-version: "2.0" -synopsis: "Website for fuzzy search in OCaml documentation" -maintainer: ["art.wendling@gmail.com"] -authors: ["Arthur Wendling"] -license: "MIT" -homepage: "https://github.com/art-w/sherlodoc" -bug-reports: "https://github.com/art-w/sherlodoc/issues" -depends: [ - "ocaml" {>= "4.14.0"} - "dune" {>= "2.9"} - "sherlodoc" - "ancient" {>= "0.9.1"} - "dream" {>= "1.0.0~alpha5"} - "alcotest" {with-test} - "odoc" {with-doc} -] -build: [ - ["dune" "subst"] {dev} - [ - "dune" - "build" - "-p" - name - "-j" - jobs - "--promote-install-files=false" - "@install" - "@runtest" {with-test} - "@doc" {with-doc} - ] - ["dune" "install" "-p" name "--create-install-files" name] -] -dev-repo: "git+https://github.com/art-w/sherlodoc.git" diff --git a/sherlodoc.opam b/sherlodoc.opam index b09cfb2205..d0a1b6897d 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -7,20 +7,23 @@ license: "MIT" homepage: "https://github.com/art-w/sherlodoc" bug-reports: "https://github.com/art-w/sherlodoc/issues" depends: [ - "ocaml" {>= "4.14.0"} "dune" {>= "2.9"} + "ocaml" {>= "4.14.0"} + "cmdliner" {>= "1.2.0"} "decompress" {>= "1.5.3"} - "bigstringaf" {>= "0.9.1"} "base64" {>= "3.5.1"} - "lwt" {>= "5.7.0"} "fpath" {>= "0.7.3"} + "lwt" {>= "5.7.0"} + "menhir" {>= "20230608"} "odoc" {>= "2.4.0"} - "opam-core" {>= "2.1.5"} "tyxml" {>= "4.6.0"} "brr" {>= "0.0.6"} "alcotest" {with-test} ] -depopts: ["ancient"] +depopts: [ + "dream" {>= "1.0.0~alpha5"} + "ancient" {>= "0.9.1"} +] build: [ ["dune" "subst"] {dev} [ diff --git a/test/cram/base_benchmark.t b/test/cram/base_benchmark.t index e31bf53db2..a3bfbe9472 100644 --- a/test/cram/base_benchmark.t +++ b/test/cram/base_benchmark.t @@ -7,7 +7,7 @@ are not crazy and discard the changes ./base_odocls/md5_lib.odocl ./base_odocls/page-index.odocl ./base_odocls/shadow_stdlib.odocl - $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + $ sherlodoc index --format=js --db=db.js $(find . -name '*.odocl') diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 3ee6f74091..f32cedb3da 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -7,129 +7,158 @@ ./base_odocls/shadow_stdlib.odocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=ancient - $ sherlodoc_index --index-docstring=false $(find . -name '*.odocl') 2> /dev/null - $ sherlodoc --print-cost --no-rhs --limit 100 "S_poly" - 115 sig Base.Map.S_poly - 115 sig Base.Set.S_poly - 119 sig Base.Hashtbl.S_poly - 623 val Base.Set.S_poly.map - 623 val Base.Set.S_poly.mem - 625 mod Base.Set.S_poly.Named - 627 val Base.Hashtbl.S_poly.add - 627 val Base.Hashtbl.S_poly.map - 627 val Base.Hashtbl.S_poly.set - 628 val Base.Hashtbl.S_poly.data - 628 val Base.Hashtbl.S_poly.find - 628 val Base.Hashtbl.S_poly.fold - 628 val Base.Hashtbl.S_poly.keys - 628 val Base.Hashtbl.S_poly.mapi - 630 val Base.Hashtbl.S_poly.choose - 632 val Base.Hashtbl.S_poly.find_exn - 632 val Base.Hashtbl.S_poly.to_alist - 634 val Base.Hashtbl.S_poly.choose_exn - 721 type ('a, 'b) Base.Map.S_poly.t - 721 type 'elt Base.Set.S_poly.t - 723 val Base.Map.S_poly.add - 723 val Base.Map.S_poly.map - 723 val Base.Map.S_poly.mem - 723 val Base.Map.S_poly.nth - 723 val Base.Map.S_poly.set - 723 val Base.Set.S_poly.add - 723 val Base.Set.S_poly.nth - 723 type ('a, 'cmp) Base.Set.S_poly.set - 723 val Base.Set.S_poly.sum - 724 val Base.Map.S_poly.data - 724 val Base.Map.S_poly.find - 724 val Base.Map.S_poly.fold - 724 val Base.Map.S_poly.iter - 724 val Base.Map.S_poly.keys - 724 val Base.Map.S_poly.mapi - 724 val Base.Map.S_poly.rank - 724 type ('a, 'b) Base.Map.S_poly.tree - 724 val Base.Set.S_poly.diff - 724 val Base.Set.S_poly.find - 724 val Base.Set.S_poly.fold - 724 val Base.Set.S_poly.iter - 724 type 'elt Base.Set.S_poly.tree - 725 type ('a, 'b) Base.Hashtbl.S_poly.t - 725 val Base.Map.S_poly.count - 725 val Base.Map.S_poly.empty - 725 val Base.Map.S_poly.iteri - 725 val Base.Set.S_poly.count - 725 val Base.Set.S_poly.empty - 725 val Base.Set.S_poly.equal - 725 val Base.Set.S_poly.inter - 725 val Base.Set.S_poly.iter2 - 725 val Base.Set.S_poly.split - 725 val Base.Set.S_poly.union - 726 val Base.Map.S_poly.append - 726 val Base.Map.S_poly.exists - 726 val Base.Map.S_poly.length - 726 val Base.Map.S_poly.remove - 726 val Base.Set.S_poly.choose - 726 val Base.Set.S_poly.exists - 726 val Base.Set.S_poly.filter - 726 val Base.Set.S_poly.length - 726 val Base.Set.S_poly.remove - 727 type 'a Base.Hashtbl.S_poly.key - 727 val Base.Hashtbl.S_poly.mem - 727 val Base.Map.S_poly.add_exn - 727 val Base.Map.S_poly.max_elt - 727 val Base.Map.S_poly.min_elt - 727 val Base.Map.S_poly.nth_exn - 727 val Base.Map.S_poly.of_tree - 727 val Base.Map.S_poly.to_tree - 727 val Base.Set.S_poly.for_all - 727 val Base.Set.S_poly.max_elt - 727 val Base.Set.S_poly.min_elt - 727 val Base.Set.S_poly.of_list - 727 val Base.Set.S_poly.of_tree - 727 val Base.Set.S_poly.to_list - 727 val Base.Set.S_poly.to_tree - 728 val Base.Hashtbl.S_poly.copy - 728 val Base.Map.S_poly.find_exn - 728 val Base.Map.S_poly.is_empty - 728 val Base.Map.S_poly.map_keys - 728 val Base.Map.S_poly.of_alist - 728 val Base.Set.S_poly.elements - 728 val Base.Set.S_poly.find_exn - 728 val Base.Set.S_poly.is_empty - 728 val Base.Set.S_poly.of_array - 728 val Base.Set.S_poly.to_array - 729 val Base.Hashtbl.S_poly.clear - 729 val Base.Map.S_poly.singleton - 729 val Base.Set.S_poly.is_subset - 729 val Base.Set.S_poly.singleton - 730 val Base.Hashtbl.S_poly.length - 730 val Base.Map.S_poly.invariants - 730 val Base.Set.S_poly.choose_exn - 730 val Base.Set.S_poly.invariants - 731 val Base.Map.S_poly.max_elt_exn - 731 val Base.Map.S_poly.min_elt_exn - 731 val Base.Set.S_poly.max_elt_exn - 731 val Base.Set.S_poly.min_elt_exn - 732 val Base.Hashtbl.S_poly.hashable - $ sherlodoc --print-cost --no-rhs "group b" - 218 val Base.List.group - 221 val Base.Hashtbl.group - 222 val Base.Sequence.group - 224 val Base.List.Assoc.group - 323 val Base.List.groupi - 324 val Base.Set.group_by - 326 val Base.Hashtbl.Poly.group - 330 val Base.List.sort_and_group - 330 val Base.Hashtbl.Creators.group - 336 val Base.List.Assoc.sort_and_group - 429 val Base.Set.Poly.group_by - 441 val Base.Set.Using_comparator.group_by - 446 val Base.Set.Using_comparator.Tree.group_by - 630 val Base.Hashtbl.Creators.group - 642 val Base.Hashtbl.S_without_submodules.group - 728 val Base.Hashtbl.S_poly.group - 831 val Base.Set.S_poly.group_by - 842 val Base.Set.Accessors_generic.group_by - 855 val Base.Set.Creators_and_accessors_generic.group_by - $ sherlodoc --no-rhs "group by" + $ sherlodoc index --index-docstring=false $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc search --print-cost --limit 100 "S_poly" + 305 sig Base.Map.S_poly + 305 sig Base.Set.S_poly + 333 sig Base.Hashtbl.S_poly + 851 mod Base.Set.S_poly.Named + 858 val Base.Set.S_poly.mem : 'a t -> 'a -> bool + 875 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t + 895 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list + 899 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + 908 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t + 908 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option + 911 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit + 923 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option + 927 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] + 929 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b + 934 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t + 935 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list + 936 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool + 937 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit + 939 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit + 940 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit + 942 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b + 947 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit + 951 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc + 953 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 957 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit + 958 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit + 963 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit + 964 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t + 974 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b + 983 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b + 985 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option + 986 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t + 990 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t + 1005 mod Base.Map.S_poly.Make_applicative_traversals + 1006 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t + 1012 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t + 1013 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit + 1015 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b + 1018 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option + 1019 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit + 1026 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> + dst:('k, 'b) t -> + f:(key:'k key -> 'a -> 'b option -> 'b Merge_into_action.t) -> + unit + 1026 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> + 'a key -> + if_found:('b -> 'c) -> + if_not_found:('a key -> 'c) -> + 'c + 1027 val Base.Hashtbl.S_poly.merge : ('k, 'a) t -> + ('k, 'b) t -> + f: + (key:'k key -> + [ `Left of 'a | `Right of 'b | `Both of 'a * 'b ] -> + 'c option) -> + ('k, 'c) t + 1036 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> + f:(key:'a key -> data:'b -> ('c, 'd) Either.t) -> + ('a, 'c) t * ('a, 'd) t + 1037 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b + 1055 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> + 'a key -> + a:'d -> + if_found:('b -> 'd -> 'c) -> + if_not_found:('a key -> 'd -> 'c) -> + 'c + 1088 val Base.Hashtbl.S_poly.create_with_key : ?growth_allowed:bool -> + ?size:int -> + get_key:('r -> 'a key) -> + 'r list -> + [ `Ok of ('a, 'r) t | `Duplicate_keys of 'a key list ] + 1092 val Base.Map.S_poly.Make_applicative_traversals.A.(<*>) : ('a -> 'b) t -> 'a t -> 'b t + 1099 val Base.Hashtbl.S_poly.create_mapped : ?growth_allowed:bool -> + ?size:int -> + get_key:('r -> 'a key) -> + get_data:('r -> 'b) -> + 'r list -> + [ `Ok of ('a, 'b) t | `Duplicate_keys of 'a key list ] + 1145 mod Base.Map.S_poly.Make_applicative_traversals.A.Applicative_infix + 1218 val Base.Map.S_poly.Make_applicative_traversals.A.Applicative_infix.(<*>) : ('a -> 'b) t -> 'a t -> 'b t + 1323 type ('a, 'b) Base.Map.S_poly.t + 1323 type 'elt Base.Set.S_poly.t + 1337 type ('a, 'cmp) Base.Set.S_poly.set + 1344 type ('a, 'b) Base.Map.S_poly.tree + 1344 type 'elt Base.Set.S_poly.tree + 1351 type ('a, 'b) Base.Hashtbl.S_poly.t + 1358 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t + 1358 val Base.Set.S_poly.empty : 'a t + 1363 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool + 1363 val Base.Map.S_poly.empty : ('k, _) t + 1364 val Base.Set.S_poly.nth : 'a t -> int -> 'a option + 1367 val Base.Map.S_poly.data : (_, 'v) t -> 'v list + 1367 val Base.Map.S_poly.keys : ('k, _) t -> 'k list + 1367 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t + 1370 type 'a Base.Hashtbl.S_poly.key = 'a + 1371 val Base.Set.S_poly.length : _ t -> int + 1374 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool + 1374 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t + 1374 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t + 1376 val Base.Map.S_poly.find : ('k, 'v) t -> 'k -> 'v option + 1376 val Base.Map.S_poly.rank : ('k, _) t -> 'k -> int option + 1376 val Base.Map.S_poly.length : (_, _) t -> int + 1377 val Base.Map.S_poly.nth : ('k, 'v) t -> int -> ('k * 'v) option + 1377 val Base.Set.S_poly.iter : 'a t -> f:('a -> unit) -> unit + 1378 val Base.Set.S_poly.choose : 'a t -> 'a option + 1379 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t + 1382 val Base.Map.S_poly.iter : (_, 'v) t -> f:('v -> unit) -> unit + 1382 val Base.Set.S_poly.find : 'a t -> f:('a -> bool) -> 'a option + 1383 val Base.Set.S_poly.count : 'a t -> f:('a -> bool) -> int + 1383 val Base.Set.S_poly.of_list : 'a list -> 'a t + 1383 val Base.Set.S_poly.of_tree : 'a tree -> 'a t + 1383 val Base.Set.S_poly.to_list : 'a t -> 'a list + 1383 val Base.Set.S_poly.to_tree : 'a t -> 'a tree + 1384 val Base.Map.S_poly.map : ('k, 'v1) t -> f:('v1 -> 'v2) -> ('k, 'v2) t + 1385 val Base.Map.S_poly.set : ('k, 'v) t -> key:'k -> data:'v -> ('k, 'v) t + 1385 val Base.Set.S_poly.max_elt : 'a t -> 'a option + 1385 val Base.Set.S_poly.min_elt : 'a t -> 'a option + 1386 val Base.Set.S_poly.is_empty : _ t -> bool + 1389 val Base.Map.S_poly.count : ('k, 'v) t -> f:('v -> bool) -> int + 1390 val Base.Set.S_poly.elements : 'a t -> 'a list + 1391 val Base.Set.S_poly.split : 'a t -> 'a -> 'a t * 'a option * 'a t + 1391 val Base.Map.S_poly.remove : ('k, 'v) t -> 'k -> ('k, 'v) t + 1391 val Base.Set.S_poly.exists : 'a t -> f:('a -> bool) -> bool + 1391 val Base.Set.S_poly.filter : 'a t -> f:('a -> bool) -> 'a t + 1391 val Base.Map.S_poly.is_empty : (_, _) t -> bool + 1391 val Base.Set.S_poly.of_array : 'a array -> 'a t + 1391 val Base.Set.S_poly.to_array : 'a t -> 'a array + 1392 val Base.Set.S_poly.singleton : 'a -> 'a t + 1395 val Base.Hashtbl.S_poly.mem : ('a, _) t -> 'a key -> bool + $ sherlodoc search --print-cost --no-rhs "group b" + 453 val Base.List.group + 484 val Base.Sequence.group + 514 val Base.List.Assoc.group + 571 val Base.List.groupi + 589 val Base.Hashtbl.group + 590 val Base.Set.group_by + 620 val Base.List.sort_and_group + 681 val Base.List.Assoc.sort_and_group + 1052 val Base.Hashtbl.Creators.group + 1109 val Base.Set.Poly.group_by + 1114 val Base.Hashtbl.Poly.group + 1136 val Base.Hashtbl.S_without_submodules.group + 1145 val Base.Hashtbl.Creators.group + 1209 val Base.Set.Using_comparator.group_by + 1244 val Base.Set.Using_comparator.Tree.group_by + 1523 val Base.Set.S_poly.group_by + 1528 val Base.Hashtbl.S_poly.group + 1624 val Base.Set.Accessors_generic.group_by + 1715 val Base.Set.Creators_and_accessors_generic.group_by + $ sherlodoc search --no-rhs "group by" val Base.Set.group_by val Base.Set.Poly.group_by val Base.Set.Using_comparator.group_by @@ -137,170 +166,169 @@ val Base.Set.S_poly.group_by val Base.Set.Accessors_generic.group_by val Base.Set.Creators_and_accessors_generic.group_by - $ sherlodoc --print-cost "map2" - 214 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 216 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 218 val Base.Or_error.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 222 val Base.Either.First.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t - 226 val Base.Applicative.Make.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t - 227 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 227 val Base.Applicative.Make2.map2 : ('a, 'e) X.t -> ('b, 'e) X.t -> f:('a -> 'b -> 'c) -> ('c, 'e) X.t - 227 val Base.Applicative.Make3.map2 : ('a, 'd, 'e) X.t -> ('b, 'd, 'e) X.t -> f:('a -> 'b -> 'c) -> ('c, 'd, 'e) X.t - 228 val Base.Applicative.Pair.F.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 228 val Base.Applicative.Pair.G.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 230 val Base.Applicative.Of_monad.map2 : 'a M.t -> 'b M.t -> f:('a -> 'b -> 'c) -> 'c M.t - 231 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 231 val Base.Applicative.Compose.F.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 231 val Base.Applicative.Compose.G.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 231 val Base.Applicative.S_to_S2.X.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 235 mod Base.Applicative.Make_using_map2 - 236 sig Base.Applicative.Basic_using_map2 - 236 mod Base.Applicative.Make2_using_map2 - 236 mod Base.Applicative.Make3_using_map2 - 237 sig Base.Applicative.Basic2_using_map2 - 237 sig Base.Applicative.Basic3_using_map2 - 242 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 243 mod Base.Applicative.Make_using_map2_local - 244 sig Base.Applicative.Basic_using_map2_local - 244 mod Base.Applicative.Make2_using_map2_local - 244 mod Base.Applicative.Make3_using_map2_local - 245 sig Base.Applicative.Basic2_using_map2_local - 245 sig Base.Applicative.Basic3_using_map2_local - 321 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 322 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 323 val Base.Array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 340 type 'a Base.Applicative.Make_using_map2.X.t - 340 val Base.Applicative.Make_using_map2.map : 'a X.t -> f:('a -> 'b) -> 'b X.t - 341 type ('a, 'e) Base.Applicative.Make2_using_map2.X.t - 341 type ('a, 'd, 'e) Base.Applicative.Make3_using_map2.X.t - 342 val Base.Applicative.Make_using_map2.X.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] - 343 val Base.Applicative.Make2_using_map2.X.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] - 343 val Base.Applicative.Make3_using_map2.X.map : [ `Define_using_map2 - | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - 343 val Base.Applicative.Make_using_map2.return : 'a -> 'a X.t - 623 val Base.Applicative.S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 624 val Base.Applicative.S2.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t - 624 val Base.Applicative.S3.map2 : ('a, 'd, 'e) t -> ('b, 'd, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'd, 'e) t - 624 val Base.Either.Focused.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t - 629 val Base.Applicative.S_local.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 739 type 'a Base.Applicative.Basic_using_map2.t - 740 type ('a, 'e) Base.Applicative.Basic2_using_map2.t - 740 type ('a, 'd, 'e) Base.Applicative.Basic3_using_map2.t - 741 val Base.Applicative.Basic_using_map2.map : [ `Define_using_map2 | `Custom of 'a t -> f:('a -> 'b) -> 'b t ] - 742 val Base.Applicative.Basic2_using_map2.map : [ `Define_using_map2 | `Custom of ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t ] - 742 val Base.Applicative.Basic3_using_map2.map : [ `Define_using_map2 - | `Custom of ('a, 'd, 'e) t -> f:('a -> 'b) -> ('b, 'd, 'e) t ] - $ sherlodoc --print-cost --no-rhs --static-sort "List map2" - 202 val Base.List.rev_map2_exn - 208 val Base.List.map2_exn - 215 val Base.List.map2 - 239 val Base.List.rev_map2 - 292 val Base.List.Cartesian_product.map2 + $ sherlodoc search --print-cost "map2" + 504 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 527 mod Base.Applicative.Make_using_map2 + 534 sig Base.Applicative.Basic_using_map2 + 534 mod Base.Applicative.Make2_using_map2 + 534 mod Base.Applicative.Make3_using_map2 + 538 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 541 sig Base.Applicative.Basic2_using_map2 + 541 sig Base.Applicative.Basic3_using_map2 + 571 mod Base.Applicative.Make_using_map2_local + 578 sig Base.Applicative.Basic_using_map2_local + 578 mod Base.Applicative.Make2_using_map2_local + 578 mod Base.Applicative.Make3_using_map2_local + 585 sig Base.Applicative.Basic2_using_map2_local + 585 sig Base.Applicative.Basic3_using_map2_local + 607 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 650 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 654 mod Base.Applicative.Make_using_map2.Applicative_infix + 661 mod Base.Applicative.Make2_using_map2.Applicative_infix + 661 mod Base.Applicative.Make3_using_map2.Applicative_infix + 697 mod Base.Applicative.Make_using_map2_local.Applicative_infix + 704 mod Base.Applicative.Make2_using_map2_local.Applicative_infix + 704 mod Base.Applicative.Make3_using_map2_local.Applicative_infix + 733 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 776 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 857 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 864 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 871 val Base.Or_error.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 917 val Base.Either.First.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t + 924 val Base.Either.Second.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t + 927 val Base.Applicative.Pair.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 933 val Base.Applicative.Make.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t + 941 val Base.Applicative.Pair.F.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 941 val Base.Applicative.Pair.G.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 948 val Base.Applicative.Compose.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 948 val Base.Applicative.S2_to_S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 948 val Base.Applicative.S3_to_S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 975 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 982 val Base.Array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 995 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 1056 type 'a Base.Applicative.Make_using_map2.X.t + 1063 type ('a, 'e) Base.Applicative.Make2_using_map2.X.t + 1063 type ('a, 'd, 'e) Base.Applicative.Make3_using_map2.X.t + 1306 val Base.Applicative.S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 1331 val Base.Applicative.S2.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t + 1331 val Base.Either.Focused.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t + 1343 val Base.Applicative.S3.map2 : ('a, 'd, 'e) t -> ('b, 'd, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'd, 'e) t + 1348 val Base.Applicative.S_local.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 1449 type 'a Base.Applicative.Basic_using_map2.t + 1456 type ('a, 'e) Base.Applicative.Basic2_using_map2.t + 1456 type ('a, 'd, 'e) Base.Applicative.Basic3_using_map2.t + $ sherlodoc search --print-cost --no-rhs --static-sort "List map2" + 277 val Base.List.rev_map2_exn + 650 val Base.List.map2 + 653 val Base.List.map2_exn + 674 val Base.List.rev_map2 + 737 val Base.List.Cartesian_product.map2 - $ sherlodoc --no-rhs "Base.Hashtbl.S_without_submodules.group" + $ sherlodoc search --no-rhs "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group - $ sherlodoc --print-cost "list" - 109 mod Base.List - 109 mod Caml.List - 118 mod Shadow_stdlib.List - 209 type 'a Base.list = 'a List.t - 216 type 'a Base.Export.list = 'a List.t - 217 val Base.List.map : 'a t -> f:('a -> 'b) -> 'b t - 217 val Base.List.mem : 'a t -> 'a -> equal:('a -> 'a -> bool) -> bool - 217 val Base.List.rev : 'a t -> 'a t - 217 val Base.List.sub : 'a t -> pos:int -> len:int -> 'a t - 217 val Base.List.sum : (module Container.Summable with type t = 'sum) -> - 'a t -> - f:('a -> 'sum) -> - 'sum - 218 val Base.List.bind : 'a t -> f:('a -> 'b t) -> 'b t - 218 val Base.List.drop : 'a t -> int -> 'a t - 218 val Base.List.find : 'a t -> f:('a -> bool) -> 'a option - 218 val Base.List.fold : 'a t -> init:'acc -> f:('acc -> 'a -> 'acc) -> 'acc - 218 val Base.List.init : int -> f:(int -> 'a) -> 'a t - 218 val Base.List.join : 'a t t -> 'a t - 218 val Base.List.last : 'a t -> 'a option - 218 val Base.List.mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t - 218 val Base.List.sort : 'a t -> compare:('a -> 'a -> int) -> 'a t - 218 val Base.List.take : 'a t -> int -> 'a t - 219 val Base.List.(>>|) : 'a t -> ('a -> 'b) -> 'b t - 219 mod Base.List.Assoc - 219 mod Base.List.Infix - 219 val Base.List.count : 'a t -> f:('a -> bool) -> int - 219 mod Base.ListLabels - 219 mod Caml.ListLabels - 219 val Base.Set.to_list : ('a, _) t -> 'a list - 220 val Base.List.append : 'a t -> 'a t -> 'a t - 220 val Base.List.concat : 'a t t -> 'a t - 220 val Base.List.hd_exn : 'a t -> 'a - 220 val Base.List.return : 'a -> 'a t - 220 val Base.List.tl_exn : 'a t -> 'a t - 221 val Base.List.nth_exn : 'a t -> int -> 'a - 221 val Base.Bytes.to_list : t -> char list - 221 val Base.Queue.of_list : 'a list -> 'a t - 221 val Base.Stack.of_list : 'a list -> 'a t - 224 mod Base.List.Let_syntax - 225 mod Base.List.Monad_infix - 228 mod Shadow_stdlib.ListLabels - 315 type 'a Base.List.t = 'a list - 316 val Base.List.hd : 'a t -> 'a option - 318 val Base.equal_list : 'a. ('a -> 'a -> bool) -> 'a list -> 'a list -> bool - 320 val Base.compare_list : 'a. ('a -> 'a -> int) -> 'a list -> 'a list -> int - 320 val Base.sexp_of_list : 'a. ('a -> Sexplib0.Sexp.t) -> 'a list -> Sexplib0.Sexp.t - 321 type ('a, 'b) Base.List.Assoc.t = ('a * 'b) list - 321 val Base.list_of_sexp : 'a. (Sexplib0.Sexp.t -> 'a) -> Sexplib0.Sexp.t -> 'a list - 322 val Base.globalize_list : 'a. ('a -> 'a) -> 'a list -> 'a list - 322 val Base.hash_fold_list : 'a. (Hash.state -> 'a -> Hash.state) -> Hash.state -> 'a list -> Hash.state - 623 val Base.Queue.S.of_list : 'a list -> 'a t - 623 val Base.Stack.S.of_list : 'a list -> 'a t - $ sherlodoc --print-cost ": list" - 116 val Base.Map.data : (_, 'v, _) t -> 'v list - 116 val Base.Map.keys : ('k, _, _) t -> 'k list - 118 val Base.Set.to_list : ('a, _) t -> 'a list - 119 val Base.Hashtbl.data : (_, 'b) t -> 'b list - 119 val Base.Hashtbl.keys : ('a, _) t -> 'a key list - 119 val Base.Set.elements : ('a, _) t -> 'a list - 119 val Base.String.split : t -> on:char -> t list - 119 val Base.Bytes.to_list : t -> char list - 121 val Base.Map.to_alist : ?key_order:[ `Increasing | `Decreasing ] -> ('k, 'v, _) t -> ('k * 'v) list - 123 val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - 123 val Base.Map.find_multi : ('k, 'v list, 'cmp) t -> 'k -> 'v list - 124 val Base.Hashtbl.to_alist : ('a, 'b) t -> ('a key * 'b) list - 124 val Base.Hashtbl.Poly.data : (_, 'b) t -> 'b list - 124 val Base.Pretty_printer.all : unit -> string list - 124 val Base.String.split_lines : t -> t list - 124 val Base.String.to_list_rev : t -> char list - 126 val Base.Sequence.to_list_rev : 'a t -> 'a list - 210 val Caml.(@) : 'a list -> 'a list -> 'a list - 213 val Base.Bool.all : t list - 213 val Base.Char.all : t list - 213 val Base.Sign.all : t list - 213 val Base.Unit.all : t list - 216 val Base.Nothing.all : t list - 217 val Base.Ordering.all : t list - 218 val Base.List.to_list : 'a t -> 'a list - 219 val Shadow_stdlib.(@) : 'a list -> 'a list -> 'a list - 219 val Base.Array.to_list : 'a t -> 'a list - 219 val Base.Queue.to_list : 'a t -> 'a list - 219 val Base.Stack.to_list : 'a t -> 'a list - 220 val Base.Map.Poly.data : (_, 'v) t -> 'v list - 220 val Base.Map.Poly.keys : ('k, _) t -> 'k list - 220 val Base.Option.to_list : 'a t -> 'a list - 220 val Base.String.to_list : t -> elt list - 220 val Base.Float.Class.all : t list - 220 val Base.Sign_or_nan.all : t list - 221 val Base.Lazy.all : 'a t list -> 'a list t - 221 val Base.List.all : 'a t list -> 'a list t - 222 val Base.Sequence.to_list : 'a t -> 'a list - 222 val Base.Set.Poly.to_list : 'a t -> 'a list - 223 val Base.Option.all : 'a t list -> 'a list t - 225 val Base.Result.all : ('a, 'e) t list -> ('a list, 'e) t - 227 val Base.Monad.Make.all : 'a X.t list -> 'a list X.t - 526 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list - 526 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list - 621 val Base.Queue.S.to_list : 'a t -> 'a list - 621 val Base.Stack.S.to_list : 'a t -> 'a list - 622 val Base.Map.S_poly.data : (_, 'v) t -> 'v list - 622 val Base.Map.S_poly.keys : ('k, _) t -> 'k list - 624 val Base.Monad.S.all : 'a t list -> 'a list t - 627 val Base.Monad.S2.all : ('a, 'e) t list -> ('a list, 'e) t + $ sherlodoc search --print-cost "list" + 263 mod Base.List + 263 mod Caml.List + 326 mod Shadow_stdlib.List + 409 mod Base.List.Assoc + 409 mod Base.List.Infix + 409 mod Base.ListLabels + 409 mod Caml.ListLabels + 410 val Base.List.rev : 'a t -> 'a t + 419 val Base.List.join : 'a t t -> 'a t + 422 val Base.List.last : 'a t -> 'a option + 424 val Base.List.drop : 'a t -> int -> 'a t + 424 val Base.List.take : 'a t -> int -> 'a t + 426 val Base.List.map : 'a t -> f:('a -> 'b) -> 'b t + 429 val Base.List.hd_exn : 'a t -> 'a + 429 val Base.List.return : 'a -> 'a t + 431 val Base.List.tl_exn : 'a t -> 'a t + 432 val Base.List.sub : 'a t -> pos:int -> len:int -> 'a t + 433 val Base.List.init : int -> f:(int -> 'a) -> 'a t + 433 val Base.List.concat : 'a t t -> 'a t + 435 val Base.List.bind : 'a t -> f:('a -> 'b t) -> 'b t + 438 val Base.List.(>>|) : 'a t -> ('a -> 'b) -> 'b t + 438 val Base.Set.to_list : ('a, _) t -> 'a list + 439 val Base.List.append : 'a t -> 'a t -> 'a t + 440 val Base.List.find : 'a t -> f:('a -> bool) -> 'a option + 440 val Base.List.mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t + 440 val Base.List.(>>=) : 'a t -> ('a -> 'b t) -> 'b t + 441 val Base.List.count : 'a t -> f:('a -> bool) -> int + 443 val Base.List.nth_exn : 'a t -> int -> 'a + 444 val Base.List.mem : 'a t -> 'a -> equal:('a -> 'a -> bool) -> bool + 444 mod Base.List.Let_syntax + 446 val Base.List.sort : 'a t -> compare:('a -> 'a -> int) -> 'a t + 446 val Base.Bytes.to_list : t -> char list + 447 val Base.List.ignore_m : 'a t -> unit t + 447 val Base.Queue.of_list : 'a list -> 'a t + 447 val Base.Stack.of_list : 'a list -> 'a t + 449 val Base.List.exists : 'a t -> f:('a -> bool) -> bool + 449 val Base.List.filter : 'a t -> f:('a -> bool) -> 'a t + 451 mod Base.List.Monad_infix + 452 val Base.List.split_n : 'a t -> int -> 'a t * 'a t + 454 val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t + 454 val Base.List.rev_map : 'a t -> f:('a -> 'b) -> 'b t + 454 val Base.List.all_unit : unit t list -> unit t + 456 val Base.List.fold : 'a t -> init:'acc -> f:('acc -> 'a -> 'acc) -> 'acc + 456 val Base.Info.of_list : ?trunc_after:int -> t list -> t + 456 val Base.List.for_all : 'a t -> f:('a -> bool) -> bool + 459 val Base.List.drop_last : 'a t -> 'a t option + 461 val Base.List.find_exn : 'a t -> f:('a -> bool) -> 'a + 463 val Base.List.transpose : 'a t t -> 'a t t option + 861 val Base.Queue.S.of_list : 'a list -> 'a t + 861 val Base.Stack.S.of_list : 'a list -> 'a t + $ sherlodoc search --print-cost ": list" + 320 val Base.Map.data : (_, 'v, _) t -> 'v list + 320 val Base.Map.keys : ('k, _, _) t -> 'k list + 337 val Base.Set.to_list : ('a, _) t -> 'a list + 344 val Base.Hashtbl.data : (_, 'b) t -> 'b list + 344 val Base.Set.elements : ('a, _) t -> 'a list + 344 val Base.Bytes.to_list : t -> char list + 346 val Base.String.split : t -> on:char -> t list + 348 val Base.Hashtbl.keys : ('a, _) t -> 'a key list + 376 val Base.String.split_lines : t -> t list + 378 val Base.Map.find_multi : ('k, 'v list, 'cmp) t -> 'k -> 'v list + 379 val Base.Hashtbl.Poly.data : (_, 'b) t -> 'b list + 379 val Base.String.to_list_rev : t -> char list + 383 val Base.Hashtbl.Poly.keys : ('a, _) t -> 'a key list + 384 val Base.Pretty_printer.all : unit -> string list + 385 val Base.Hashtbl.to_alist : ('a, 'b) t -> ('a key * 'b) list + 389 val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list + 389 val Base.Sequence.split_n : 'a t -> int -> 'a list * 'a t + 392 val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t + 394 val Base.Sequence.to_list_rev : 'a t -> 'a list + 401 val Base.Map.to_alist : ?key_order:[ `Increasing | `Decreasing ] -> ('k, 'v, _) t -> ('k * 'v) list + 403 val Base.Hashtbl.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 404 val Base.Sequence.chunks_exn : 'a t -> int -> 'a list t + 410 val Base.Map.add_multi : ('k, 'v list, 'cmp) t -> key:'k -> data:'v -> ('k, 'v list, 'cmp) t + 412 val Base.List.find_all_dups : 'a t -> compare:('a -> 'a -> int) -> 'a list + 414 val Base.String.split_on_chars : t -> on:char list -> t list + 415 val Base.Map.remove_multi : ('k, 'v list, 'cmp) t -> 'k -> ('k, 'v list, 'cmp) t + 420 val Base.Hashtbl.Poly.to_alist : ('a, 'b) t -> ('a key * 'b) list + 424 val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t + 424 val Base.Map.range_to_alist : ('k, 'v, 'cmp) t -> min:'k -> max:'k -> ('k * 'v) list + 429 val Base.Or_error.combine_errors : 'a t list -> 'a list t + 437 val Base.Set.stable_dedup_list : ('a, _) Comparator.Module.t -> 'a list -> 'a list + 438 val Base.Hashtbl.Poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 440 val Base.Result.combine_errors : ('ok, 'err) t list -> ('ok list, 'err list) t + 440 val Base.String.Escaping.split : string -> on:char -> escape_char:char -> string list + 450 val Base.Map.of_alist_multi : ('a, 'cmp) Comparator.Module.t -> ('a * 'b) list -> ('a, 'b list, 'cmp) t + 472 val Base.Result.combine_errors_unit : (unit, 'err) t list -> (unit, 'err list) t + 476 val Base.String.Search_pattern.split_on : t -> string -> string list + 477 val Base.Map.of_sequence_multi : ('a, 'cmp) Comparator.Module.t -> ('a * 'b) Sequence.t -> ('a, 'b list, 'cmp) t + 485 val Base.Or_error.filter_ok_at_least_one : 'a t list -> 'a list t + 488 val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t + 495 val Base.Hashtbl.of_alist_multi : ?growth_allowed:bool -> + ?size:int -> + 'a Key.t -> + ('a * 'b) list -> + ('a, 'b list) t + 793 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list + 797 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + 814 val Base.Hashtbl.Accessors.data : (_, 'b) t -> 'b list + 818 val Base.Hashtbl.Accessors.keys : ('a, _) t -> 'a key list + 834 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list + 845 val Base.Hashtbl.Multi.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 852 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 855 val Base.Hashtbl.Accessors.to_alist : ('a, 'b) t -> ('a key * 'b) list + 891 val Base.Hashtbl.S_without_submodules.data : (_, 'b) t -> 'b list diff --git a/test/cram/base_web.t b/test/cram/base_web.t index f51350f3cd..e734c44d75 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -8,7 +8,7 @@ $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 4.8M megaodocl - $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') + $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $(find . -name '*.odocl') $ gzip -k db.js @@ -18,8 +18,8 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2700 db.js - 2036 db.js.gz + 2600 db.js + 1960 db.js.gz 1548 megaodocl.gz $ for f in $(find . -name '*.odocl'); do diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 53c5ccdb64..22d2ac1302 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -8,61 +8,61 @@ 8.0K megaodocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=ancient - $ sherlodoc_index $(find . -name '*.odocl') - $ sherlodoc "unique_name" + $ sherlodoc index $(find . -name '*.odocl') + $ sherlodoc search "unique_name" val Main.unique_name : foo - $ sherlodoc "multiple_hit" + $ sherlodoc search "multiple_hit" val Main.multiple_hit_1 : foo val Main.multiple_hit_2 : foo val Main.multiple_hit_3 : foo - $ sherlodoc "name_conflict" - type Main.name_conflict = foo - val Main.name_conflict : foo - $ sherlodoc "nesting_priority" + $ sherlodoc search --print-cost "name_conflict" + 832 val Main.name_conflict : foo + 832 type Main.name_conflict = foo + $ sherlodoc search "nesting_priority" val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo - $ sherlodoc "list" + $ sherlodoc search "list" mod Main.List type 'a Main.list type 'a Main.List.t = 'a list + val Main.Map.to_list : foo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - val Main.Map.to_list : foo val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo doc - $ sherlodoc "map" + $ sherlodoc search "map" mod Main.Map val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.Map.to_list : foo + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo - $ sherlodoc "list map" + $ sherlodoc search "list map" val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.Map.to_list : foo + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo - $ sherlodoc "map2" + $ sherlodoc search "map2" val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - $ sherlodoc ":moo" + $ sherlodoc search ":moo" val Main.value : moo val Main.produce : unit -> moo val Main.produce_2' : unit -> unit -> moo - $ sherlodoc ":_ -> moo" + $ sherlodoc search ":_ -> moo" val Main.produce : unit -> moo val Main.produce_2' : unit -> unit -> moo - $ sherlodoc ":moo -> _" + $ sherlodoc search ":moo -> _" val Main.consume : moo -> unit val Main.consume_2 : moo -> moo -> unit val Main.consume_2_other : moo -> t -> unit cons Main.MyExtension : moo -> extensible_type - $ sherlodoc "modtype" + $ sherlodoc search "modtype" sig Main.Modtype val Main.Modtype.v_modtype : foo - $ sherlodoc "S" + $ sherlodoc search "S" sig Main.S mod Main.List mod Main.Nest @@ -70,59 +70,59 @@ type 'a Main.list type 'a Main.List.t = 'a list val Main.consume : moo -> unit - val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - val Main.consume_2 : moo -> moo -> unit val Main.Map.to_list : foo - val Main.consume_2_other : moo -> t -> unit + val Main.consume_2 : moo -> moo -> unit + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t type Main.extensible_type = .. + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.nesting_priority : foo - val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - val Main.Nest.nesting_priority : foo + val Main.consume_2_other : moo -> t -> unit cons Main.MyExtension : moo -> extensible_type + val Main.Nest.nesting_priority : foo + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo doc - $ sherlodoc "qwertyuiopasdfghjklzxcvbnm" + $ sherlodoc search "qwertyuiopasdfghjklzxcvbnm" [No results] - $ sherlodoc "hidden" + $ sherlodoc search "hidden" [No results] TODO : get a result for the query bellow - $ sherlodoc ":mo" + $ sherlodoc search ":mo" val Main.value : moo val Main.produce : unit -> moo val Main.produce_2' : unit -> unit -> moo - $ sherlodoc ":'a" + $ sherlodoc search ":'a" val Main.poly_1 : 'a -> 'b -> 'c val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.poly_param : 'a boo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - $ sherlodoc ": 'a -> 'b -> 'c " + $ sherlodoc search ": 'a -> 'b -> 'c " val Main.poly_1 : 'a -> 'b -> 'c val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - $ sherlodoc ": ('a -> 'b) -> 'a t -> 'b t" + $ sherlodoc search ": ('a -> 'b) -> 'a t -> 'b t" val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t TODO : get a result for the query bellow - $ sherlodoc ": 'a bo" + $ sherlodoc search ": 'a bo" val Main.poly_param : 'a boo - $ sherlodoc ":extensible_type" + $ sherlodoc search ":extensible_type" cons Main.MyExtension : moo -> extensible_type - $ sherlodoc ":exn" + $ sherlodoc search ":exn" exn Main.Explicit_exn : exn_payload -> exn exn Main.Implicit_exn : exn_payload -> exn cons Main.Very_explicit_exn : exn_payload -> exn - $ sherlodoc ": exn_payload -> _" + $ sherlodoc search ": exn_payload -> _" exn Main.Explicit_exn : exn_payload -> exn exn Main.Implicit_exn : exn_payload -> exn cons Main.Very_explicit_exn : exn_payload -> exn - $ sherlodoc ": long_name_type" + $ sherlodoc search ": long_name_type" val Main.long_name_value : long_name_type - $ sherlodoc ": long_nam" + $ sherlodoc search ": long_nam" val Main.long_name_value : long_name_type - $ sherlodoc "long_name" + $ sherlodoc search "long_name" type Main.long_name_type val Main.long_name_value : long_name_type diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index 44c16a93e1..b799a74098 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -8,10 +8,10 @@ 4.0K megaodocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=ancient - $ sherlodoc_index $(find . -name '*.odocl') + $ sherlodoc index $(find . -name '*.odocl') TODO : get a result for the query bellow - $ sherlodoc ":'a" + $ sherlodoc search ":'a" val Main.poly_1 : 'a -> 'b -> 'c - $ sherlodoc ": 'a -> 'b -> 'c " + $ sherlodoc search ": 'a -> 'b -> 'c " val Main.poly_1 : 'a -> 'b -> 'c TODO : get a result for the query bellow diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 8337565d25..fce70d25ce 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -6,13 +6,12 @@ 4.0K megaodocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=ancient - $ sherlodoc_index $(find . -name '*.odocl') - $ sherlodoc --print-cost "list" - 109 mod Main.List - 209 type 'a Main.list - 315 type 'a Main.List.t = 'a list - 317 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 319 val Main.List.empty : 'a t * 'b t - $ export OCAMLRUNPARAM=b - $ sherlodoc ": (int, 'a) result" + $ sherlodoc index $(find . -name '*.odocl') + $ sherlodoc search --print-cost "list" + 263 mod Main.List + 763 type 'a Main.list + 891 type 'a Main.List.t = 'a list + 923 val Main.List.empty : 'a t * 'b t + 924 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + $ sherlodoc search ": (int, 'a) result" val Main.ok_zero : (int, 'a) result diff --git a/test/cram/dune b/test/cram/dune index cba60c517c..af6aba9786 100644 --- a/test/cram/dune +++ b/test/cram/dune @@ -3,5 +3,4 @@ (source_tree base_odocls) %{bin:odoc} %{bin:sherlodoc} - %{bin:sherlodoc_index} ../../jsoo/main.bc.js)) diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t index 9115565c67..2cf7b428f3 100644 --- a/test/cram/module_type_cost.t/run.t +++ b/test/cram/module_type_cost.t/run.t @@ -6,15 +6,15 @@ 4.0K megaodocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=ancient - $ sherlodoc_index $(find . -name '*.odocl') + $ sherlodoc index $(find . -name '*.odocl') Here we expect to have the `my_function` from the module be above the one from the module type. - $ sherlodoc --print-cost --no-rhs "my_function" - 218 val Main.M.my_function - 221 val Main.Make.my_function - 223 val Main.Make.M.my_function - 618 val Main.S.my_function + $ sherlodoc search --print-cost --no-rhs "my_function" + 839 val Main.M.my_function + 860 val Main.Make.my_function + 874 val Main.Make.M.my_function + 1239 val Main.S.my_function Here we expect both the module type and the module to be ranked the same - $ sherlodoc --print-cost "module" - 220 mod Main.Module_nype - 220 sig Main.Module_type + $ sherlodoc search --print-cost "module" + 416 mod Main.Module_nype + 416 sig Main.Module_type diff --git a/test/cram/query_syntax.t b/test/cram/query_syntax.t index 3dd0b1618a..3eda2f4d94 100644 --- a/test/cram/query_syntax.t +++ b/test/cram/query_syntax.t @@ -5,61 +5,61 @@ We need a dummy file because sherlodoc requires an odocl. $ odoc link -I . main.odoc $ export SHERLODOC_FORMAT=marshal $ export SHERLODOC_DB=db.bin - $ sherlodoc_index main.odocl - $ sherlodoc --pretty-query ": int list option" + $ sherlodoc index main.odocl + $ sherlodoc search --pretty-query ": int list option" : int list option [No results] $ export OCAMLRUNPARAM=b - $ sherlodoc --pretty-query ": _" + $ sherlodoc search --pretty-query ": _" : _ [No results] Testing incomplete queries - $ sherlodoc --pretty-query ": ->" + $ sherlodoc search --pretty-query ": ->" : _ -> _ [No results] - $ sherlodoc --pretty-query ": int ->" + $ sherlodoc search --pretty-query ": int ->" : int -> _ [No results] - $ sherlodoc --pretty-query ": int *" + $ sherlodoc search --pretty-query ": int *" : int * _ [No results] - $ sherlodoc --pretty-query ": string -> (" + $ sherlodoc search --pretty-query ": string -> (" : string -> _ [No results] - $ sherlodoc --pretty-query ": (int" + $ sherlodoc search --pretty-query ": (int" : int [No results] - $ sherlodoc --pretty-query ": (int ->" + $ sherlodoc search --pretty-query ": (int ->" : int -> _ [No results] - $ sherlodoc --pretty-query ": (int *" + $ sherlodoc search --pretty-query ": (int *" : int * _ [No results] - $ sherlodoc --pretty-query ": foo bar qux" + $ sherlodoc search --pretty-query ": foo bar qux" : foo bar qux [No results] - $ sherlodoc --pretty-query ": ()" + $ sherlodoc search --pretty-query ": ()" : _ [No results] - $ sherlodoc --pretty-query ": )" + $ sherlodoc search --pretty-query ": )" : _ [No results] - $ sherlodoc --pretty-query ": (int," + $ sherlodoc search --pretty-query ": (int," : int * _ [No results] - $ sherlodoc --pretty-query ": (int,string" + $ sherlodoc search --pretty-query ": (int,string" : int * string [No results] - $ sherlodoc --pretty-query ": 'a, 'b) result -" + $ sherlodoc search --pretty-query ": 'a, 'b) result -" : ('a, 'b) result -> _ [No results] - $ sherlodoc --pretty-query ": 'a * 'b) list" + $ sherlodoc search --pretty-query ": 'a * 'b) list" : ('a * 'b) list [No results] - $ sherlodoc --pretty-query ": - ,'a * 'b, 'c) result -) - ( -" + $ sherlodoc search --pretty-query ": - ,'a * 'b, 'c) result -) - ( -" : ((_ -> _, 'a * 'b, 'c) result -> _) -> _ -> _ [No results] Testing syntax errors - $ sherlodoc --pretty-query ": )(" + $ sherlodoc search --pretty-query ": )(" : [No results] diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 6297d0a37a..8a508aec7c 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -6,7 +6,7 @@ $ cat $(find . -name '*.odocl') > megaodocl $ du -sh megaodocl 12K megaodocl - $ sherlodoc_index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js diff --git a/www/dune b/www/dune index 738c903fa5..a4d68d049b 100644 --- a/www/dune +++ b/www/dune @@ -1,8 +1,3 @@ -; This is a server to answer sherlocode queries. A version of this runs on -; https://doc.sherlocode.com - -(executable - (public_name sherlodoc-www) +(library (name www) - (package sherlodoc-www) (libraries cmdliner dream tyxml db db_store query)) diff --git a/www/packages.ml b/www/packages.ml index fcff8b0dda..06a108c9d5 100644 --- a/www/packages.ml +++ b/www/packages.ml @@ -131,7 +131,7 @@ let load filename = close_in h ; result -let packages = +let packages () = List.fold_left (fun acc p -> M.remove p acc) (load "./static/packages.csv") @@ -139,10 +139,10 @@ let packages = open Tyxml.Html -let html = +let html () = div ~a:[ a_class [ "categories" ] ] - (M.bindings packages + (M.bindings (packages ()) |> List.map (fun (category, packages) -> div ~a:[ a_class [ "category" ] ] @@ -158,3 +158,6 @@ let html = ] [ txt package.name ])) ])) + +let html = lazy (html ()) +let html () = Lazy.force html diff --git a/www/ui.ml b/www/ui.ml index e61fc7bd14..1556c1f066 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -146,7 +146,7 @@ let link_to_repo = let link str = a ~a:[ a_href ("?q=" ^ Uri.pct_encode str) ] [ code [ txt str ] ] -let explain = +let explain () = div ~a:[ a_class [ "doc" ] ] [ h1 [ txt "Sherlodoc" ] @@ -171,6 +171,9 @@ let explain = ; link ": 'a list -> ('a * int -> bool) -> 'a list" ] ] - ; Packages.html + ; Packages.html () ; link_to_repo ] + +let explain = lazy (explain ()) +let explain () = Lazy.force explain diff --git a/www/www.ml b/www/www.ml index d221e5de8f..3496bae994 100644 --- a/www/www.ml +++ b/www/www.ml @@ -8,7 +8,7 @@ let api ~shards params = let api ~shards params = if String.trim params.Query.query = "" - then Lwt.return Ui.explain + then Lwt.return (Ui.explain ()) else api ~shards params open Lwt.Syntax @@ -46,11 +46,11 @@ let root fn params = try root fn params with | err -> Format.printf "ERROR: %S@." (Printexc.to_string err) ; - Dream.html (string_of_tyxml @@ Ui.template params.query Ui.explain) + Dream.html (string_of_tyxml @@ Ui.template params.query (Ui.explain ())) let root fn params = try root fn params with - | _ -> Dream.html (string_of_tyxml @@ Ui.template "" Ui.explain) + | _ -> Dream.html (string_of_tyxml @@ Ui.template "" (Ui.explain ())) let cache_header : int option -> Dream.middleware = fun max_age f req -> @@ -118,11 +118,4 @@ let cache_max_age = let doc = "HTTP cache max age (in seconds)" in Arg.(value & opt (some int) None & info [ "c"; "cache" ] ~docv:"MAX_AGE" ~doc) -let www = Term.(const main $ db_format $ db_path $ cache_max_age) - -let cmd = - let doc = "Webserver for sherlodoc" in - let info = Cmd.info "www" ~doc in - Cmd.v info www - -let () = exit (Cmd.eval cmd) +let term = Term.(const main $ db_format $ db_path $ cache_max_age) From a93155fd834539473e045bb5aa95747bae29db20 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 3 Jan 2024 09:45:06 +0100 Subject: [PATCH 217/285] optional dependency to dream --- cli/dune | 11 ++++++++++- cli/main.ml | 2 +- cli/serve.available.ml | 1 + cli/serve.mli | 1 + cli/serve.unavailable.ml | 6 ++++++ index/index.mli | 1 + www/dune | 1 + www/www.mli | 1 + 8 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 cli/serve.available.ml create mode 100644 cli/serve.mli create mode 100644 cli/serve.unavailable.ml create mode 100644 index/index.mli create mode 100644 www/www.mli diff --git a/cli/dune b/cli/dune index 4445803ceb..7be3cf6dde 100644 --- a/cli/dune +++ b/cli/dune @@ -4,4 +4,13 @@ (name main) (public_name sherlodoc) (package sherlodoc) - (libraries index www cmdliner query db_store)) + (libraries + cmdliner + index + query + db_store + (select + serve.ml + from + (www -> serve.available.ml) + (!www -> serve.unavailable.ml)))) diff --git a/cli/main.ml b/cli/main.ml index dcc0329de4..2360bb78e5 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -139,7 +139,7 @@ let cmd_index = let cmd_serve = let doc = "Webserver interface" in let info = Cmd.info "serve" ~doc in - Cmd.v info Www.term + Cmd.v info Serve.term let cmd = let doc = "Sherlodoc" in diff --git a/cli/serve.available.ml b/cli/serve.available.ml new file mode 100644 index 0000000000..87d0864b6b --- /dev/null +++ b/cli/serve.available.ml @@ -0,0 +1 @@ +let term = Www.term diff --git a/cli/serve.mli b/cli/serve.mli new file mode 100644 index 0000000000..fae8900e05 --- /dev/null +++ b/cli/serve.mli @@ -0,0 +1 @@ +val term : (Db_store.db_format -> string -> unit) Cmdliner.Term.t diff --git a/cli/serve.unavailable.ml b/cli/serve.unavailable.ml new file mode 100644 index 0000000000..4dad6408f7 --- /dev/null +++ b/cli/serve.unavailable.ml @@ -0,0 +1,6 @@ +let main () = + Format.fprintf + Format.err_formatter + "Webserver unavailable: please install dream and retry.@." + +let term = Cmdliner.Term.(const main $ const ()) diff --git a/index/index.mli b/index/index.mli new file mode 100644 index 0000000000..f935ca2041 --- /dev/null +++ b/index/index.mli @@ -0,0 +1 @@ +val term : unit Cmdliner.Term.t diff --git a/www/dune b/www/dune index a4d68d049b..f9728d72ef 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,4 @@ (library (name www) + (optional) (libraries cmdliner dream tyxml db db_store query)) diff --git a/www/www.mli b/www/www.mli new file mode 100644 index 0000000000..f935ca2041 --- /dev/null +++ b/www/www.mli @@ -0,0 +1 @@ +val term : unit Cmdliner.Term.t From 0115e952b2962ce54aa5c2504eb14952dcf6be30 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 3 Jan 2024 10:20:54 +0100 Subject: [PATCH 218/285] fix cmdliner db argument --- cli/main.ml | 28 +++++++--------------------- cli/serve.unavailable.ml | 4 ++-- www/www.ml | 13 ++----------- www/www.mli | 8 +++++++- 4 files changed, 18 insertions(+), 35 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index 2360bb78e5..64da8a8b50 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -1,8 +1,3 @@ -(** This executable allows to search in a sherlodoc database on the commandline. - It is mainly used for testing, but should work as is as a commandline tool. *) - -let pp_or cond pp_true pp_false ppf = if cond then pp_true ppf else pp_false ppf - let string_of_kind = let open Db.Entry.Kind in function @@ -55,20 +50,11 @@ let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db = | None -> print_endline "[Search session ended]" let main db_format db query print_cost no_rhs static_sort limit pretty_query = - match db with - | None -> - output_string - stderr - "No database provided. Provide one by exporting the SHERLODOC_DB variable, or \ - using the --db option\n" ; - exit 1 - | Some db -> - let module Storage = (val Db_store.storage_module db_format) in - let db = Storage.load db in - (match query with - | None -> search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db - | Some query -> - search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db query) + let module Storage = (val Db_store.storage_module db_format) in + let db = Storage.load db in + match query with + | None -> search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db + | Some query -> search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db query open Cmdliner @@ -85,7 +71,7 @@ let db_filename = let doc = "The database to query" in Cmd.Env.info "SHERLODOC_DB" ~doc in - Arg.(value & opt (some file) None & info [ "db" ] ~docv:"DB" ~env) + Arg.(required & opt (some file) None & info [ "db" ] ~docv:"DB" ~env) let limit = let doc = "The maximum number of results per query" in @@ -139,7 +125,7 @@ let cmd_index = let cmd_serve = let doc = "Webserver interface" in let info = Cmd.info "serve" ~doc in - Cmd.v info Serve.term + Cmd.v info Term.(Serve.term $ db_format $ db_filename) let cmd = let doc = "Sherlodoc" in diff --git a/cli/serve.unavailable.ml b/cli/serve.unavailable.ml index 4dad6408f7..fa2c0ffbab 100644 --- a/cli/serve.unavailable.ml +++ b/cli/serve.unavailable.ml @@ -1,6 +1,6 @@ -let main () = +let main _ _ = Format.fprintf Format.err_formatter "Webserver unavailable: please install dream and retry.@." -let term = Cmdliner.Term.(const main $ const ()) +let term = Cmdliner.Term.const main diff --git a/www/www.ml b/www/www.ml index 3496bae994..436e9db567 100644 --- a/www/www.ml +++ b/www/www.ml @@ -78,7 +78,7 @@ let cors_options = Dream.add_header response "Access-Control-Allow-Headers" "*" ; response) -let main db_format db_filename cache_max_age = +let main cache_max_age db_format db_filename = let module Storage = (val Db_store.storage_module db_format) in let shards = Storage.load db_filename in Dream.run ~interface:"127.0.0.1" ~port:1234 @@ -105,17 +105,8 @@ let main db_format db_filename cache_max_age = open Cmdliner -let db_format = - let doc = "Database format" in - let kind = Arg.enum Db_store.available_backends in - Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~doc) - -let db_path = - let doc = "Database filename" in - Arg.(required & pos 0 (some file) None & info [] ~docv:"DB" ~doc) - let cache_max_age = let doc = "HTTP cache max age (in seconds)" in Arg.(value & opt (some int) None & info [ "c"; "cache" ] ~docv:"MAX_AGE" ~doc) -let term = Term.(const main $ db_format $ db_path $ cache_max_age) +let term = Term.(const main $ cache_max_age) diff --git a/www/www.mli b/www/www.mli index f935ca2041..934bcb68db 100644 --- a/www/www.mli +++ b/www/www.mli @@ -1 +1,7 @@ -val term : unit Cmdliner.Term.t +type db_format := + [ `ancient + | `marshal + | `js + ] + +val term : (db_format -> string -> unit) Cmdliner.Term.t From abfbdbe46a794076af67bfecc5861d663ef2b60e Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 3 Jan 2024 10:58:58 +0100 Subject: [PATCH 219/285] guess db_format from filename extension --- cli/main.ml | 58 +++++++++++++++++++++++----------- index/index.ml | 27 ++-------------- index/index.mli | 2 +- store/db_store.default.ml | 5 +++ store/db_store.with_ancient.ml | 6 ++++ www/www.mli | 8 +---- 6 files changed, 55 insertions(+), 51 deletions(-) diff --git a/cli/main.ml b/cli/main.ml index 64da8a8b50..6af5777220 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -49,9 +49,26 @@ let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db = search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db | None -> print_endline "[Search session ended]" -let main db_format db query print_cost no_rhs static_sort limit pretty_query = +let guess_db_format db_format db_filename = + match db_format with + | Some db_format -> db_format + | None -> begin + let ext = Filename.extension db_filename in + let ext_len = String.length ext in + let ext = if ext_len = 0 then ext else String.sub ext 1 (ext_len - 1) in + try List.assoc ext Db_store.available_backends with + | Not_found -> + Format.fprintf + Format.err_formatter + "Unknown db format extension %S (expected: %s)@." + ext + (String.concat ", " @@ List.map fst Db_store.available_backends) ; + exit 1 + end + +let search query print_cost no_rhs static_sort limit pretty_query db_format db_filename = let module Storage = (val Db_store.storage_module db_format) in - let db = Storage.load db in + let db = Storage.load db_filename in match query with | None -> search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db | Some query -> search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db query @@ -64,9 +81,16 @@ let db_format = Cmd.Env.info "SHERLODOC_FORMAT" ~doc in let kind = Arg.enum Db_store.available_backends in - Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~env) + Arg.(value & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~env) let db_filename = + let env = + let doc = "The database to query" in + Cmd.Env.info "SHERLODOC_DB" ~doc + in + Arg.(required & opt (some string) None & info [ "db" ] ~docv:"DB" ~env) + +let db_path = let env = let doc = "The database to query" in Cmd.Env.info "SHERLODOC_DB" ~doc @@ -101,31 +125,29 @@ let pretty_query = let doc = "Prints the query itself as it was parsed" in Arg.(value & flag & info [ "pretty-query" ] ~doc) -let main = - Term.( - const main - $ db_format - $ db_filename - $ query - $ print_cost - $ no_rhs - $ static_sort - $ limit - $ pretty_query) +let search_term = + Term.(const search $ query $ print_cost $ no_rhs $ static_sort $ limit $ pretty_query) + +let with_db fn db_path = + let apply fn db_format db_filename = + let db_format = guess_db_format db_format db_filename in + fn db_format db_filename + in + Term.(const apply $ fn $ db_format $ db_path) let cmd_search = - let info = Cmd.info "search" ~doc:"Search" in - Cmd.v info main + let info = Cmd.info "search" ~doc:"Command-line search" in + Cmd.v info (with_db search_term db_path) let cmd_index = let doc = "Index odocl files to create a Sherlodoc database" in let info = Cmd.info "index" ~doc in - Cmd.v info Index.term + Cmd.v info (with_db Index.term db_filename) let cmd_serve = let doc = "Webserver interface" in let info = Cmd.info "serve" ~doc in - Cmd.v info Term.(Serve.term $ db_format $ db_filename) + Cmd.v info (with_db Serve.term db_path) let cmd = let doc = "Sherlodoc" in diff --git a/index/index.ml b/index/index.ml index 2238f7eb45..e851b6f73b 100644 --- a/index/index.ml +++ b/index/index.ml @@ -15,7 +15,7 @@ let index_file register filename = | Ok result -> result | Error (`Msg msg) -> Format.printf "Odoc warning or error %s: %s@." filename msg) -let main files file_list index_docstring index_name type_search db_filename db_format = +let main files file_list index_docstring index_name type_search db_format db_filename = let module Storage = (val Db_store.storage_module db_format) in let db = Db.make () in let pkg = Db.Entry.Package.v ~name:"" ~version:"" in @@ -51,21 +51,6 @@ let type_search = let doc = "Enable type based search" in Arg.(value & opt bool true & info ~doc [ "type-search" ]) -let db_format = - let env = - let doc = "Database format" in - Cmd.Env.info "SHERLODOC_FORMAT" ~doc - in - let kind = Arg.enum Db_store.available_backends in - Arg.(required & opt (some kind) None & info [ "format" ] ~docv:"DB_FORMAT" ~env) - -let db_filename = - let env = - let doc = "The database to create" in - Cmd.Env.info "SHERLODOC_DB" ~doc - in - Arg.(required & opt (some string) None & info [ "db"; "output"; "o" ] ~docv:"DB" ~env) - let file_list = let doc = "File containing a list of .odocl files.\n\ @@ -78,12 +63,4 @@ let odoc_files = Arg.(non_empty & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) let term = - Term.( - const main - $ odoc_files - $ file_list - $ index_docstring - $ index_name - $ type_search - $ db_filename - $ db_format) + Term.(const main $ odoc_files $ file_list $ index_docstring $ index_name $ type_search) diff --git a/index/index.mli b/index/index.mli index f935ca2041..fae8900e05 100644 --- a/index/index.mli +++ b/index/index.mli @@ -1 +1 @@ -val term : unit Cmdliner.Term.t +val term : (Db_store.db_format -> string -> unit) Cmdliner.Term.t diff --git a/store/db_store.default.ml b/store/db_store.default.ml index 588bf32ddd..2183d094c6 100644 --- a/store/db_store.default.ml +++ b/store/db_store.default.ml @@ -1,3 +1,8 @@ +type db_format = + [ `marshal + | `js + ] + let available_backends = [ "marshal", `marshal; "js", `js ] let storage_module = function diff --git a/store/db_store.with_ancient.ml b/store/db_store.with_ancient.ml index 7e475fdaad..344dae6eef 100644 --- a/store/db_store.with_ancient.ml +++ b/store/db_store.with_ancient.ml @@ -1,3 +1,9 @@ +type db_format = + [ `ancient + | `marshal + | `js + ] + let available_backends = [ "ancient", `ancient; "marshal", `marshal; "js", `js ] let storage_module = function diff --git a/www/www.mli b/www/www.mli index 934bcb68db..fae8900e05 100644 --- a/www/www.mli +++ b/www/www.mli @@ -1,7 +1 @@ -type db_format := - [ `ancient - | `marshal - | `js - ] - -val term : (db_format -> string -> unit) Cmdliner.Term.t +val term : (Db_store.db_format -> string -> unit) Cmdliner.Term.t From d16f726fa225472e1655cd1c5ff5f64701df9f22 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 3 Jan 2024 11:46:26 +0100 Subject: [PATCH 220/285] interactive cli with colors --- cli/main.ml | 91 +---------------------------------------- cli/search.ml | 96 ++++++++++++++++++++++++++++++++++++++++++++ cli/search.mli | 1 + test/cram/base_cli.t | 79 ------------------------------------ 4 files changed, 98 insertions(+), 169 deletions(-) create mode 100644 cli/search.ml create mode 100644 cli/search.mli diff --git a/cli/main.ml b/cli/main.ml index 6af5777220..745f6be0cd 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -1,54 +1,3 @@ -let string_of_kind = - let open Db.Entry.Kind in - function - | Doc -> "doc" - | Type_decl _ -> "type" - | Module -> "mod" - | Exception _ -> "exn" - | Class_type -> "class" - | Method -> "meth" - | Class -> "class" - | Type_extension -> "type" - | Extension_constructor _ -> "cons" - | Module_type -> "sig" - | Constructor _ -> "cons" - | Field _ -> "field" - | Val _ -> "val" - -let print_result ~print_cost ~no_rhs (elt : Db.Entry.t) = - let cost = if print_cost then string_of_int elt.cost ^ " " else "" in - let typedecl_params = - (match elt.kind with - | Type_decl args -> args - | _ -> None) - |> Option.map (fun str -> str ^ " ") - |> Option.value ~default:"" - in - let kind = elt.kind |> string_of_kind |> Unescape.string in - let name = Unescape.string elt.name in - let pp_rhs h = function - | None -> () - | Some _ when no_rhs -> () - | Some rhs -> Format.fprintf h "%s" (Unescape.string rhs) - in - Format.printf "%s%s %s%s%a@." cost kind typedecl_params name pp_rhs elt.rhs - -let search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query = - let query = Query.{ query; packages = []; limit } in - if pretty_query then print_endline (Query.pretty query) ; - match Query.(search ~shards:db ~dynamic_sort:(not static_sort) query) with - | [] -> print_endline "[No results]" - | _ :: _ as results -> - List.iter (print_result ~print_cost ~no_rhs) results ; - flush stdout - -let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db = - match In_channel.input_line stdin with - | Some query -> - search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query ; - search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db - | None -> print_endline "[Search session ended]" - let guess_db_format db_format db_filename = match db_format with | Some db_format -> db_format @@ -66,13 +15,6 @@ let guess_db_format db_format db_filename = exit 1 end -let search query print_cost no_rhs static_sort limit pretty_query db_format db_filename = - let module Storage = (val Db_store.storage_module db_format) in - let db = Storage.load db_filename in - match query with - | None -> search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db - | Some query -> search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db query - open Cmdliner let db_format = @@ -97,37 +39,6 @@ let db_path = in Arg.(required & opt (some file) None & info [ "db" ] ~docv:"DB" ~env) -let limit = - let doc = "The maximum number of results per query" in - Arg.(value & opt int 50 & info [ "limit"; "n" ] ~docv:"N" ~doc) - -let query = - let doc = "The query. If absent, sherlodoc will read queries in the standard input." in - Arg.(value & pos 0 (some string) None & info [] ~docv:"QUERY" ~doc) - -let print_cost = - let doc = "For debugging purposes : prints the cost of each result" in - Arg.(value & flag & info [ "print-cost" ] ~doc) - -let static_sort = - let doc = - "Sort the results without looking at the query.\n\ - Enabling it allows to look at the static costs of elements.\n\ - Mainly for testing purposes." - in - Arg.(value & flag & info [ "static-sort" ] ~doc) - -let no_rhs = - let doc = "Do not print the right-hand side of results." in - Arg.(value & flag & info [ "no-rhs"; "no-right-hand-side" ] ~doc) - -let pretty_query = - let doc = "Prints the query itself as it was parsed" in - Arg.(value & flag & info [ "pretty-query" ] ~doc) - -let search_term = - Term.(const search $ query $ print_cost $ no_rhs $ static_sort $ limit $ pretty_query) - let with_db fn db_path = let apply fn db_format db_filename = let db_format = guess_db_format db_format db_filename in @@ -137,7 +48,7 @@ let with_db fn db_path = let cmd_search = let info = Cmd.info "search" ~doc:"Command-line search" in - Cmd.v info (with_db search_term db_path) + Cmd.v info (with_db Search.term db_path) let cmd_index = let doc = "Index odocl files to create a Sherlodoc database" in diff --git a/cli/search.ml b/cli/search.ml new file mode 100644 index 0000000000..4b8bfdbf97 --- /dev/null +++ b/cli/search.ml @@ -0,0 +1,96 @@ +let header = + {|Sherlodoc v0.2 -- search OCaml documentation by name and type (use CTRL-D to exit)|} + +let string_of_kind = + let open Db.Entry.Kind in + function + | Doc -> "doc" + | Type_decl _ -> "type" + | Module -> "mod" + | Exception _ -> "exn" + | Class_type -> "class" + | Method -> "meth" + | Class -> "class" + | Type_extension -> "type" + | Extension_constructor _ -> "cons" + | Module_type -> "sig" + | Constructor _ -> "cons" + | Field _ -> "field" + | Val _ -> "val" + +let print_result ~print_cost ~no_rhs (elt : Db.Entry.t) = + let cost = if print_cost then string_of_int elt.cost ^ " " else "" in + let typedecl_params = + (match elt.kind with + | Type_decl args -> args + | _ -> None) + |> Option.map (fun str -> str ^ " ") + |> Option.value ~default:"" + in + let kind = elt.kind |> string_of_kind |> Unescape.string in + let name = Unescape.string elt.name in + let pp_rhs h = function + | None -> () + | Some _ when no_rhs -> () + | Some rhs -> Format.fprintf h "%s" (Unescape.string rhs) + in + Format.printf "%s%s %s%s%a@." cost kind typedecl_params name pp_rhs elt.rhs + +let search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query = + let query = Query.{ query; packages = []; limit } in + if pretty_query then print_endline (Query.pretty query) ; + match Query.search ~shards:db ~dynamic_sort:(not static_sort) query with + | [] -> print_endline "[No results]" + | _ :: _ as results -> + List.iter (print_result ~print_cost ~no_rhs) results ; + flush stdout + +let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db = + Printf.printf "%ssearch>%s %!" "\027[0;36m" "\027[0;0m" ; + match Stdlib.input_line stdin with + | query -> + search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query ; + search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db + | None -> print_endline "[Search session ended]" + +let search query print_cost no_rhs static_sort limit pretty_query db_format db_filename = + let module Storage = (val Db_store.storage_module db_format) in + let db = Storage.load db_filename in + match query with + | None -> + print_endline header ; + search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db + | Some query -> search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db query + +open Cmdliner + +let limit = + let doc = "The maximum number of results per query" in + Arg.(value & opt int 25 & info [ "limit"; "n" ] ~docv:"N" ~doc) + +let query = + let doc = "The query. If absent, queries will be read interactively." in + Arg.(value & pos 0 (some string) None & info [] ~docv:"QUERY" ~doc) + +let print_cost = + let doc = "For debugging purposes: prints the cost of each result" in + Arg.(value & flag & info [ "print-cost" ] ~doc) + +let static_sort = + let doc = + "Sort the results without looking at the query.\n\ + Enabling it allows to look at the static costs of elements.\n\ + Mainly for testing purposes." + in + Arg.(value & flag & info [ "static-sort" ] ~doc) + +let no_rhs = + let doc = "Do not print the right-hand side of results." in + Arg.(value & flag & info [ "no-rhs"; "no-right-hand-side" ] ~doc) + +let pretty_query = + let doc = "Prints the query itself as it was parsed" in + Arg.(value & flag & info [ "pretty-query" ] ~doc) + +let term = + Term.(const search $ query $ print_cost $ no_rhs $ static_sort $ limit $ pretty_query) diff --git a/cli/search.mli b/cli/search.mli new file mode 100644 index 0000000000..fae8900e05 --- /dev/null +++ b/cli/search.mli @@ -0,0 +1 @@ +val term : (Db_store.db_format -> string -> unit) Cmdliner.Term.t diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index f32cedb3da..481adf4dd6 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -192,31 +192,6 @@ 733 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t 776 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t 857 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 864 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 871 val Base.Or_error.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 917 val Base.Either.First.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t - 924 val Base.Either.Second.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t - 927 val Base.Applicative.Pair.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 933 val Base.Applicative.Make.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t - 941 val Base.Applicative.Pair.F.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 941 val Base.Applicative.Pair.G.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 948 val Base.Applicative.Compose.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 948 val Base.Applicative.S2_to_S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 948 val Base.Applicative.S3_to_S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 975 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 982 val Base.Array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 995 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 1056 type 'a Base.Applicative.Make_using_map2.X.t - 1063 type ('a, 'e) Base.Applicative.Make2_using_map2.X.t - 1063 type ('a, 'd, 'e) Base.Applicative.Make3_using_map2.X.t - 1306 val Base.Applicative.S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 1331 val Base.Applicative.S2.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t - 1331 val Base.Either.Focused.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t - 1343 val Base.Applicative.S3.map2 : ('a, 'd, 'e) t -> ('b, 'd, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'd, 'e) t - 1348 val Base.Applicative.S_local.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 1449 type 'a Base.Applicative.Basic_using_map2.t - 1456 type ('a, 'e) Base.Applicative.Basic2_using_map2.t - 1456 type ('a, 'd, 'e) Base.Applicative.Basic3_using_map2.t $ sherlodoc search --print-cost --no-rhs --static-sort "List map2" 277 val Base.List.rev_map2_exn 650 val Base.List.map2 @@ -250,33 +225,8 @@ 438 val Base.List.(>>|) : 'a t -> ('a -> 'b) -> 'b t 438 val Base.Set.to_list : ('a, _) t -> 'a list 439 val Base.List.append : 'a t -> 'a t -> 'a t - 440 val Base.List.find : 'a t -> f:('a -> bool) -> 'a option - 440 val Base.List.mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t 440 val Base.List.(>>=) : 'a t -> ('a -> 'b t) -> 'b t - 441 val Base.List.count : 'a t -> f:('a -> bool) -> int - 443 val Base.List.nth_exn : 'a t -> int -> 'a - 444 val Base.List.mem : 'a t -> 'a -> equal:('a -> 'a -> bool) -> bool 444 mod Base.List.Let_syntax - 446 val Base.List.sort : 'a t -> compare:('a -> 'a -> int) -> 'a t - 446 val Base.Bytes.to_list : t -> char list - 447 val Base.List.ignore_m : 'a t -> unit t - 447 val Base.Queue.of_list : 'a list -> 'a t - 447 val Base.Stack.of_list : 'a list -> 'a t - 449 val Base.List.exists : 'a t -> f:('a -> bool) -> bool - 449 val Base.List.filter : 'a t -> f:('a -> bool) -> 'a t - 451 mod Base.List.Monad_infix - 452 val Base.List.split_n : 'a t -> int -> 'a t * 'a t - 454 val Base.List.group : 'a t -> break:('a -> 'a -> bool) -> 'a t t - 454 val Base.List.rev_map : 'a t -> f:('a -> 'b) -> 'b t - 454 val Base.List.all_unit : unit t list -> unit t - 456 val Base.List.fold : 'a t -> init:'acc -> f:('acc -> 'a -> 'acc) -> 'acc - 456 val Base.Info.of_list : ?trunc_after:int -> t list -> t - 456 val Base.List.for_all : 'a t -> f:('a -> bool) -> bool - 459 val Base.List.drop_last : 'a t -> 'a t option - 461 val Base.List.find_exn : 'a t -> f:('a -> bool) -> 'a - 463 val Base.List.transpose : 'a t t -> 'a t t option - 861 val Base.Queue.S.of_list : 'a list -> 'a t - 861 val Base.Stack.S.of_list : 'a list -> 'a t $ sherlodoc search --print-cost ": list" 320 val Base.Map.data : (_, 'v, _) t -> 'v list 320 val Base.Map.keys : ('k, _, _) t -> 'k list @@ -301,34 +251,5 @@ 403 val Base.Hashtbl.find_multi : ('a, 'b list) t -> 'a key -> 'b list 404 val Base.Sequence.chunks_exn : 'a t -> int -> 'a list t 410 val Base.Map.add_multi : ('k, 'v list, 'cmp) t -> key:'k -> data:'v -> ('k, 'v list, 'cmp) t - 412 val Base.List.find_all_dups : 'a t -> compare:('a -> 'a -> int) -> 'a list - 414 val Base.String.split_on_chars : t -> on:char list -> t list - 415 val Base.Map.remove_multi : ('k, 'v list, 'cmp) t -> 'k -> ('k, 'v list, 'cmp) t - 420 val Base.Hashtbl.Poly.to_alist : ('a, 'b) t -> ('a key * 'b) list - 424 val Base.List.Assoc.group : ('a * 'b) list -> equal:('a -> 'a -> bool) -> ('a, 'b list) t - 424 val Base.Map.range_to_alist : ('k, 'v, 'cmp) t -> min:'k -> max:'k -> ('k * 'v) list - 429 val Base.Or_error.combine_errors : 'a t list -> 'a list t - 437 val Base.Set.stable_dedup_list : ('a, _) Comparator.Module.t -> 'a list -> 'a list - 438 val Base.Hashtbl.Poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list - 440 val Base.Result.combine_errors : ('ok, 'err) t list -> ('ok list, 'err list) t - 440 val Base.String.Escaping.split : string -> on:char -> escape_char:char -> string list - 450 val Base.Map.of_alist_multi : ('a, 'cmp) Comparator.Module.t -> ('a * 'b) list -> ('a, 'b list, 'cmp) t - 472 val Base.Result.combine_errors_unit : (unit, 'err) t list -> (unit, 'err list) t - 476 val Base.String.Search_pattern.split_on : t -> string -> string list - 477 val Base.Map.of_sequence_multi : ('a, 'cmp) Comparator.Module.t -> ('a * 'b) Sequence.t -> ('a, 'b list, 'cmp) t - 485 val Base.Or_error.filter_ok_at_least_one : 'a t list -> 'a list t - 488 val Base.List.Assoc.sort_and_group : ('a * 'b) list -> compare:('a -> 'a -> int) -> ('a, 'b list) t - 495 val Base.Hashtbl.of_alist_multi : ?growth_allowed:bool -> - ?size:int -> - 'a Key.t -> - ('a * 'b) list -> - ('a, 'b list) t 793 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list 797 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list - 814 val Base.Hashtbl.Accessors.data : (_, 'b) t -> 'b list - 818 val Base.Hashtbl.Accessors.keys : ('a, _) t -> 'a key list - 834 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list - 845 val Base.Hashtbl.Multi.find_multi : ('a, 'b list) t -> 'a key -> 'b list - 852 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list - 855 val Base.Hashtbl.Accessors.to_alist : ('a, 'b) t -> ('a key * 'b) list - 891 val Base.Hashtbl.S_without_submodules.data : (_, 'b) t -> 'b list From ad6b9d7c76272a2295bccc2a789bf6f112b2869c Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 3 Jan 2024 14:50:14 +0100 Subject: [PATCH 221/285] allow search with incomplete type names --- db/db.ml | 27 +++++++++++++++------- db/db.mli | 5 ++-- db/storage.ml | 3 ++- db/suffix_tree.ml | 19 +++++++++++---- db/suffix_tree.mli | 8 ++++++- db/type_polarity.ml | 41 +++++++++++++++----------------- db/type_polarity.mli | 4 ++-- query/query.ml | 16 ++++++++----- query/succ.ml | 5 ++-- test/cram/base_cli.t | 54 +++++++++++++++++++++++++++++++++++++++++++ test/cram/base_web.t | 4 ++-- test/cram/cli.t/run.t | 1 + 12 files changed, 136 insertions(+), 51 deletions(-) diff --git a/db/db.ml b/db/db.ml index fe5b0d880c..2c574731f1 100644 --- a/db/db.ml +++ b/db/db.ml @@ -7,28 +7,39 @@ module Typexpr = Typexpr type t = Storage.db = { db_names : Suffix_tree.With_elts.reader - ; db_types : Suffix_tree.With_occ.reader + ; db_pos_types : Suffix_tree.With_occ.reader + ; db_neg_types : Suffix_tree.With_occ.reader } type writer = { writer_names : Suffix_tree.With_elts.writer - ; writer_types : Suffix_tree.With_occ.writer + ; writer_pos_types : Suffix_tree.With_occ.writer + ; writer_neg_types : Suffix_tree.With_occ.writer } let make () = - { writer_names = Suffix_tree.With_elts.make () - ; writer_types = Suffix_tree.With_occ.make () + let buffer_names = Suffix_tree.Buf.make () in + let buffer_types = Suffix_tree.Buf.make () in + { writer_names = Suffix_tree.With_elts.make buffer_names + ; writer_pos_types = Suffix_tree.With_occ.make buffer_types + ; writer_neg_types = Suffix_tree.With_occ.make buffer_types } let export db = { Storage.db_names = Suffix_tree.With_elts.export db.writer_names - ; db_types = Suffix_tree.With_occ.export db.writer_types + ; db_pos_types = Suffix_tree.With_occ.export db.writer_pos_types + ; db_neg_types = Suffix_tree.With_occ.export db.writer_neg_types } -let store db name elt ~count = - Suffix_tree.With_occ.add_suffixes db.writer_types name (count, elt) +let store db name elt ~count ~polarity = + let st = + match polarity with + | Type_polarity.Sign.Pos -> db.writer_pos_types + | Type_polarity.Sign.Neg -> db.writer_neg_types + in + Suffix_tree.With_occ.add_suffixes st name (count, elt) let store_type_polarities db elt polarities = - List.iter (fun (word, count) -> store db ~count word elt) polarities + Seq.iter (fun (path, count, polarity) -> store db ~count ~polarity path elt) polarities let store_word db word elt = Suffix_tree.With_elts.add_suffixes db.writer_names word elt diff --git a/db/db.mli b/db/db.mli index 6d85214fb6..239ff3ce85 100644 --- a/db/db.mli +++ b/db/db.mli @@ -7,7 +7,8 @@ module Typexpr = Typexpr type t = Storage.db = { db_names : Suffix_tree.With_elts.reader - ; db_types : Suffix_tree.With_occ.reader + ; db_pos_types : Suffix_tree.With_occ.reader + ; db_neg_types : Suffix_tree.With_occ.reader } (** The type of a search database. @@ -28,6 +29,6 @@ type writer val make : unit -> writer (** [make ()] returns an empty search database. *) -val store_type_polarities : writer -> Entry.t -> Type_polarity.t list -> unit +val store_type_polarities : writer -> Entry.t -> Type_polarity.t Seq.t -> unit val store_word : writer -> string -> Entry.t -> unit val export : writer -> t diff --git a/db/storage.ml b/db/storage.ml index 9e9c151591..0b1315e37d 100644 --- a/db/storage.ml +++ b/db/storage.ml @@ -1,6 +1,7 @@ type db = { db_names : Suffix_tree.With_elts.reader - ; db_types : Suffix_tree.With_occ.reader + ; db_pos_types : Suffix_tree.With_occ.reader + ; db_neg_types : Suffix_tree.With_occ.reader } module type S = sig diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index dc1f97344c..f89e4d8b38 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -37,13 +37,24 @@ module Buf = struct type t = { buffer : Buffer.t ; cache : int String_hashtbl.t + ; mutable contents : string option } - let make () = { buffer = Buffer.create 16; cache = String_hashtbl.create 16 } - let contents t = Buffer.contents t.buffer + let make () = + { buffer = Buffer.create 16; cache = String_hashtbl.create 16; contents = None } + + let contents t = + match t.contents with + | Some contents -> contents + | None -> + let contents = Buffer.contents t.buffer in + t.contents <- Some contents ; + contents + let get t i = Buffer.nth t.buffer i - let add { buffer; cache } substr = + let add { buffer; cache; contents } substr = + assert (contents = None) ; match String_hashtbl.find_opt cache substr with | Some start -> start | None -> @@ -112,7 +123,7 @@ module Make (S : SET) = struct ; children = Char_map.empty } - let make () = { root = make_root (); buffer = Buf.make () } + let make buffer = { root = make_root (); buffer } let split_at ~str node len = let split_chr = Buf.get str (node.start + len) in diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index d5017babbe..5dfaf721b2 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -13,12 +13,18 @@ module type SET = sig val equal_elt : elt -> elt -> bool end +module Buf : sig + type t + + val make : unit -> t +end + module Make (S : SET) : sig type writer (** A writer is an incomplete suffix tree. You can add suffixes to it. *) - val make : unit -> writer + val make : Buf.t -> writer val add_suffixes : writer -> string -> S.elt -> unit type reader diff --git a/db/type_polarity.ml b/db/type_polarity.ml index 12ed04b72f..1ed8d6f235 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -1,18 +1,5 @@ -module String_map = Map.Make (String) open Typexpr -let regroup lst = - String_map.bindings - @@ List.fold_left - (fun acc s -> - let count = - try String_map.find s acc with - | Not_found -> 0 - in - String_map.add s (count + 1) acc) - String_map.empty - lst - module Sign = struct type t = | Pos @@ -33,17 +20,14 @@ let rec tails = function | [] -> [] | _ :: xs as lst -> lst :: tails xs -type t = string * int +type t = string * int * Sign.t let all_type_names name = name |> String.split_on_char '.' |> tails |> List.map (String.concat ".") let rec of_typ ~any_is_poly ~all_names ~prefix ~sgn = function - | Poly _ -> [ Sign.to_string sgn :: "POLY" :: prefix ] - | Any -> - if any_is_poly - then [ Sign.to_string sgn :: "POLY" :: prefix ] - else [ Sign.to_string sgn :: prefix ] + | Poly _ -> [ sgn, "POLY" :: prefix ] + | Any -> if any_is_poly then [ sgn, "POLY" :: prefix ] else [ sgn, prefix ] | Arrow (a, b) -> List.rev_append (of_typ ~any_is_poly ~all_names ~prefix ~sgn:(Sign.not sgn) a) @@ -52,10 +36,10 @@ let rec of_typ ~any_is_poly ~all_names ~prefix ~sgn = function name |> (if all_names then all_type_names else fun name -> [ name ]) |> List.map (fun name -> - let prefix = Sign.to_string sgn :: name :: prefix in + let prefix = name :: prefix in begin match args with - | [] -> [ prefix ] + | [] -> [ sgn, prefix ] | _ -> rev_concat @@ List.mapi @@ -69,8 +53,21 @@ let rec of_typ ~any_is_poly ~all_names ~prefix ~sgn = function rev_concat @@ List.map (of_typ ~any_is_poly ~all_names ~prefix ~sgn) @@ args | Unhandled -> [] +let regroup lst = + let h = Hashtbl.create 16 in + List.iter + (fun v -> + let count = + try Hashtbl.find h v with + | Not_found -> 0 + in + Hashtbl.replace h v (count + 1)) + lst ; + Hashtbl.to_seq h + let of_typ ~any_is_poly ~all_names t = t |> of_typ ~any_is_poly ~all_names ~prefix:[] ~sgn:Pos - |> List.map (String.concat "") + |> List.map (fun (polarity, path) -> polarity, String.concat " " path) |> regroup + |> Seq.map (fun ((polarity, path), count) -> path, count, polarity) diff --git a/db/type_polarity.mli b/db/type_polarity.mli index e22c005825..fcd4a3aa15 100644 --- a/db/type_polarity.mli +++ b/db/type_polarity.mli @@ -56,7 +56,7 @@ module Sign : sig val not : t -> t end -type t = string * int +type t = string * int * Sign.t (** The search database is a suffix tree structure, implemented in {!Suffix_tree}. It is a solely text-based datastructure. Therefore, we need a text represention for the polarities. @@ -71,7 +71,7 @@ type t = string * int The integer represents the occurences of the polarity, as explained in the toplevel documentation of the module. *) -val of_typ : any_is_poly:bool -> all_names:bool -> Typexpr.t -> t list +val of_typ : any_is_poly:bool -> all_names:bool -> Typexpr.t -> t Seq.t (** [of_typ ~ignore_any ~all_names typ] is the list of polarised types corresponding to [typ]. diff --git a/query/query.ml b/query/query.ml index fe3aa9fb13..dfde47590a 100644 --- a/query/query.ml +++ b/query/query.ml @@ -29,20 +29,24 @@ let collapse_trie t = Succ.(Tree.sets_tree ~union ~terminal:of_array_opt ~union_of_array t) let polarities typ = - List.filter - (fun (word, _count) -> String.length word > 0) - (Db.Type_polarity.of_typ ~any_is_poly:false ~all_names:false typ) + List.of_seq + @@ Seq.filter + (fun (word, _count, _) -> String.length word > 0) + (Db.Type_polarity.of_typ ~any_is_poly:false ~all_names:false typ) let find_types ~shards typ = let polarities = polarities typ in - if polarities = [] then failwith "Query.find_types : type with empty polarities" ; List.fold_left (fun acc shard -> - let db = Db.(shard.db_types) in let r = Succ.inter_of_list @@ List.map - (fun (name, count) -> + (fun (name, count, polarity) -> + let db = + match polarity with + | Db.Type_polarity.Sign.Pos -> shard.Db.db_pos_types + | Neg -> shard.Db.db_neg_types + in match Tree_occ.find db name with | Some trie -> collapse_trie_occ ~count trie | None -> Succ.empty) diff --git a/query/succ.ml b/query/succ.ml index 3a878a18c7..7e7c2a3939 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -145,7 +145,6 @@ let union_of_array arr = let union_of_list li = li |> Array.of_list |> union_of_array let print a { s; _ } = print_node a s -let inter_of_list li = - match li with +let inter_of_list = function + | [] -> empty | elt :: li -> List.fold_left inter elt li - | [] -> invalid_arg "Succ.inter_of_list []" diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 481adf4dd6..287ca5d11c 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -253,3 +253,57 @@ 410 val Base.Map.add_multi : ('k, 'v list, 'cmp) t -> key:'k -> data:'v -> ('k, 'v list, 'cmp) t 793 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list 797 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + +Partial name search: + $ sherlodoc search --print-cost "strin" + 381 mod Base.String + 381 mod Caml.String + 409 mod Base.Stringable + 418 val Base.String.rev : t -> t + 423 val Base.String.(^) : t -> t -> t + 423 mod Base.StringLabels + 423 sig Base.Stringable.S + 423 mod Caml.StringLabels + 427 val Base.String.hash : t -> int + 436 val Base.String.map : t -> f:(elt -> elt) -> t + 440 val Base.String.equal : t -> t -> bool + 444 val Base.String.append : t -> t -> t + 444 mod Base.String.Caseless + 444 mod Base.String.Escaping + 444 mod Shadow_stdlib.String + 445 val Base.String.init : int -> f:(int -> elt) -> t + 445 val Base.Exn.to_string : t -> string + 445 val Base.Sexp.of_string : unit + 445 mod Base.Bytes.To_string + 446 val Base.String.prefix : t -> int -> t + 446 val Base.String.suffix : t -> int -> t + 446 val Base.String.escaped : t -> t + 447 val Base.String.iter : t -> f:(elt -> unit) -> unit + 452 sig Base.Blit.S_to_string + 452 mod Base.Buffer.To_string + $ sherlodoc search --print-cost "tring" + 380 mod Base.String + 380 mod Caml.String + 411 mod Base.Stringable + 418 val Base.String.rev : t -> t + 423 val Base.String.(^) : t -> t -> t + 425 mod Base.StringLabels + 425 sig Base.Stringable.S + 425 mod Caml.StringLabels + 427 val Base.String.hash : t -> int + 436 val Base.String.map : t -> f:(elt -> elt) -> t + 440 val Base.String.equal : t -> t -> bool + 443 val Base.Exn.to_string : t -> string + 443 val Base.Sexp.of_string : unit + 443 mod Base.Bytes.To_string + 443 mod Shadow_stdlib.String + 444 val Base.String.append : t -> t -> t + 444 mod Base.String.Caseless + 444 mod Base.String.Escaping + 445 val Base.String.init : int -> f:(int -> elt) -> t + 446 val Base.String.prefix : t -> int -> t + 446 val Base.String.suffix : t -> int -> t + 446 val Base.String.escaped : t -> t + 447 val Base.String.iter : t -> f:(elt -> unit) -> unit + 450 sig Base.Blit.S_to_string + 450 mod Base.Buffer.To_string diff --git a/test/cram/base_web.t b/test/cram/base_web.t index e734c44d75..95dddae531 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -18,8 +18,8 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2600 db.js - 1960 db.js.gz + 2528 db.js + 1904 db.js.gz 1548 megaodocl.gz $ for f in $(find . -name '*.odocl'); do diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 22d2ac1302..0eec07b873 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -54,6 +54,7 @@ $ sherlodoc search ":_ -> moo" val Main.produce : unit -> moo val Main.produce_2' : unit -> unit -> moo + val Main.value : moo $ sherlodoc search ":moo -> _" val Main.consume : moo -> unit val Main.consume_2 : moo -> moo -> unit From 36989933c35dfc863bb29d12a6b84d68ee1c6f8f Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 3 Jan 2024 15:34:28 +0100 Subject: [PATCH 222/285] simplify type occurrences --- db/db.ml | 38 +++++++++++++++++--------- db/db.mli | 6 ++--- db/occ.ml | 29 -------------------- db/occ.mli | 63 -------------------------------------------- db/storage.ml | 6 +++-- db/suffix_tree.ml | 1 - db/suffix_tree.mli | 4 --- query/query.ml | 27 +++++++++---------- test/cram/base_web.t | 4 +-- 9 files changed, 47 insertions(+), 131 deletions(-) delete mode 100644 db/occ.ml delete mode 100644 db/occ.mli diff --git a/db/db.ml b/db/db.ml index 2c574731f1..90f740a7e4 100644 --- a/db/db.ml +++ b/db/db.ml @@ -1,43 +1,57 @@ module Entry = Entry module Suffix_tree = Suffix_tree -module Occ = Occ module Storage = Storage module Type_polarity = Type_polarity module Typexpr = Typexpr +module Occurences = Storage.Occurences type t = Storage.db = { db_names : Suffix_tree.With_elts.reader - ; db_pos_types : Suffix_tree.With_occ.reader - ; db_neg_types : Suffix_tree.With_occ.reader + ; db_pos_types : Suffix_tree.With_elts.reader Occurences.t + ; db_neg_types : Suffix_tree.With_elts.reader Occurences.t } type writer = { writer_names : Suffix_tree.With_elts.writer - ; writer_pos_types : Suffix_tree.With_occ.writer - ; writer_neg_types : Suffix_tree.With_occ.writer + ; buffer_types : Suffix_tree.Buf.t + ; mutable writer_pos_types : Suffix_tree.With_elts.writer Occurences.t + ; mutable writer_neg_types : Suffix_tree.With_elts.writer Occurences.t } let make () = let buffer_names = Suffix_tree.Buf.make () in let buffer_types = Suffix_tree.Buf.make () in { writer_names = Suffix_tree.With_elts.make buffer_names - ; writer_pos_types = Suffix_tree.With_occ.make buffer_types - ; writer_neg_types = Suffix_tree.With_occ.make buffer_types + ; buffer_types + ; writer_pos_types = Occurences.empty + ; writer_neg_types = Occurences.empty } let export db = { Storage.db_names = Suffix_tree.With_elts.export db.writer_names - ; db_pos_types = Suffix_tree.With_occ.export db.writer_pos_types - ; db_neg_types = Suffix_tree.With_occ.export db.writer_neg_types + ; db_pos_types = Occurences.map Suffix_tree.With_elts.export db.writer_pos_types + ; db_neg_types = Occurences.map Suffix_tree.With_elts.export db.writer_neg_types } let store db name elt ~count ~polarity = let st = match polarity with - | Type_polarity.Sign.Pos -> db.writer_pos_types - | Type_polarity.Sign.Neg -> db.writer_neg_types + | Type_polarity.Sign.Pos -> begin + try Occurences.find count db.writer_pos_types with + | Not_found -> + let st = Suffix_tree.With_elts.make db.buffer_types in + db.writer_pos_types <- Occurences.add count st db.writer_pos_types ; + st + end + | Type_polarity.Sign.Neg -> begin + try Occurences.find count db.writer_neg_types with + | Not_found -> + let st = Suffix_tree.With_elts.make db.buffer_types in + db.writer_neg_types <- Occurences.add count st db.writer_neg_types ; + st + end in - Suffix_tree.With_occ.add_suffixes st name (count, elt) + Suffix_tree.With_elts.add_suffixes st name elt let store_type_polarities db elt polarities = Seq.iter (fun (path, count, polarity) -> store db ~count ~polarity path elt) polarities diff --git a/db/db.mli b/db/db.mli index 239ff3ce85..db7ae3095e 100644 --- a/db/db.mli +++ b/db/db.mli @@ -1,14 +1,14 @@ module Entry = Entry module Storage = Storage module Suffix_tree = Suffix_tree -module Occ = Occ module Type_polarity = Type_polarity module Typexpr = Typexpr +module Occurences = Storage.Occurences type t = Storage.db = { db_names : Suffix_tree.With_elts.reader - ; db_pos_types : Suffix_tree.With_occ.reader - ; db_neg_types : Suffix_tree.With_occ.reader + ; db_pos_types : Suffix_tree.With_elts.reader Occurences.t + ; db_neg_types : Suffix_tree.With_elts.reader Occurences.t } (** The type of a search database. diff --git a/db/occ.ml b/db/occ.ml deleted file mode 100644 index 9d657cc347..0000000000 --- a/db/occ.ml +++ /dev/null @@ -1,29 +0,0 @@ -module Int_map = Map.Make (Int) - -type t = Entry.t array Int_map.t -type elt = int * Entry.t - -let find = Int_map.find_opt -let fold = Int_map.fold -let is_empty = Int_map.is_empty -let equal_elt (a_count, a) (b_count, b) = a_count = b_count && Entry.equal a b - -(* - let of_list li = - List.fold_left - (fun acc (count, elt) -> - let elts = try Int_map.find count acc with Not_found -> [] in - Int_map.add count (elt :: elts) acc) - Int_map.empty li - |> Int_map.map Entry.Array.of_list -*) - -let of_list li = - List.fold_left - (fun acc (count, elt) -> - match Int_map.find_opt count acc with - | None -> Int_map.add count (Entry.Set.singleton elt) acc - | Some set -> Int_map.add count (Entry.Set.add elt set) acc) - Int_map.empty - li - |> Int_map.map (fun set -> set |> Entry.Set.to_seq |> Array.of_seq) diff --git a/db/occ.mli b/db/occ.mli deleted file mode 100644 index 512f1b6e32..0000000000 --- a/db/occ.mli +++ /dev/null @@ -1,63 +0,0 @@ -(** [Occ] stands for occurences. It associate sets of elements to the number of - time members of the set occurs. - - The list [[a, a, b, b, c]] would correspond to [[(2, [a; b]); (1, [c]) ]]. It is - used or type search : you want to be able to return every function that takes - two ints as an argument. Without this datastrucure, we would only be able to - search for functions that take ints, without specifying the amount. - - This datastructure is used at the leafs of the suffix tree : so when doing type - search, we first perform a type search ignoring occurences, and afterwards - filter the results according to them. - - I will give an example bellow, it is probably better to read {!Type_polarities} - first to understand it completely. - - If you have the following entries : - - {[ - val a : string -> int - val b : string -> string -> int - val c : string -> string -> int * int - val d : string * string -> float -> int * int - ]} - - Their polarities will be : - - {[ - val a : {(-string, 1); (+int, 1)} - val b : {(-string, 2); (+int, 1)} - val c : {(-string, 2); (+int, 2)} - val d : {(-string, 2); (+int, 2); (-float, 1)} - ]} - - We can combine them into a database that will look like this : - - {[ - +int -> - { 1 -> {a; b} - 2 -> {c; d} - } - -string -> - { 1 -> {a} - 2 -> {b; c; d} - } - -float -> - { 1 -> {d} - } - ]} - - If there is a query for type [string -> string -> (int * int)], the polarities - of the query are [(-string, 2)], [(+int, 2)]. - - The entries of [(-string, 2)] are [{b; c; d}], and the entries of [(+int, 2)] - are [{c; d}]. The intersection of the two is [{c; d}]. *) - -type t -type elt = int * Entry.t - -val find : int -> t -> Entry.t array option -val fold : (int -> Entry.t array -> 'a -> 'a) -> t -> 'a -> 'a -val is_empty : t -> bool -val equal_elt : elt -> elt -> bool -val of_list : elt list -> t diff --git a/db/storage.ml b/db/storage.ml index 0b1315e37d..633496ea34 100644 --- a/db/storage.ml +++ b/db/storage.ml @@ -1,7 +1,9 @@ +module Occurences = Map.Make (Int) + type db = { db_names : Suffix_tree.With_elts.reader - ; db_pos_types : Suffix_tree.With_occ.reader - ; db_neg_types : Suffix_tree.With_occ.reader + ; db_pos_types : Suffix_tree.With_elts.reader Occurences.t + ; db_neg_types : Suffix_tree.With_elts.reader Occurences.t } module type S = sig diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index f89e4d8b38..85952bf303 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -461,4 +461,3 @@ module Make (S : SET) = struct end module With_elts = Make (Entry.Array) -module With_occ = Make (Occ) diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index 5dfaf721b2..019aec05fe 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -46,7 +46,3 @@ end module With_elts : module type of Make (Entry.Array) (** [With_elts] is a suffix tree with array of entries at the leafs. It is used for the text-based part of the database. *) - -module With_occ : module type of Make (Occ) -(** [With_occ] is a suffix tree with occurence annotated arrays of entries at - the leafs. It is used for the type-based part of the database. *) diff --git a/query/query.ml b/query/query.ml index dfde47590a..a090274499 100644 --- a/query/query.ml +++ b/query/query.ml @@ -2,8 +2,6 @@ module Parser = Query_parser module Dynamic_cost = Dynamic_cost module Storage = Db.Storage module Tree = Db.Suffix_tree.With_elts -module Tree_occ = Db.Suffix_tree.With_occ -module Occ = Db.Occ module Private = struct module Array_succ = Array_succ @@ -16,15 +14,6 @@ module Private = struct end end -let collapse_occ ~count occs = - Occ.fold - (fun k x acc -> if k < count then acc else Succ.union (Succ.of_array x) acc) - occs - Succ.empty - -let collapse_trie_occ ~count t = - Succ.(Tree_occ.sets_tree ~union ~terminal:(collapse_occ ~count) ~union_of_array t) - let collapse_trie t = Succ.(Tree.sets_tree ~union ~terminal:of_array_opt ~union_of_array t) @@ -42,14 +31,22 @@ let find_types ~shards typ = Succ.inter_of_list @@ List.map (fun (name, count, polarity) -> - let db = + let st_occ = match polarity with | Db.Type_polarity.Sign.Pos -> shard.Db.db_pos_types | Neg -> shard.Db.db_neg_types in - match Tree_occ.find db name with - | Some trie -> collapse_trie_occ ~count trie - | None -> Succ.empty) + Db.Occurences.fold + (fun occurrences st acc -> + if occurrences < count + then acc + else begin + match Tree.find st name with + | Some trie -> Succ.union acc (collapse_trie trie) + | None -> acc + end) + st_occ + Succ.empty) polarities in Succ.union acc r) diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 95dddae531..b0dc025472 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -18,8 +18,8 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2528 db.js - 1904 db.js.gz + 2520 db.js + 1900 db.js.gz 1548 megaodocl.gz $ for f in $(find . -name '*.odocl'); do From 91c2b0454ec4fbd268fc2d0a57b6a7e9f3c51b40 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Mon, 8 Jan 2024 18:51:10 +0100 Subject: [PATCH 223/285] sort suffix trie children --- db/entry.ml | 20 +++++++++++++++----- db/entry.mli | 5 +++-- db/suffix_tree.ml | 26 ++++++++++++++++++++++---- db/suffix_tree.mli | 8 ++------ 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/db/entry.ml b/db/entry.ml index 406b178093..0109825771 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -53,14 +53,19 @@ module T = struct ; is_from_module_type : bool } + let string_compare_shorter a b = + match Int.compare (String.length a) (String.length b) with + | 0 -> String.compare a b + | c -> c + let structural_compare a b = - match Int.compare (String.length a.name) (String.length b.name) with + match string_compare_shorter a.name b.name with | 0 -> begin - match String.compare a.name b.name with + match Package.compare a.pkg b.pkg with | 0 -> begin - match Package.compare a.pkg b.pkg with + match Stdlib.compare a.kind b.kind with | 0 -> begin - match Stdlib.compare a.kind b.kind with + match string_compare_shorter a.doc_html b.doc_html with | 0 -> String.compare a.url b.url | c -> c end @@ -98,12 +103,17 @@ module Array = struct let empty = None + let minimum = function + | None -> None + | Some arr -> Some arr.(0) + let of_list arr = let arr = Array.of_list arr in Array.sort compare arr ; if Array.length arr = 0 then empty else Some arr - let equal_elt = equal + let equal_elt = T.equal + let compare_elt = T.compare end let link t = diff --git a/db/entry.mli b/db/entry.mli index 7e107574d3..1529d49d7d 100644 --- a/db/entry.mli +++ b/db/entry.mli @@ -61,8 +61,9 @@ module Array : sig type elt = t type t = elt array option - val empty : t - val is_empty : t -> bool val of_list : elt list -> t + val is_empty : t -> bool + val minimum : t -> elt option val equal_elt : elt -> elt -> bool + val compare_elt : elt -> elt -> int end diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index 85952bf303..14253d89b9 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -4,7 +4,9 @@ module type SET = sig val of_list : elt list -> t val is_empty : t -> bool + val minimum : t -> elt option val equal_elt : elt -> elt -> bool + val compare_elt : elt -> elt -> int end module Doc = struct @@ -429,23 +431,39 @@ module Make (S : SET) = struct let children = Char_map.bindings @@ Char_map.map (export ~cache ~cache_term) node.children in - let children_uids = List.map (fun (chr, (uid, _)) -> chr, uid) children in + let children = + List.sort + (fun (a_chr, (_, _, a)) (b_chr, (_, _, b)) -> + match S.compare_elt a b with + | 0 -> Char.compare a_chr b_chr + | c -> c) + children + in + let min_terminal = S.minimum terminals in + let min_child = + match min_terminal, children with + | Some a, (_, (_, _, b)) :: _ -> if S.compare_elt a b <= 0 then a else b + | Some a, [] -> a + | None, (_, (_, _, b)) :: _ -> b + | None, [] -> assert false + in + let children_uids = List.map (fun (chr, (uid, _, _)) -> chr, uid) children in let key = node.start, node.len, terminals_uid, children_uids in try Hashtbl.find cache key with | Not_found -> let children = - Array.of_list @@ List.map (fun (_, (_, child)) -> child) children + Array.of_list @@ List.map (fun (_, (_, child, _)) -> child) children in let children = if Array.length children = 0 then None else Some children in let node = { T.start = node.start; len = node.len; terminals; children } in - let result = Uid.make (), node in + let result = Uid.make (), node, min_child in Hashtbl.add cache key result ; result let clear ~str t = let cache = Hashtbl.create 16 in let cache_term = Terminals.Hashtbl.create 16 in - let _, t = export ~cache ~cache_term t in + let _, t, _ = export ~cache ~cache_term t in { T.str; t } end diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index 019aec05fe..2f131e534b 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -1,16 +1,12 @@ -(** The suffix tree datastructure. This datastructure allows to efficiently - search for strings suffixes. - - You need to provide a datastructure for the sets of elements at the leafs of the - tree. *) - module type SET = sig type t type elt val of_list : elt list -> t val is_empty : t -> bool + val minimum : t -> elt option val equal_elt : elt -> elt -> bool + val compare_elt : elt -> elt -> int end module Buf : sig From 62e529a5805651519a4194b36aac83e0e33c37c0 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 9 Jan 2024 15:24:31 +0100 Subject: [PATCH 224/285] remove functor from suffix tree and split construction/usage --- db/db.ml | 30 +- db/db.mli | 8 +- db/storage.ml | 6 +- db/string_automata.ml | 73 +++++ db/string_automata.mli | 23 ++ db/suffix_tree.ml | 647 +++++++++++++++++------------------------ db/suffix_tree.mli | 41 +-- query/query.ml | 2 +- 8 files changed, 384 insertions(+), 446 deletions(-) create mode 100644 db/string_automata.ml create mode 100644 db/string_automata.mli diff --git a/db/db.ml b/db/db.ml index 90f740a7e4..adacff387c 100644 --- a/db/db.ml +++ b/db/db.ml @@ -1,36 +1,36 @@ module Entry = Entry -module Suffix_tree = Suffix_tree module Storage = Storage module Type_polarity = Type_polarity module Typexpr = Typexpr module Occurences = Storage.Occurences +module String_automata = String_automata type t = Storage.db = - { db_names : Suffix_tree.With_elts.reader - ; db_pos_types : Suffix_tree.With_elts.reader Occurences.t - ; db_neg_types : Suffix_tree.With_elts.reader Occurences.t + { db_names : String_automata.t + ; db_pos_types : String_automata.t Occurences.t + ; db_neg_types : String_automata.t Occurences.t } type writer = - { writer_names : Suffix_tree.With_elts.writer + { writer_names : Suffix_tree.t ; buffer_types : Suffix_tree.Buf.t - ; mutable writer_pos_types : Suffix_tree.With_elts.writer Occurences.t - ; mutable writer_neg_types : Suffix_tree.With_elts.writer Occurences.t + ; mutable writer_pos_types : Suffix_tree.t Occurences.t + ; mutable writer_neg_types : Suffix_tree.t Occurences.t } let make () = let buffer_names = Suffix_tree.Buf.make () in let buffer_types = Suffix_tree.Buf.make () in - { writer_names = Suffix_tree.With_elts.make buffer_names + { writer_names = Suffix_tree.make buffer_names ; buffer_types ; writer_pos_types = Occurences.empty ; writer_neg_types = Occurences.empty } let export db = - { Storage.db_names = Suffix_tree.With_elts.export db.writer_names - ; db_pos_types = Occurences.map Suffix_tree.With_elts.export db.writer_pos_types - ; db_neg_types = Occurences.map Suffix_tree.With_elts.export db.writer_neg_types + { Storage.db_names = Suffix_tree.export db.writer_names + ; db_pos_types = Occurences.map Suffix_tree.export db.writer_pos_types + ; db_neg_types = Occurences.map Suffix_tree.export db.writer_neg_types } let store db name elt ~count ~polarity = @@ -39,21 +39,21 @@ let store db name elt ~count ~polarity = | Type_polarity.Sign.Pos -> begin try Occurences.find count db.writer_pos_types with | Not_found -> - let st = Suffix_tree.With_elts.make db.buffer_types in + let st = Suffix_tree.make db.buffer_types in db.writer_pos_types <- Occurences.add count st db.writer_pos_types ; st end | Type_polarity.Sign.Neg -> begin try Occurences.find count db.writer_neg_types with | Not_found -> - let st = Suffix_tree.With_elts.make db.buffer_types in + let st = Suffix_tree.make db.buffer_types in db.writer_neg_types <- Occurences.add count st db.writer_neg_types ; st end in - Suffix_tree.With_elts.add_suffixes st name elt + Suffix_tree.add_suffixes st name elt let store_type_polarities db elt polarities = Seq.iter (fun (path, count, polarity) -> store db ~count ~polarity path elt) polarities -let store_word db word elt = Suffix_tree.With_elts.add_suffixes db.writer_names word elt +let store_word db word elt = Suffix_tree.add_suffixes db.writer_names word elt diff --git a/db/db.mli b/db/db.mli index db7ae3095e..9c2e8df1e8 100644 --- a/db/db.mli +++ b/db/db.mli @@ -1,14 +1,14 @@ module Entry = Entry module Storage = Storage -module Suffix_tree = Suffix_tree module Type_polarity = Type_polarity module Typexpr = Typexpr module Occurences = Storage.Occurences +module String_automata = String_automata type t = Storage.db = - { db_names : Suffix_tree.With_elts.reader - ; db_pos_types : Suffix_tree.With_elts.reader Occurences.t - ; db_neg_types : Suffix_tree.With_elts.reader Occurences.t + { db_names : String_automata.t + ; db_pos_types : String_automata.t Occurences.t + ; db_neg_types : String_automata.t Occurences.t } (** The type of a search database. diff --git a/db/storage.ml b/db/storage.ml index 633496ea34..24a91f6b8f 100644 --- a/db/storage.ml +++ b/db/storage.ml @@ -1,9 +1,9 @@ module Occurences = Map.Make (Int) type db = - { db_names : Suffix_tree.With_elts.reader - ; db_pos_types : Suffix_tree.With_elts.reader Occurences.t - ; db_neg_types : Suffix_tree.With_elts.reader Occurences.t + { db_names : String_automata.t + ; db_pos_types : String_automata.t Occurences.t + ; db_neg_types : String_automata.t Occurences.t } module type S = sig diff --git a/db/string_automata.ml b/db/string_automata.ml new file mode 100644 index 0000000000..73149bfd2d --- /dev/null +++ b/db/string_automata.ml @@ -0,0 +1,73 @@ +type node = + { start : int + ; len : int + ; terminals : Entry.Array.t + ; children : node array option + } + +type t = + { str : string + ; t : node + } + +let array_find ~str chr arr = + let rec go i = + if i >= Array.length arr + then raise Not_found + else ( + let node = arr.(i) in + if chr = str.[node.start - 1] then node else go (i + 1)) + in + go 0 + +let array_find ~str chr = function + | None -> raise Not_found + | Some arr -> array_find ~str chr arr + +let lcp i_str i j_str j j_len = + let j_stop = j + j_len in + let rec go_lcp i j = + if i >= String.length i_str || j >= j_stop + then i + else ( + let i_chr, j_chr = i_str.[i], j_str.[j] in + if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1)) + in + let i' = go_lcp i j in + i' - i + +let rec find ~str node pattern i = + if i >= String.length pattern + then node + else ( + let chr = pattern.[i] in + let child = array_find ~str chr node.children in + find_lcp ~str child pattern (i + 1)) + +and find_lcp ~str child pattern i = + let n = lcp pattern i str child.start child.len in + if i + n = String.length pattern + then { child with start = child.start + n } + else if n = child.len + then find ~str child pattern (i + n) + else raise Not_found + +let find t pattern = + let child = find ~str:t.str t.t pattern 0 in + { str = t.str; t = child } + +let find t pattern = + try Some (find t pattern) with + | Not_found -> None + +let rec sets_tree ~union ~terminal ~union_of_array t = + let ts = terminal t.terminals in + let cs = + match t.children with + | None -> [||] + | Some children -> Array.map (sets_tree ~union ~terminal ~union_of_array) children + in + union ts (union_of_array cs) + +let sets_tree ~union ~terminal ~union_of_array t = + sets_tree ~union ~terminal ~union_of_array t.t diff --git a/db/string_automata.mli b/db/string_automata.mli new file mode 100644 index 0000000000..1e29b6315f --- /dev/null +++ b/db/string_automata.mli @@ -0,0 +1,23 @@ +(* A string automata, constructed from a suffix tree and optimized + for fast queries and small serialization. *) + +type node = + { start : int + ; len : int + ; terminals : Entry.Array.t + ; children : node array option + } + +type t = + { str : string + ; t : node + } + +val find : t -> string -> t option + +val sets_tree + : union:('a -> 'a -> 'a) + -> terminal:(Entry.Array.t -> 'a) + -> union_of_array:('a array -> 'a) + -> t + -> 'a diff --git a/db/suffix_tree.ml b/db/suffix_tree.ml index 14253d89b9..b8eae934dd 100644 --- a/db/suffix_tree.ml +++ b/db/suffix_tree.ml @@ -1,14 +1,3 @@ -module type SET = sig - type t - type elt - - val of_list : elt list -> t - val is_empty : t -> bool - val minimum : t -> elt option - val equal_elt : elt -> elt -> bool - val compare_elt : elt -> elt -> int -end - module Doc = struct type 'a t = { uid : 'a @@ -26,8 +15,7 @@ module Doc = struct end module Buf = struct - (** This module allows to construct a big string such that if you add the same - string twice, the second addition is not performed. *) + (* Cache small strings as slices in one bigstring. *) module String_hashtbl = Hashtbl.Make (struct type t = string @@ -73,409 +61,296 @@ module Buf = struct start end -module Make (S : SET) = struct - (** Terminals is the temporary storage for the payload of the leafs. It is - converted into [S.t] after the suffix tree is built. *) - module Terminals = struct - type t = S.elt list - - let empty = [] - let singleton x = [ x ] - - let add ~hint x xs = - match hint with - | Some (prev_xs, xxs) when prev_xs == xs -> xxs - | _ -> x :: xs +module Terminals = struct + type t = Entry.t list - let hash = Hashtbl.hash - let equal = List.equal S.equal_elt + let empty = [] + let singleton x = [ x ] - let mem (x : S.elt) = function - | y :: _ -> S.equal_elt x y - | _ -> false + let add ~hint x xs = + match hint with + | Some (prev_xs, xxs) when prev_xs == xs -> xxs + | _ -> x :: xs - module Hashtbl = Hashtbl.Make (struct - type nonrec t = t + let hash = Hashtbl.hash + let equal = List.equal Entry.equal - let hash = hash - let equal = equal - end) - end - - module Char_map = Map.Make (Char) - - type node = - { mutable start : int - ; mutable len : int - ; mutable suffix_link : node option - ; mutable terminals : Terminals.t - ; mutable children : node Char_map.t - } - - type writer = - { buffer : Buf.t - ; root : node - } - - let make_root () = - { start = 0 - ; len = 0 - ; suffix_link = None - ; terminals = Terminals.empty - ; children = Char_map.empty - } + let mem x = function + | y :: _ -> Entry.equal x y + | _ -> false +end - let make buffer = { root = make_root (); buffer } - - let split_at ~str node len = - let split_chr = Buf.get str (node.start + len) in - let new_node = - { start = node.start - ; len - ; suffix_link = None - ; terminals = Terminals.empty - ; children = Char_map.singleton split_chr node - } - in - node.start <- node.start + len + 1 ; - node.len <- node.len - 1 - len ; - new_node - - let lcp i_str i j_str j j_len = - let j_stop = j + j_len in - let rec go_lcp i j = - if i >= String.length i_str || j >= j_stop - then i - else ( - let i_chr, j_chr = i_str.[i], Buf.get j_str j in - if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1)) - in - let i' = go_lcp i j in - i' - i - - let make_leaf ~prev_leaf ~buffer ~doc str_start = - let start = - match prev_leaf with - | None -> - let substr = Doc.sub doc (str_start - 1) in - let start = Buf.add buffer substr in - start + 1 - | Some (prev_leaf, _depth, _) -> - let doc_len = Doc.length doc in - prev_leaf.start + prev_leaf.len - (doc_len - str_start) + 1 - in - let len = Doc.length doc - str_start - 1 in - assert (start > 0) ; - { start +module Char_map = Map.Make (Char) + +type node = + { mutable start : int + ; mutable len : int + ; mutable suffix_link : node option + ; mutable terminals : Terminals.t + ; mutable children : node Char_map.t + } + +type t = + { buffer : Buf.t + ; root : node + } + +let make_root () = + { start = 0 + ; len = 0 + ; suffix_link = None + ; terminals = Terminals.empty + ; children = Char_map.empty + } + +let make buffer = { root = make_root (); buffer } + +let split_at ~str node len = + let split_chr = Buf.get str (node.start + len) in + let new_node = + { start = node.start ; len ; suffix_link = None - ; terminals = Terminals.singleton doc.Doc.uid - ; children = Char_map.empty + ; terminals = Terminals.empty + ; children = Char_map.singleton split_chr node } - - let set_suffix_link ~prev ~depth node = - match prev with - | Some (prev, prev_depth) when depth = prev_depth -> + in + node.start <- node.start + len + 1 ; + node.len <- node.len - 1 - len ; + new_node + +let lcp i_str i j_str j j_len = + let j_stop = j + j_len in + let rec go_lcp i j = + if i >= String.length i_str || j >= j_stop + then i + else ( + let i_chr, j_chr = i_str.[i], Buf.get j_str j in + if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1)) + in + let i' = go_lcp i j in + i' - i + +let make_leaf ~prev_leaf ~buffer ~doc str_start = + let start = + match prev_leaf with + | None -> + let substr = Doc.sub doc (str_start - 1) in + let start = Buf.add buffer substr in + start + 1 + | Some (prev_leaf, _depth, _) -> + let doc_len = Doc.length doc in + prev_leaf.start + prev_leaf.len - (doc_len - str_start) + 1 + in + let len = Doc.length doc - str_start - 1 in + assert (start > 0) ; + { start + ; len + ; suffix_link = None + ; terminals = Terminals.singleton doc.Doc.uid + ; children = Char_map.empty + } + +let set_suffix_link ~prev ~depth node = + match prev with + | Some (prev, prev_depth) when depth = prev_depth -> + begin + match prev.suffix_link with + | None -> prev.suffix_link <- Some node + | Some node' -> assert (node == node') + end ; + None + | _ -> prev + +let add_document trie doc = + let root = trie.root in + let set_leaf ?debug:_ ~prev_leaf ~depth node = + if node == root + then None + else begin begin - match prev.suffix_link with - | None -> prev.suffix_link <- Some node - | Some node' -> assert (node == node') - end ; - None - | _ -> prev - - let add_document trie doc = - let root = trie.root in - let set_leaf ?debug:_ ~prev_leaf ~depth node = - if node == root - then None - else begin - begin - match prev_leaf with - | None -> () - | Some (prev_leaf, prev_depth, _) -> - assert (prev_depth = depth) ; - begin - match prev_leaf.suffix_link with - | None -> prev_leaf.suffix_link <- Some node - | Some node' -> assert (node' == node) - end - end ; - Some (node, depth - 1) - end - in - let rec go ~prev ~prev_leaf ~depth node i = - let prev = set_suffix_link ~prev ~depth node in - if i >= Doc.length doc - then assert (depth = 0) - else ( - let chr = Doc.get doc i in - let i, depth = i + 1, depth + 1 in - match chr with - | Terminal doc_uid -> - if not (Terminals.mem doc_uid node.terminals) - then begin - let hint = - Option.map - (fun (t, _, prev_terminals) -> prev_terminals, t.terminals) - prev_leaf - in - let prev_terminals = node.terminals in - node.terminals <- Terminals.add ~hint doc_uid node.terminals ; - let prev_leaf = - match set_leaf ~debug:"0" ~prev_leaf ~depth node with - | None -> None - | Some (t, depth) -> Some (t, depth, prev_terminals) - in - follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i + match prev_leaf with + | None -> () + | Some (prev_leaf, prev_depth, _) -> + assert (prev_depth = depth) ; + begin + match prev_leaf.suffix_link with + | None -> prev_leaf.suffix_link <- Some node + | Some node' -> assert (node' == node) end - | Char chr -> begin - match Char_map.find chr node.children with - | child -> - assert (depth >= 0) ; - assert (i - depth >= 0) ; - assert (i < Doc.length doc) ; - let len = lcp doc.Doc.text i trie.buffer child.start child.len in - let i, depth = i + len, depth + len in - assert (i < Doc.length doc) ; - if len = child.len - then - if not (Char_map.is_empty child.children) - then go ~prev ~prev_leaf ~depth child i - else add_leaf ~prev_leaf ~node ~child ~depth ~i ~len - else begin - let new_child = split_at ~str:trie.buffer child len in - node.children <- Char_map.add chr new_child node.children ; - let prev = set_suffix_link ~prev ~depth new_child in - assert (prev = None) ; - add_leaf ~prev_leaf ~node ~child:new_child ~depth ~i ~len - end - | exception Not_found -> - let new_leaf = make_leaf ~prev_leaf ~buffer:trie.buffer ~doc i in - node.children <- Char_map.add chr new_leaf node.children ; - let prev_leaf = - set_leaf ~debug:"1" ~prev_leaf ~depth:(depth + Doc.length doc - i) new_leaf - in - let prev_leaf = - match prev_leaf with - | None -> None - | Some (t, depth) -> Some (t, depth, Terminals.empty) - in - follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i - end) - and add_leaf ~prev_leaf ~node ~child ~depth ~i ~len = - match Doc.get doc i with + end ; + Some (node, depth - 1) + end + in + let rec go ~prev ~prev_leaf ~depth node i = + let prev = set_suffix_link ~prev ~depth node in + if i >= Doc.length doc + then assert (depth = 0) + else ( + let chr = Doc.get doc i in + let i, depth = i + 1, depth + 1 in + match chr with | Terminal doc_uid -> - if not (Terminals.mem doc_uid child.terminals) + if not (Terminals.mem doc_uid node.terminals) then begin let hint = Option.map (fun (t, _, prev_terminals) -> prev_terminals, t.terminals) prev_leaf in - let prev_terminals = child.terminals in - child.terminals <- Terminals.add ~hint doc_uid child.terminals ; + let prev_terminals = node.terminals in + node.terminals <- Terminals.add ~hint doc_uid node.terminals ; let prev_leaf = - match set_leaf ~debug:"2" ~prev_leaf ~depth:(depth + 1) child with + match set_leaf ~debug:"0" ~prev_leaf ~depth node with | None -> None | Some (t, depth) -> Some (t, depth, prev_terminals) in - assert (Doc.length doc - i = 1) ; - begin - match child.suffix_link with - | None -> - let i, depth = i - len, depth - len in - follow_suffix ~prev:None ~prev_leaf ~parent:node ~depth ~i - | Some next_child -> - let depth = depth - 1 in - go ~prev:None ~prev_leaf:None ~depth next_child i - end + follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i end - | Char new_chr -> - let new_leaf = make_leaf ~prev_leaf ~buffer:trie.buffer ~doc (i + 1) in - let prev_leaf = - set_leaf ~debug:"3" ~prev_leaf ~depth:(depth + Doc.length doc - i) new_leaf + | Char chr -> begin + match Char_map.find chr node.children with + | child -> + assert (depth >= 0) ; + assert (i - depth >= 0) ; + assert (i < Doc.length doc) ; + let len = lcp doc.Doc.text i trie.buffer child.start child.len in + let i, depth = i + len, depth + len in + assert (i < Doc.length doc) ; + if len = child.len + then + if not (Char_map.is_empty child.children) + then go ~prev ~prev_leaf ~depth child i + else add_leaf ~prev_leaf ~node ~child ~depth ~i ~len + else begin + let new_child = split_at ~str:trie.buffer child len in + node.children <- Char_map.add chr new_child node.children ; + let prev = set_suffix_link ~prev ~depth new_child in + assert (prev = None) ; + add_leaf ~prev_leaf ~node ~child:new_child ~depth ~i ~len + end + | exception Not_found -> + let new_leaf = make_leaf ~prev_leaf ~buffer:trie.buffer ~doc i in + node.children <- Char_map.add chr new_leaf node.children ; + let prev_leaf = + set_leaf ~debug:"1" ~prev_leaf ~depth:(depth + Doc.length doc - i) new_leaf + in + let prev_leaf = + match prev_leaf with + | None -> None + | Some (t, depth) -> Some (t, depth, Terminals.empty) + in + follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i + end) + and add_leaf ~prev_leaf ~node ~child ~depth ~i ~len = + match Doc.get doc i with + | Terminal doc_uid -> + if not (Terminals.mem doc_uid child.terminals) + then begin + let hint = + Option.map (fun (t, _, prev_terminals) -> prev_terminals, t.terminals) prev_leaf in + let prev_terminals = child.terminals in + child.terminals <- Terminals.add ~hint doc_uid child.terminals ; let prev_leaf = - match prev_leaf with + match set_leaf ~debug:"2" ~prev_leaf ~depth:(depth + 1) child with | None -> None - | Some (t, depth) -> Some (t, depth, Terminals.empty) + | Some (t, depth) -> Some (t, depth, prev_terminals) in - child.children <- Char_map.add new_chr new_leaf child.children ; - let prev = Some (child, depth - 1) in - let i, depth = i - len, depth - len in - follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i - and follow_suffix ~prev ~prev_leaf ~parent ~depth ~i = - match parent.suffix_link with - | None -> begin - let i = i - depth + 1 in - go ~prev:None ~prev_leaf ~depth:0 root i + assert (Doc.length doc - i = 1) ; + begin + match child.suffix_link with + | None -> + let i, depth = i - len, depth - len in + follow_suffix ~prev:None ~prev_leaf ~parent:node ~depth ~i + | Some next_child -> + let depth = depth - 1 in + go ~prev:None ~prev_leaf:None ~depth next_child i + end end - | Some next -> - assert (depth >= 2) ; - assert (next != root) ; - go ~prev ~prev_leaf ~depth:(depth - 2) next (i - 1) - in - go ~prev:None ~prev_leaf:None ~depth:0 root 0 - - let add_suffixes t text elt = add_document t { Doc.text; uid = elt } - - module Automata = struct - (** Automata is the most compact version that uses arrays for branching. It - is not practical to use it for constructing a suffix tree, but it is - better for serialiazing. *) - - module Uid = struct - let gen = ref 0 - - let make () = - let u = !gen in - gen := u + 1 ; - u + | Char new_chr -> + let new_leaf = make_leaf ~prev_leaf ~buffer:trie.buffer ~doc (i + 1) in + let prev_leaf = + set_leaf ~debug:"3" ~prev_leaf ~depth:(depth + Doc.length doc - i) new_leaf + in + let prev_leaf = + match prev_leaf with + | None -> None + | Some (t, depth) -> Some (t, depth, Terminals.empty) + in + child.children <- Char_map.add new_chr new_leaf child.children ; + let prev = Some (child, depth - 1) in + let i, depth = i - len, depth - len in + follow_suffix ~prev ~prev_leaf ~parent:node ~depth ~i + and follow_suffix ~prev ~prev_leaf ~parent ~depth ~i = + match parent.suffix_link with + | None -> begin + let i = i - depth + 1 in + go ~prev:None ~prev_leaf ~depth:0 root i end + | Some next -> + assert (depth >= 2) ; + assert (next != root) ; + go ~prev ~prev_leaf ~depth:(depth - 2) next (i - 1) + in + go ~prev:None ~prev_leaf:None ~depth:0 root 0 - module T = struct - type node = - { start : int - ; len : int - ; terminals : S.t - ; children : node array option - } - - type t = - { str : string - ; t : node - } - - let array_find ~str chr arr = - let rec go i = - if i >= Array.length arr - then raise Not_found - else ( - let node = arr.(i) in - if chr = str.[node.start - 1] then node else go (i + 1)) - in - go 0 - - let array_find ~str chr = function - | None -> raise Not_found - | Some arr -> array_find ~str chr arr - - let lcp i_str i j_str j j_len = - let j_stop = j + j_len in - let rec go_lcp i j = - if i >= String.length i_str || j >= j_stop - then i - else ( - let i_chr, j_chr = i_str.[i], j_str.[j] in - if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1)) - in - let i' = go_lcp i j in - i' - i - - let rec find ~str node pattern i = - if i >= String.length pattern - then node - else ( - let chr = pattern.[i] in - let child = array_find ~str chr node.children in - find_lcp ~str child pattern (i + 1)) - - and find_lcp ~str child pattern i = - let n = lcp pattern i str child.start child.len in - if i + n = String.length pattern - then { child with start = child.start + n } - else if n = child.len - then find ~str child pattern (i + n) - else raise Not_found - - let find t pattern = - let child = find ~str:t.str t.t pattern 0 in - { str = t.str; t = child } - - let find t pattern = - try Some (find t pattern) with - | Not_found -> None - - let rec collapse acc t = - let acc = if S.is_empty t.terminals then acc else t.terminals :: acc in - match t.children with - | None -> acc - | Some children -> Array.fold_left collapse acc children - - let collapse t = collapse [] t.t - - let rec sets_tree ~union ~terminal ~union_of_array t = - let ts = terminal t.terminals in - let cs = - match t.children with - | None -> [||] - | Some children -> - Array.map (sets_tree ~union ~terminal ~union_of_array) children - in - union ts (union_of_array cs) +let add_suffixes t text elt = add_document t { Doc.text; uid = elt } - let sets_tree ~union ~terminal ~union_of_array t = - sets_tree ~union ~terminal ~union_of_array t.t - end +module Uid = struct + let gen = ref 0 - let export_terminals ~cache_term ts = - try Terminals.Hashtbl.find cache_term ts with - | Not_found -> - let result = Uid.make (), S.of_list ts in - Terminals.Hashtbl.add cache_term ts result ; - result - - let rec export ~cache ~cache_term node = - let terminals_uid, terminals = export_terminals ~cache_term node.terminals in - let children = - Char_map.bindings @@ Char_map.map (export ~cache ~cache_term) node.children - in - let children = - List.sort - (fun (a_chr, (_, _, a)) (b_chr, (_, _, b)) -> - match S.compare_elt a b with - | 0 -> Char.compare a_chr b_chr - | c -> c) - children - in - let min_terminal = S.minimum terminals in - let min_child = - match min_terminal, children with - | Some a, (_, (_, _, b)) :: _ -> if S.compare_elt a b <= 0 then a else b - | Some a, [] -> a - | None, (_, (_, _, b)) :: _ -> b - | None, [] -> assert false - in - let children_uids = List.map (fun (chr, (uid, _, _)) -> chr, uid) children in - let key = node.start, node.len, terminals_uid, children_uids in - try Hashtbl.find cache key with - | Not_found -> - let children = - Array.of_list @@ List.map (fun (_, (_, child, _)) -> child) children - in - let children = if Array.length children = 0 then None else Some children in - let node = { T.start = node.start; len = node.len; terminals; children } in - let result = Uid.make (), node, min_child in - Hashtbl.add cache key result ; - result - - let clear ~str t = - let cache = Hashtbl.create 16 in - let cache_term = Terminals.Hashtbl.create 16 in - let _, t, _ = export ~cache ~cache_term t in - { T.str; t } - end - - type reader = Automata.T.t - - let export t = - let str = Buf.contents t.buffer in - Automata.clear ~str t.root - - let find = Automata.T.find - let to_sets = Automata.T.collapse - let sets_tree = Automata.T.sets_tree + let make () = + let u = !gen in + gen := u + 1 ; + u end -module With_elts = Make (Entry.Array) +module Terminals_cache = Hashtbl.Make (Terminals) + +let export_terminals ~cache_term ts = + try Terminals_cache.find cache_term ts with + | Not_found -> + let result = Uid.make (), Entry.Array.of_list ts in + Terminals_cache.add cache_term ts result ; + result + +let rec export ~cache ~cache_term node = + let terminals_uid, terminals = export_terminals ~cache_term node.terminals in + let children = + Char_map.bindings @@ Char_map.map (export ~cache ~cache_term) node.children + in + let children = + List.sort + (fun (a_chr, (_, _, a)) (b_chr, (_, _, b)) -> + match Entry.compare a b with + | 0 -> Char.compare a_chr b_chr + | c -> c) + children + in + let min_terminal = Entry.Array.minimum terminals in + let min_child = + match min_terminal, children with + | Some a, (_, (_, _, b)) :: _ -> if Entry.compare a b <= 0 then a else b + | Some a, [] -> a + | None, (_, (_, _, b)) :: _ -> b + | None, [] -> assert false + in + let children_uids = List.map (fun (chr, (uid, _, _)) -> chr, uid) children in + let key = node.start, node.len, terminals_uid, children_uids in + try Hashtbl.find cache key with + | Not_found -> + let children = Array.of_list @@ List.map (fun (_, (_, child, _)) -> child) children in + let children = if Array.length children = 0 then None else Some children in + let node = + { String_automata.start = node.start; len = node.len; terminals; children } + in + let result = Uid.make (), node, min_child in + Hashtbl.add cache key result ; + result + +let export { buffer; root = t } = + let str = Buf.contents buffer in + let cache = Hashtbl.create 16 in + let cache_term = Terminals_cache.create 16 in + let _, t, _ = export ~cache ~cache_term t in + { String_automata.str; t } diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli index 2f131e534b..1a473a37e7 100644 --- a/db/suffix_tree.mli +++ b/db/suffix_tree.mli @@ -1,44 +1,11 @@ -module type SET = sig - type t - type elt - - val of_list : elt list -> t - val is_empty : t -> bool - val minimum : t -> elt option - val equal_elt : elt -> elt -> bool - val compare_elt : elt -> elt -> int -end - module Buf : sig type t val make : unit -> t end -module Make (S : SET) : sig - type writer - (** A writer is an incomplete suffix tree. - You can add suffixes to it. *) - - val make : Buf.t -> writer - val add_suffixes : writer -> string -> S.elt -> unit - - type reader - (** A reader is a completed suffix tree. You can make queries on it. Its size - is smaller than the equivalent [writer]. *) - - val export : writer -> reader - val find : reader -> string -> reader option - val to_sets : reader -> S.t list - - val sets_tree - : union:('a -> 'a -> 'a) - -> terminal:(S.t -> 'a) - -> union_of_array:('a array -> 'a) - -> reader - -> 'a -end +type t -module With_elts : module type of Make (Entry.Array) -(** [With_elts] is a suffix tree with array of entries at the leafs. It is used - for the text-based part of the database. *) +val make : Buf.t -> t +val add_suffixes : t -> string -> Entry.t -> unit +val export : t -> String_automata.t diff --git a/query/query.ml b/query/query.ml index a090274499..54272e1fbb 100644 --- a/query/query.ml +++ b/query/query.ml @@ -1,7 +1,7 @@ module Parser = Query_parser module Dynamic_cost = Dynamic_cost module Storage = Db.Storage -module Tree = Db.Suffix_tree.With_elts +module Tree = Db.String_automata module Private = struct module Array_succ = Array_succ From b51e61db25153aeacba6a1f100895afdf34ae866 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 9 Jan 2024 18:05:09 +0100 Subject: [PATCH 225/285] optimize search for short queries --- db/string_automata.ml | 33 +++++--- db/string_automata.mli | 8 +- query/priority_queue.ml | 100 +++++++++++++++++++++++ query/priority_queue.mli | 8 ++ query/query.ml | 9 +-- query/succ.ml | 167 ++++++++++++++++----------------------- query/succ.mli | 32 +++----- query/test/test_succ.ml | 35 +++++--- 8 files changed, 240 insertions(+), 152 deletions(-) create mode 100644 query/priority_queue.ml create mode 100644 query/priority_queue.mli diff --git a/db/string_automata.ml b/db/string_automata.ml index 73149bfd2d..87ea165520 100644 --- a/db/string_automata.ml +++ b/db/string_automata.ml @@ -14,9 +14,10 @@ let array_find ~str chr arr = let rec go i = if i >= Array.length arr then raise Not_found - else ( + else begin let node = arr.(i) in - if chr = str.[node.start - 1] then node else go (i + 1)) + if chr = str.[node.start - 1] then node else go (i + 1) + end in go 0 @@ -60,14 +61,26 @@ let find t pattern = try Some (find t pattern) with | Not_found -> None -let rec sets_tree ~union ~terminal ~union_of_array t = - let ts = terminal t.terminals in - let cs = +let min_opt a b = + match a, b with + | Some x, Some y -> Some (if Entry.compare x y <= 0 then x else y) + | Some x, None | None, Some x -> Some x + | None, None -> None + +let rec minimum t = + let min_terminal = + match t.terminals with + | None -> None + | Some arr -> Some arr.(0) + in + let min_child = match t.children with - | None -> [||] - | Some children -> Array.map (sets_tree ~union ~terminal ~union_of_array) children + | None -> None + | Some children -> minimum children.(0) in - union ts (union_of_array cs) + min_opt min_terminal min_child -let sets_tree ~union ~terminal ~union_of_array t = - sets_tree ~union ~terminal ~union_of_array t.t +let minimum { t; _ } = + match minimum t with + | None -> assert false + | Some elt -> elt diff --git a/db/string_automata.mli b/db/string_automata.mli index 1e29b6315f..03f11b71b4 100644 --- a/db/string_automata.mli +++ b/db/string_automata.mli @@ -14,10 +14,4 @@ type t = } val find : t -> string -> t option - -val sets_tree - : union:('a -> 'a -> 'a) - -> terminal:(Entry.Array.t -> 'a) - -> union_of_array:('a array -> 'a) - -> t - -> 'a +val minimum : t -> Entry.t diff --git a/query/priority_queue.ml b/query/priority_queue.ml new file mode 100644 index 0000000000..8579199e3c --- /dev/null +++ b/query/priority_queue.ml @@ -0,0 +1,100 @@ +module String_automata = Db.String_automata +module Entry = Db.Entry + +type elt = Entry.t + +type t = + | Empty + | Array of int * elt array + | All of elt * String_automata.t + | Union of elt * t list + +let minimum = function + | Empty -> None + | Array (i, arr) -> Some arr.(i) + | All (elt, _) | Union (elt, _) -> Some elt + +let of_sorted_array = function + | None -> Empty + | Some arr -> Array (0, arr) + +let of_automata s = + let elt = String_automata.minimum s in + All (elt, s) + +let insert_sort x lst = + match minimum x with + | None -> lst + | Some min_elt -> + let rec go lst = + match lst with + | [] -> [ x ] + | y :: ys -> begin + match minimum y with + | None -> go ys + | Some min_y when Entry.compare min_elt min_y <= 0 -> x :: lst + | _ -> y :: go ys + end + in + go lst + +let union_with ~min_elt lst = + match List.filter (( <> ) Empty) lst with + | [] -> Empty + | [ t ] -> t + | sorted_lst -> Union (min_elt, sorted_lst) + +let rec union_sorted lst = + match lst with + | [] -> Empty + | [ t ] -> t + | x :: xs -> begin + match minimum x with + | None -> union_sorted xs + | Some min_elt -> Union (min_elt, lst) + end + +let rec pop_until cond = function + | Empty -> Empty + | Array (i, arr) as t -> + let rec search i j = + assert (not (cond arr.(i))) ; + assert (cond arr.(j)) ; + let m = (i + j) / 2 in + if i = m then Array (j, arr) else if cond arr.(m) then search i m else search m j + in + let rec go j step = + if j >= Array.length arr + then begin + let last = Array.length arr - 1 in + let j_prev = j - (step / 2) in + if cond arr.(last) then search j_prev last else Empty + end + else if cond arr.(j) + then if i = j then t else search (j - (step / 2)) j + else go (j + step) (step * 2) + in + go i 1 + | All (min_elt, _) as t when cond min_elt -> t + | All (min_elt, ({ String_automata.t; _ } as automata)) -> + let terminals = of_sorted_array t.terminals in + let children = + Array.to_list + @@ Array.map (fun child -> of_automata { automata with t = child }) + @@ Option.value ~default:[||] t.children + in + let all = insert_sort terminals children in + pop_until cond (union_with ~min_elt all) + | Union (min_elt, _) as t when cond min_elt -> t + | Union (_, lst) -> + let rec go = function + | [] -> [] + | x :: xs -> + let x' = pop_until cond x in + if x == x' then x :: xs else insert_sort x' (go xs) + in + let lst = go lst in + union_sorted lst + +let pop_lt elt t = pop_until (fun x -> Entry.compare x elt >= 0) t +let pop_lte elt t = pop_until (fun x -> Entry.compare x elt > 0) t diff --git a/query/priority_queue.mli b/query/priority_queue.mli new file mode 100644 index 0000000000..40134bc653 --- /dev/null +++ b/query/priority_queue.mli @@ -0,0 +1,8 @@ +type elt = Db.Entry.t +type t + +val minimum : t -> elt option +val of_automata : Db.String_automata.t -> t +val of_sorted_array : elt array option -> t +val pop_lt : elt -> t -> t +val pop_lte : elt -> t -> t diff --git a/query/query.ml b/query/query.ml index 54272e1fbb..061f3de577 100644 --- a/query/query.ml +++ b/query/query.ml @@ -14,9 +14,6 @@ module Private = struct end end -let collapse_trie t = - Succ.(Tree.sets_tree ~union ~terminal:of_array_opt ~union_of_array t) - let polarities typ = List.of_seq @@ Seq.filter @@ -42,7 +39,7 @@ let find_types ~shards typ = then acc else begin match Tree.find st name with - | Some trie -> Succ.union acc (collapse_trie trie) + | Some trie -> Succ.union acc (Succ.of_automata trie) | None -> acc end) st_occ @@ -62,7 +59,7 @@ let find_names ~(shards : Db.t list) names = List.map (fun name -> match Tree.find db_names name with - | Some trie -> collapse_trie trie + | Some trie -> Succ.of_automata trie | None -> Succ.empty) names in @@ -98,7 +95,7 @@ let match_packages ~packages results = let search ~(shards : Db.t list) ?(dynamic_sort = true) params = let words, typ = Parser.of_string params.query in let results = search ~shards words typ in - let results = Succ.to_seq ~compare:Db.Entry.compare results in + let results = Succ.to_seq results in let results = match_packages ~packages:params.packages results in let results = List.of_seq @@ Seq.take params.limit results in let results = diff --git a/query/succ.ml b/query/succ.ml index 7e7c2a3939..29e6c6d15d 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,101 +1,94 @@ -type 'a node = - | Empty - | Array of 'a array - | Inter of 'a node * 'a node - | Union of 'a node * 'a node +module Entry = Db.Entry -let rec print_node a ~depth s = - print_string (String.make (depth * 4) ' ') ; - let depth = depth + 1 in - match s with - | Empty -> print_endline "Empty" - | Inter (l, r) -> - print_endline "Inter" ; - print_node a ~depth l ; - print_node a ~depth r - | Union (l, r) -> - print_endline "Union" ; - print_node a ~depth l ; - print_node a ~depth r - | Array arr -> - print_string "{ " ; - Array.iter - (fun elt -> - a elt ; - print_string " ") - arr ; - print_endline "}" - -let print_node a s = print_node a ~depth:0 s +type node = + | Empty + | Pq of Priority_queue.t + | Inter of node * node + | Union of node * node -let best ~compare x y = - match compare x y with - | 0 -> x - | c when c < 0 -> x - | _ -> y +let best x y = if Entry.compare x y <= 0 then x else y -let best_opt ~compare old_cand new_cand = +let best_opt old_cand new_cand = match old_cand, new_cand with | None, None -> None | None, Some z | Some z, None -> Some z - | Some x, Some y -> Some (best ~compare x y) - -let ( let* ) = Option.bind + | Some x, Some y -> Some (best x y) type strictness = | Gt | Ge -let array_succ ~strictness = - match strictness with - | Ge -> Array_succ.succ_ge - | Gt -> Array_succ.succ_gt - -let rec succ ~compare ~strictness t elt = +let rec succ ~strictness t elt = match t with - | Empty -> None - | Array arr -> array_succ ~strictness ~compare elt arr + | Empty -> None, t + | Pq pqueue -> + let pqueue = + match strictness with + | Gt -> Priority_queue.pop_lte elt pqueue + | Ge -> Priority_queue.pop_lt elt pqueue + in + begin + match Priority_queue.minimum pqueue with + | None -> () + | Some e -> assert (Entry.compare elt e <= 0) + end ; + Priority_queue.minimum pqueue, Pq pqueue | Union (l, r) -> - let elt_r = succ ~compare ~strictness r elt in - let elt_l = succ ~compare ~strictness l elt in - best_opt ~compare elt_l elt_r + let elt_l, l = succ ~strictness l elt in + let elt_r, r = succ ~strictness r elt in + best_opt elt_l elt_r, Union (l, r) | Inter (l, r) -> - let rec loop elt_r = - let* elt_l = succ ~compare ~strictness:Ge l elt_r in - let* elt_r = succ ~compare ~strictness:Ge r elt_l in - if compare elt_l elt_r = 0 then Some elt_l else loop elt_r + let rec loop elt l r = + match succ ~strictness:Ge l elt with + | None, _ -> None, Empty + | Some elt_l, l -> begin + match succ ~strictness:Ge r elt_l with + | None, _ -> None, Empty + | Some elt_r, r -> + assert (Entry.compare elt_l elt_r <= 0) ; + if Entry.compare elt_l elt_r = 0 + then Some elt_l, Inter (l, r) + else loop elt_r l r + end in - let* elt_l = succ ~compare ~strictness l elt in - loop elt_l + begin + match succ ~strictness l elt with + | None, _ -> None, Empty + | Some elt, l -> loop elt l r + end -let rec first ~compare t = +let rec first t = match t with - | Empty -> None - | Array s -> Some s.(0) - | Inter (l, _) -> - let* elt = first ~compare l in - succ ~strictness:Ge ~compare t elt - | Union (l, r) -> begin - let elt_l = first ~compare l in - let elt_r = first ~compare r in - best_opt ~compare elt_l elt_r + | Empty -> None, Empty + | Pq pqueue -> Priority_queue.minimum pqueue, t + | Inter (l, r) -> begin + match first l with + | None, _ -> None, Empty + | Some elt, l -> succ ~strictness:Ge (Inter (l, r)) elt end + | Union (l, r) -> + let elt_l, l = first l in + let elt_r, r = first r in + best_opt elt_l elt_r, Union (l, r) -type 'a t = +type t = { cardinal : int - ; s : 'a node + ; s : node } -let to_seq ~compare { s; _ } = +let to_seq { s; _ } = let state = ref None in let loop () = - let elt = + let elt, s = match !state with - | None -> first ~compare s - | Some previous_elt -> succ ~strictness:Gt ~compare s previous_elt + | None -> first s + | Some (previous_elt, s) -> succ ~strictness:Gt s previous_elt in - state := elt ; - elt + match elt with + | None -> None + | Some elt -> + state := Some (elt, s) ; + Some elt in Seq.of_dispenser loop @@ -103,13 +96,6 @@ let to_seq ~compare { s; _ } = let empty = { cardinal = 0; s = Empty } -let of_array arr = - if Array.length arr = 0 then empty else { cardinal = Array.length arr; s = Array arr } - -let of_array_opt = function - | None -> empty - | Some arr -> of_array arr - let inter a b = match a.s, b.s with | Empty, _ | _, Empty -> empty @@ -127,24 +113,11 @@ let union a b = let x, y = if a.cardinal < b.cardinal then x, y else y, x in { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } -(** This does a dychotomy to avoid building a comb, which would have poor - performance. *) -let union_of_array arr = - let rec loop lo hi = - match hi - lo with - | 0 -> empty - | 1 -> arr.(lo) - | dist -> - let mid = lo + (dist / 2) in - let left = loop lo mid in - let right = loop mid hi in - union left right - in - loop 0 (Array.length arr) - -let union_of_list li = li |> Array.of_list |> union_of_array -let print a { s; _ } = print_node a s - let inter_of_list = function | [] -> empty | elt :: li -> List.fold_left inter elt li + +let of_automata t = { s = Pq (Priority_queue.of_automata t); cardinal = 1 } + +let of_array arr = + { s = Pq (Priority_queue.of_sorted_array (Some arr)); cardinal = Array.length arr } diff --git a/query/succ.mli b/query/succ.mli index fb367717ce..b4d2e418b2 100644 --- a/query/succ.mli +++ b/query/succ.mli @@ -1,26 +1,12 @@ (** This module provides a way to get the first n elements of a very large set without computing the whole list of elements. *) -type 'a t - -val print : ('a -> unit) -> 'a t -> unit -val to_seq : compare:('a -> 'a -> int) -> 'a t -> 'a Seq.t - -(** Functions to build a succ tree *) - -val empty : 'a t -val of_array : 'a array -> 'a t - -val of_array_opt : 'a array option -> 'a t -(** Warning : only provide a sorted array, this is not checked ! - It has to be sorted according to the [compare] function that you will - eventually pass to [to_seq]. *) - -val inter : 'a t -> 'a t -> 'a t -val union : 'a t -> 'a t -> 'a t -val union_of_array : 'a t array -> 'a t - -val union_of_list : 'a t list -> 'a t -(** [union_of_list] has better performance than [List.fold_left union empty]. *) - -val inter_of_list : 'a t list -> 'a t +type t + +val to_seq : t -> Db.Entry.t Seq.t +val empty : t +val of_automata : Db.String_automata.t -> t +val inter : t -> t -> t +val union : t -> t -> t +val inter_of_list : t list -> t +val of_array : Db.Entry.t array -> t diff --git a/query/test/test_succ.ml b/query/test/test_succ.ml index be71c31801..5adaca5299 100644 --- a/query/test/test_succ.ml +++ b/query/test/test_succ.ml @@ -1,12 +1,25 @@ open Query.Private +let pkg = Db.Entry.Package.v ~name:"" ~version:"" + +let elt cost = + Db.Entry.v + ~cost + ~name:"" + ~kind:Db.Entry.Kind.Doc + ~rhs:None + ~doc_html:"" + ~url:"" + ~is_from_module_type:false + ~pkg + () + (** This module does the same thing as Succ, but its correctness is obvious and its performance terrible. *) module Reference = struct - include Set.Make (Int) + include Set.Make (Db.Entry) let of_array arr = arr |> Array.to_seq |> of_seq - let to_seq ~compare:_ = to_seq end (** This module is used to construct a pair of a "set array" using [Reference] @@ -21,10 +34,11 @@ end (** This is a problematic exemple that was found randomly. It is saved here to check for regressions. *) let extra_succ = - Both.( - union - (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) - (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |]))) + let open Both in + let of_array arr = Both.of_array (Array.map elt arr) in + union + (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) + (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |])) let rec random_set ~empty ~union ~inter ~of_array size = let random_set = random_set ~empty ~union ~inter ~of_array in @@ -34,15 +48,18 @@ let rec random_set ~empty ~union ~inter ~of_array size = match Random.int 3 with | 0 -> let arr = Test_array.random_array size in - Array.sort Int.compare arr ; + let arr = Array.map elt arr in + Array.sort Db.Entry.compare arr ; of_array arr | 1 -> inter (random_set (size / 2)) (random_set (size / 2)) | 2 -> union (random_set (size / 2)) (random_set (size / 2)) | _ -> assert false) +let to_costs lst = List.map (fun e -> e.Db.Entry.cost) (List.of_seq lst) + let test_to_seq tree () = - let ref = fst tree |> Reference.to_seq ~compare:Int.compare |> List.of_seq in - let real = snd tree |> Succ.to_seq ~compare:Int.compare |> List.of_seq in + let ref = fst tree |> Reference.to_seq |> to_costs in + let real = snd tree |> Succ.to_seq |> to_costs in Alcotest.(check (list int)) "same int list" ref real let tests_to_seq = From 0182637b01829232c4abce9d5a9ebd2557d3b26e Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 10 Jan 2024 15:22:54 +0100 Subject: [PATCH 226/285] simplify succ --- query/succ.ml | 80 +++++++++++++++++++++++--------------------------- query/succ.mli | 1 + 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/query/succ.ml b/query/succ.ml index 29e6c6d15d..b82182ee91 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,11 +1,40 @@ module Entry = Db.Entry -type node = +type t = | Empty | Pq of Priority_queue.t - | Inter of node * node - | Union of node * node + | Inter of t * t + | Union of t * t + +let empty = Empty +let of_automata t = Pq (Priority_queue.of_automata t) +let of_array arr = Pq (Priority_queue.of_sorted_array (Some arr)) + +let inter a b = + match a, b with + | Empty, _ | _, Empty -> empty + | x, y when x == y -> a + | x, y -> Inter (x, y) +let union a b = + match a, b with + | Empty, _ -> b + | _, Empty -> a + | x, y when x == y -> a + | x, y -> Union (x, y) + +let rec join_with fn = function + | [] -> [] + | [ x ] -> [ x ] + | a :: b :: xs -> fn a b :: join_with fn xs + +let rec perfect fn = function + | [] -> Empty + | [ x ] -> x + | xs -> perfect fn (join_with fn xs) + +let inter_of_list xs = perfect inter xs +let union_of_list xs = perfect union xs let best x y = if Entry.compare x y <= 0 then x else y let best_opt old_cand new_cand = @@ -71,53 +100,18 @@ let rec first t = let elt_r, r = first r in best_opt elt_l elt_r, Union (l, r) -type t = - { cardinal : int - ; s : node - } - -let to_seq { s; _ } = +let to_seq t = let state = ref None in let loop () = - let elt, s = + let elt, t = match !state with - | None -> first s - | Some (previous_elt, s) -> succ ~strictness:Gt s previous_elt + | None -> first t + | Some (previous_elt, t) -> succ ~strictness:Gt t previous_elt in match elt with | None -> None | Some elt -> - state := Some (elt, s) ; + state := Some (elt, t) ; Some elt in Seq.of_dispenser loop - -(** Functions to build a succ tree *) - -let empty = { cardinal = 0; s = Empty } - -let inter a b = - match a.s, b.s with - | Empty, _ | _, Empty -> empty - | x, y when x == y -> a - | x, y -> - let x, y = if a.cardinal < b.cardinal then x, y else y, x in - { cardinal = min a.cardinal b.cardinal; s = Inter (x, y) } - -let union a b = - match a.s, b.s with - | Empty, _ -> b - | _, Empty -> a - | x, y when x == y -> a - | x, y -> - let x, y = if a.cardinal < b.cardinal then x, y else y, x in - { cardinal = a.cardinal + b.cardinal; s = Union (x, y) } - -let inter_of_list = function - | [] -> empty - | elt :: li -> List.fold_left inter elt li - -let of_automata t = { s = Pq (Priority_queue.of_automata t); cardinal = 1 } - -let of_array arr = - { s = Pq (Priority_queue.of_sorted_array (Some arr)); cardinal = Array.length arr } diff --git a/query/succ.mli b/query/succ.mli index b4d2e418b2..c0041cd658 100644 --- a/query/succ.mli +++ b/query/succ.mli @@ -9,4 +9,5 @@ val of_automata : Db.String_automata.t -> t val inter : t -> t -> t val union : t -> t -> t val inter_of_list : t list -> t +val union_of_list : t list -> t val of_array : Db.Entry.t array -> t From ec04144060374340cd1c211a0b3850e78795cebc Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 10 Jan 2024 16:24:11 +0100 Subject: [PATCH 227/285] refactor parts of query --- query/dynamic_cost.ml | 36 ++++++++---- query/query.ml | 119 ++++++++++++++++++---------------------- query/query_parser.ml | 41 +++++++++----- query/query_parser.mli | 8 ++- query/type_distance.ml | 5 +- query/type_distance.mli | 14 +++-- 6 files changed, 122 insertions(+), 101 deletions(-) diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 93549f9543..7dee2641b1 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -1,5 +1,18 @@ module Entry = Db.Entry +type query = + { name : string list + ; type_paths : Type_distance.Type_path.t option + } + +let of_query { Query_parser.name; typ } = + let type_paths = + match typ with + | `typ t -> Some (Type_distance.Type_path.of_typ ~ignore_any:true t) + | _ -> None + in + { name; type_paths } + module Reasoning = struct (** The [Reasoning] module contains a representation that include every reason for which a search entry would be ranked higher or lower. It does not @@ -64,14 +77,14 @@ module Reasoning = struct } let type_distance query_type entry = - let open Entry in - match query_type, Entry.Kind.get_type entry.kind with - | Error _, _ -> None - | Ok query_type, Some entry_type -> - Some (Type_distance.v ~query:query_type ~entry:entry_type) - | _, None -> None + match query_type, Entry.Kind.get_type entry.Entry.kind with + | Some query_paths, Some entry_type -> + Some (Type_distance.v ~query_paths ~entry:entry_type) + | _ -> None - let type_in_query query_type = Result.is_ok query_type + let type_in_query = function + | Some _ -> true + | _ -> false let type_in_entry entry = let open Entry in @@ -88,7 +101,7 @@ module Reasoning = struct let has_doc e = e.Entry.doc_html <> "" (** Compute the reasoning for the cost of an entry *) - let v query_words query_type entry = + let v { name = query_words; type_paths = query_type } entry = { is_stdlib = is_stdlib entry ; has_doc = has_doc entry ; name_matches = Name_match.with_words query_words entry @@ -162,8 +175,7 @@ let cost_of_reasoning + name_length + is_from_module_type_cost -let cost_of_entry ~query_name ~query_type entry = - cost_of_reasoning (Reasoning.v query_name query_type entry) +let cost_of_entry query entry = cost_of_reasoning (Reasoning.v query entry) -let update_entry ~query_name ~query_type entry = - Entry.{ entry with cost = entry.cost + cost_of_entry ~query_name ~query_type entry } +let update_entry query entry = + Entry.{ entry with cost = entry.cost + cost_of_entry query entry } diff --git a/query/query.ml b/query/query.ml index 061f3de577..0b9655b9cf 100644 --- a/query/query.ml +++ b/query/query.ml @@ -20,53 +20,54 @@ let polarities typ = (fun (word, _count, _) -> String.length word > 0) (Db.Type_polarity.of_typ ~any_is_poly:false ~all_names:false typ) -let find_types ~shards typ = +let find_types ~shard typ = let polarities = polarities typ in - List.fold_left - (fun acc shard -> - let r = - Succ.inter_of_list - @@ List.map - (fun (name, count, polarity) -> - let st_occ = - match polarity with - | Db.Type_polarity.Sign.Pos -> shard.Db.db_pos_types - | Neg -> shard.Db.db_neg_types - in - Db.Occurences.fold - (fun occurrences st acc -> - if occurrences < count - then acc - else begin - match Tree.find st name with - | Some trie -> Succ.union acc (Succ.of_automata trie) - | None -> acc - end) - st_occ - Succ.empty) - polarities - in - Succ.union acc r) - Succ.empty - shards + Succ.inter_of_list + @@ List.map + (fun (name, count, polarity) -> + let st_occ = + match polarity with + | Db.Type_polarity.Sign.Pos -> shard.Db.db_pos_types + | Neg -> shard.Db.db_neg_types + in + Db.Occurences.fold + (fun occurrences st acc -> + if occurrences < count + then acc + else begin + match Tree.find st name with + | Some trie -> Succ.union acc (Succ.of_automata trie) + | None -> acc + end) + st_occ + Succ.empty) + polarities -let find_names ~(shards : Db.t list) names = +let find_names ~shard names = let names = List.map String.lowercase_ascii names in - List.fold_left - (fun acc shard -> - let db_names = Db.(shard.db_names) in - let candidates = - List.map - (fun name -> - match Tree.find db_names name with - | Some trie -> Succ.of_automata trie - | None -> Succ.empty) - names - in - let candidates = Succ.inter_of_list candidates in - Succ.union acc candidates) - Succ.empty - shards + let db_names = Db.(shard.db_names) in + let candidates = + List.map + (fun name -> + match Tree.find db_names name with + | Some trie -> Succ.of_automata trie + | None -> Succ.empty) + names + in + Succ.inter_of_list candidates + +let search ~shard { Query_parser.name; typ } = + match name, typ with + | _ :: _, `typ typ -> + let results_name = find_names ~shard name in + let results_typ = find_types ~shard typ in + Succ.inter results_name results_typ + | _ :: _, _ -> find_names ~shard name + | [], `typ typ -> find_types ~shard typ + | [], (`no_typ | `parse_error) -> Succ.empty + +let search ~shards query = + Succ.union_of_list (List.map (fun shard -> search ~shard query) shards) type t = { query : string @@ -74,16 +75,6 @@ type t = ; limit : int } -let search ~(shards : Db.t list) query_name query_typ = - match query_name, query_typ with - | [], Error _ -> Succ.empty - | _ :: _, Error _ -> find_names ~shards query_name - | [], Ok query_typ -> find_types ~shards query_typ - | _ :: _, Ok query_typ -> - let results_name = find_names ~shards query_name in - let results_typ = find_types ~shards query_typ in - Succ.inter results_name results_typ - let match_packages ~packages { Db.Entry.pkg; _ } = List.exists (String.equal pkg.name) packages @@ -92,25 +83,21 @@ let match_packages ~packages results = | [] -> results | _ -> Seq.filter (match_packages ~packages) results -let search ~(shards : Db.t list) ?(dynamic_sort = true) params = - let words, typ = Parser.of_string params.query in - let results = search ~shards words typ in +let search ~shards ?(dynamic_sort = true) params = + let query = Parser.of_string params.query in + let results = search ~shards query in let results = Succ.to_seq results in let results = match_packages ~packages:params.packages results in let results = List.of_seq @@ Seq.take params.limit results in let results = if dynamic_sort - then List.map (Dynamic_cost.update_entry ~query_name:words ~query_type:typ) results + then begin + let query = Dynamic_cost.of_query query in + List.map (Dynamic_cost.update_entry query) results + end else results in let results = List.sort Db.Entry.compare results in results -let pretty params = - let words, typ = Parser.of_string params.query in - let words = String.concat " " words in - match typ with - | Ok typ -> words ^ " : " ^ Db.Typexpr.show typ - | Error `parse -> words ^ " : " - | Error `any -> words ^ " : _" - | Error `empty -> words +let pretty params = Parser.(to_string @@ of_string params.query) diff --git a/query/query_parser.ml b/query/query_parser.ml index 8268495c8a..46d6b63cbc 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -25,20 +25,31 @@ let guess_type_search str = String.length str >= 1 && (str.[0] = '\'' || String.contains str '-' || String.contains str '(') +type t = + { name : string list + ; typ : [ `typ of Db.Typexpr.t | `no_typ | `parse_error ] + } + +let type_of_string str_typ = + match type_of_string str_typ with + | Ok typ -> `typ typ + | Error _ -> `parse_error + let of_string str = - let str = String.trim str in - let str_name, str_typ = - match String.split_on_char ':' str with - | [ a; b ] -> a, Ok b - | _ when guess_type_search str -> "", Ok str - | _ -> str, Error `empty + let query_name, typ = + match String.index_opt str ':' with + | None -> if guess_type_search str then "", type_of_string str else str, `no_typ + | Some loc -> + let str_name = String.sub str 0 loc in + let str_typ = String.sub str (loc + 1) (String.length str - loc - 1) in + str_name, type_of_string str_typ in - let typ = - Result.bind str_typ (fun str_typ -> - match type_of_string str_typ with - | Ok Any -> Error `any - | Ok typ -> Ok typ - | Error _ -> Error `parse) - in - let words = naive_of_string str_name in - words, typ + let name = naive_of_string query_name in + { name; typ } + +let to_string { name; typ } = + let words = String.concat " " name in + match typ with + | `typ typ -> words ^ " : " ^ Db.Typexpr.show typ + | `parse_error -> words ^ " : " + | `no_typ -> words diff --git a/query/query_parser.mli b/query/query_parser.mli index c4acfa5a7b..7c7d1d74a9 100644 --- a/query/query_parser.mli +++ b/query/query_parser.mli @@ -1 +1,7 @@ -val of_string : string -> string list * (Db.Typexpr.t, [> `any | `parse | `empty ]) result +type t = + { name : string list + ; typ : [ `typ of Db.Typexpr.t | `no_typ | `parse_error ] + } + +val of_string : string -> t +val to_string : t -> string diff --git a/query/type_distance.ml b/query/type_distance.ml index 266b7c6f19..c99dc541e1 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -195,9 +195,8 @@ let minimize = function let _ = go (Array.length used) 0 0 in !best -let v ~query ~entry = - let query_paths = Type_path.of_typ ~ignore_any:false query in - let entry_paths = Type_path.of_typ ~ignore_any:true entry in +let v ~query_paths ~entry = + let entry_paths = Type_path.of_typ ~ignore_any:false entry in match entry_paths, query_paths with | _, [] | [], _ -> 0 | _ -> diff --git a/query/type_distance.mli b/query/type_distance.mli index 5a6dc5b39f..3d73b7eafe 100644 --- a/query/type_distance.mli +++ b/query/type_distance.mli @@ -1,4 +1,10 @@ -val v : query:Db.Typexpr.t -> entry:Db.Typexpr.t -> int -(** [Type_distance.v ~query ~entry] is an integer representing a notion of - distance between two types. [query] is a type from a query, and [entry] is - the type of a possible response to this query. *) +module Type_path : sig + type t + + val of_typ : ignore_any:bool -> Db.Typexpr.t -> t +end + +val v : query_paths:Type_path.t -> entry:Db.Typexpr.t -> int +(** [Type_distance.v ~query_paths ~entry] is an integer representing a notion of + distance between two types. [query_paths] is a type from a query, and [entry] is + the type of a possible candidate for this query. *) From 515b4698f34256bdcfb2cc9d7f71fb610795f6f4 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 11 Jan 2024 11:25:24 +0100 Subject: [PATCH 228/285] fetch more results to improve sort quality --- query/dynamic_cost.ml | 3 --- query/query.ml | 18 ++++++-------- query/top_results.ml | 53 ++++++++++++++++++++++++++++++++++++++++ query/top_results.mli | 1 + test/cram/base_cli.t | 18 +++++++------- test/cram/base_web.t | 6 ++--- test/cram/cli.t/run.t | 1 + test/cram/simple.t/run.t | 2 +- 8 files changed, 75 insertions(+), 27 deletions(-) create mode 100644 query/top_results.ml create mode 100644 query/top_results.mli diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 7dee2641b1..031c68147a 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -176,6 +176,3 @@ let cost_of_reasoning + is_from_module_type_cost let cost_of_entry query entry = cost_of_reasoning (Reasoning.v query entry) - -let update_entry query entry = - Entry.{ entry with cost = entry.cost + cost_of_entry query entry } diff --git a/query/query.ml b/query/query.ml index 0b9655b9cf..2017268c2d 100644 --- a/query/query.ml +++ b/query/query.ml @@ -84,20 +84,16 @@ let match_packages ~packages results = | _ -> Seq.filter (match_packages ~packages) results let search ~shards ?(dynamic_sort = true) params = + let limit = params.limit in let query = Parser.of_string params.query in let results = search ~shards query in let results = Succ.to_seq results in let results = match_packages ~packages:params.packages results in - let results = List.of_seq @@ Seq.take params.limit results in - let results = - if dynamic_sort - then begin - let query = Dynamic_cost.of_query query in - List.map (Dynamic_cost.update_entry query) results - end - else results - in - let results = List.sort Db.Entry.compare results in - results + if dynamic_sort + then begin + let query = Dynamic_cost.of_query query in + List.of_seq @@ Top_results.of_seq ~query ~limit results + end + else List.of_seq @@ Seq.take params.limit results let pretty params = Parser.(to_string @@ of_string params.query) diff --git a/query/top_results.ml b/query/top_results.ml new file mode 100644 index 0000000000..13e1981411 --- /dev/null +++ b/query/top_results.ml @@ -0,0 +1,53 @@ +module Bests = Set.Make (Db.Entry) + +type t = + { size : int + ; bests : Bests.t + } + +let empty = { size = 0; bests = Bests.empty } + +type step = + | Continue of t + | Stop of t + +let update_entry query entry = + let extra_cost = Dynamic_cost.cost_of_entry query entry in + Db.Entry.{ entry with cost = entry.cost + extra_cost } + +let add ~query ~limit elt t = + if t.size < limit + then begin + let elt = update_entry query elt in + Continue { size = t.size + 1; bests = Bests.add elt t.bests } + end + else begin + let worst = Bests.max_elt t.bests in + if Db.Entry.(elt.cost > worst.cost) + then Stop t + else begin + let elt = update_entry query elt in + if Db.Entry.(elt.cost > worst.cost) + then Continue t + else Continue { t with bests = Bests.add elt @@ Bests.remove worst t.bests } + end + end + +let max_seek = 500 + +let of_seq ~query ~limit seq = + let rec go total_seen t seq = + if total_seen >= limit + max_seek + then t + else begin + match seq () with + | Seq.Nil -> t + | Cons (x, xs) -> begin + match add ~query ~limit x t with + | Stop t -> t + | Continue t -> go (total_seen + 1) t xs + end + end + in + let t = go 0 empty seq in + Bests.to_seq t.bests diff --git a/query/top_results.mli b/query/top_results.mli new file mode 100644 index 0000000000..c8c33d0ea1 --- /dev/null +++ b/query/top_results.mli @@ -0,0 +1 @@ +val of_seq : query:Dynamic_cost.query -> limit:int -> Db.Entry.t Seq.t -> Db.Entry.t Seq.t diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 287ca5d11c..73f3ff13fd 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -137,7 +137,7 @@ 1391 val Base.Set.S_poly.of_array : 'a array -> 'a t 1391 val Base.Set.S_poly.to_array : 'a t -> 'a array 1392 val Base.Set.S_poly.singleton : 'a -> 'a t - 1395 val Base.Hashtbl.S_poly.mem : ('a, _) t -> 'a key -> bool + 1395 val Base.Map.S_poly.to_tree : ('k, 'v) t -> ('k, 'v) tree $ sherlodoc search --print-cost --no-rhs "group b" 453 val Base.List.group 484 val Base.Sequence.group @@ -225,8 +225,8 @@ 438 val Base.List.(>>|) : 'a t -> ('a -> 'b) -> 'b t 438 val Base.Set.to_list : ('a, _) t -> 'a list 439 val Base.List.append : 'a t -> 'a t -> 'a t - 440 val Base.List.(>>=) : 'a t -> ('a -> 'b t) -> 'b t - 444 mod Base.List.Let_syntax + 440 val Base.List.find : 'a t -> f:('a -> bool) -> 'a option + 440 val Base.List.mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t $ sherlodoc search --print-cost ": list" 320 val Base.Map.data : (_, 'v, _) t -> 'v list 320 val Base.Map.keys : ('k, _, _) t -> 'k list @@ -251,8 +251,8 @@ 403 val Base.Hashtbl.find_multi : ('a, 'b list) t -> 'a key -> 'b list 404 val Base.Sequence.chunks_exn : 'a t -> int -> 'a list t 410 val Base.Map.add_multi : ('k, 'v list, 'cmp) t -> key:'k -> data:'v -> ('k, 'v list, 'cmp) t - 793 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list - 797 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + 412 val Base.List.find_all_dups : 'a t -> compare:('a -> 'a -> int) -> 'a list + 414 val Base.String.split_on_chars : t -> on:char list -> t list Partial name search: $ sherlodoc search --print-cost "strin" @@ -275,12 +275,12 @@ Partial name search: 445 val Base.Exn.to_string : t -> string 445 val Base.Sexp.of_string : unit 445 mod Base.Bytes.To_string + 446 val Base.String.tr : target:char -> replacement:char -> t -> t 446 val Base.String.prefix : t -> int -> t 446 val Base.String.suffix : t -> int -> t 446 val Base.String.escaped : t -> t 447 val Base.String.iter : t -> f:(elt -> unit) -> unit - 452 sig Base.Blit.S_to_string - 452 mod Base.Buffer.To_string + 448 val Base.String.split : t -> on:char -> t list $ sherlodoc search --print-cost "tring" 380 mod Base.String 380 mod Caml.String @@ -301,9 +301,9 @@ Partial name search: 444 mod Base.String.Caseless 444 mod Base.String.Escaping 445 val Base.String.init : int -> f:(int -> elt) -> t + 446 val Base.String.tr : target:char -> replacement:char -> t -> t 446 val Base.String.prefix : t -> int -> t 446 val Base.String.suffix : t -> int -> t 446 val Base.String.escaped : t -> t 447 val Base.String.iter : t -> f:(elt -> unit) -> unit - 450 sig Base.Blit.S_to_string - 450 mod Base.Buffer.To_string + 448 val Base.String.split : t -> on:char -> t list diff --git a/test/cram/base_web.t b/test/cram/base_web.t index b0dc025472..854103b19d 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -18,8 +18,8 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2520 db.js - 1900 db.js.gz + 2540 db.js + 1916 db.js.gz 1548 megaodocl.gz $ for f in $(find . -name '*.odocl'); do @@ -31,7 +31,7 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 216K html/sherlodoc.js + 212K html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 0eec07b873..c33944633b 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -83,6 +83,7 @@ val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo doc + doc $ sherlodoc search "qwertyuiopasdfghjklzxcvbnm" [No results] $ sherlodoc search "hidden" diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 8a508aec7c..b2196f97e3 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 216K sherlodoc.js + 212K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html From 694c7b0db0db4db767932b48ae5db9ab9c6114c5 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 11 Jan 2024 15:15:47 +0100 Subject: [PATCH 229/285] remove dependency to re,tyxml for smaller sherlodoc.js --- jsoo/dune | 5 +-- jsoo/main.ml | 17 ++++---- jsoo/odoc_html_frontend.ml | 50 +++++++++++++++++++++++ jsoo/tyxml.ml | 84 ++++++++++++++++++++++++++++++++++++++ jsoo/tyxml.mli | 18 ++++++++ query/dune | 2 +- query/dynamic_cost.ml | 17 +++++++- test/cram/base_web.t | 2 +- test/cram/simple.t/run.t | 2 +- 9 files changed, 179 insertions(+), 18 deletions(-) create mode 100644 jsoo/odoc_html_frontend.ml create mode 100644 jsoo/tyxml.ml create mode 100644 jsoo/tyxml.mli diff --git a/jsoo/dune b/jsoo/dune index 1b1dc9fd13..41175ded2c 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -1,10 +1,7 @@ -; This provides a javascript file for sherlodoc searches. This is compatible -; with the api decided by odoc. - (executable (name main) (modes js) - (libraries tyxml query storage_js brr odoc.search_html_frontend)) + (libraries query storage_js brr)) (rule (alias all) diff --git a/jsoo/main.ml b/jsoo/main.ml index 0b672f438b..72d3c6a74a 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -115,15 +115,14 @@ let search message db = in let kind = string_of_kind kind in let html = - Odoc_html_frontend.of_strings - ~kind - ~prefix_name - ~name - ~typedecl_params - ~rhs - ~doc:doc_html - |> List.map (Format.asprintf "%a" (Tyxml.Html.pp_elt ())) - |> String.concat "\n" + Tyxml.Html.string_of_list + @@ Odoc_html_frontend.of_strings + ~kind + ~prefix_name + ~name + ~typedecl_params + ~rhs + ~doc:doc_html in Jv.obj [| "html", Jv.of_string html; "url", Jv.of_string url |]) results diff --git a/jsoo/odoc_html_frontend.ml b/jsoo/odoc_html_frontend.ml new file mode 100644 index 0000000000..c44af2a2ad --- /dev/null +++ b/jsoo/odoc_html_frontend.ml @@ -0,0 +1,50 @@ +(* copy-pasted from odoc/src/search/odoc_html_frontend.ml *) + +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 typedecl_params = + match typedecl_params with + | None -> [] + | Some p -> + [ span + ~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 + | Some name -> [ span ~a:[ a_class [ "entry-name" ] ] [ txt name ] ] + | None -> [] + and rhs = + match rhs with + | None -> [] + | Some rhs -> [ code ~a:[ a_class [ "entry-rhs" ] ] [ txt rhs ] ] + in + [ kind + ; code ~a:[ a_class [ "entry-title" ] ] (typedecl_params @ prefix_name @ name @ rhs) + ; div ~a:[ a_class [ "entry-comment" ] ] [ Unsafe.data doc ] + ] + +let kind_doc = "doc" +let kind_typedecl = "type" +let kind_module = "mod" +let kind_exception = "exn" +let kind_class_type = "class" +let kind_class = "class" +let kind_method = "meth" +let kind_extension_constructor = "cons" +let kind_module_type = "sig" +let kind_constructor = "cons" +let kind_field = "field" +let kind_value = "val" +let kind_extension = "ext" diff --git a/jsoo/tyxml.ml b/jsoo/tyxml.ml new file mode 100644 index 0000000000..3ebabd7e18 --- /dev/null +++ b/jsoo/tyxml.ml @@ -0,0 +1,84 @@ +module Html : sig + type t + + val string_of_list : t list -> string + + type attr + + val a_class : string list -> attr + val code : a:attr list -> t list -> t + val span : a:attr list -> t list -> t + val div : a:attr list -> t list -> t + val txt : string -> t + + module Unsafe : sig + val data : string -> t + end +end = struct + type t = + | Raw of string + | Txt of string + | Concat of t list + + let add_escape_string buf s = + (* https://discuss.ocaml.org/t/html-encoding-of-string/4289/4 *) + let add = Buffer.add_string buf in + let len = String.length s in + let max_idx = len - 1 in + let flush start i = + if start < len then Buffer.add_substring buf s start (i - start) + in + let rec loop start i = + if i > max_idx + then flush start i + else begin + match String.get s i with + | '&' -> escape "&" start i + | '<' -> escape "<" start i + | '>' -> escape ">" start i + | '\'' -> escape "'" start i + | '"' -> escape """ start i + | '@' -> escape "@" start i + | _ -> loop start (i + 1) + end + and escape amperstr start i = + flush start i ; + add amperstr ; + let next = i + 1 in + loop next next + in + loop 0 0 + + let to_string t = + let buf = Buffer.create 16 in + let rec go = function + | Raw s -> Buffer.add_string buf s + | Txt s -> add_escape_string buf s + | Concat xs -> List.iter go xs + in + go t ; + Buffer.contents buf + + let string_of_list lst = to_string (Concat lst) + + type attr = t + + let a_class lst = Concat [ Raw "class=\""; Txt (String.concat " " lst); Raw "\"" ] + + let attrs = function + | [] -> Concat [] + | xs -> Concat (Raw " " :: xs) + + let block name ~a body = + let name = Raw name in + Concat [ Raw "<"; name; attrs a; Raw ">"; Concat body; Raw "" ] + + let code = block "code" + let span = block "span" + let div = block "span" + let txt s = Txt s + + module Unsafe = struct + let data s = Raw s + end +end diff --git a/jsoo/tyxml.mli b/jsoo/tyxml.mli new file mode 100644 index 0000000000..f539ea363a --- /dev/null +++ b/jsoo/tyxml.mli @@ -0,0 +1,18 @@ +(* smaller js bundle than the real TyXml *) +module Html : sig + type t + + val string_of_list : t list -> string + + type attr + + val a_class : string list -> attr + val code : a:attr list -> t list -> t + val span : a:attr list -> t list -> t + val div : a:attr list -> t list -> t + val txt : string -> t + + module Unsafe : sig + val data : string -> t + end +end diff --git a/query/dune b/query/dune index 1be6efc5e8..eec425d7db 100644 --- a/query/dune +++ b/query/dune @@ -1,6 +1,6 @@ (library (name query) - (libraries lwt re db)) + (libraries lwt db)) (menhir (modules type_parser) diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 031c68147a..f6ae3a7ad9 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -30,9 +30,22 @@ module Reasoning = struct | Lowercase | Doc + let rec is_prefix_at ~sub i s j = + if i >= String.length sub + then true + else if sub.[i] = s.[j] + then is_prefix_at ~sub (i + 1) s (j + 1) + else false + let is_substring ~sub s = - let re = Re.(compile (str sub)) in - Re.execp re s + let rec go j = + if j + String.length sub > String.length s + then false + else if is_prefix_at ~sub 0 s j + then true + else go (j + 1) + in + go 0 let with_word query_word name = let low_query_word = String.lowercase_ascii query_word in diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 854103b19d..1c02de306d 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -31,7 +31,7 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 212K html/sherlodoc.js + 140K html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index b2196f97e3..fdfa64d855 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 212K sherlodoc.js + 140K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html From e9f6151b57b3f6cbb21a7b0278798d513121bbd6 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 11 Jan 2024 15:16:36 +0100 Subject: [PATCH 230/285] remove dependency to storage_js for smaller sherlodoc.js --- jsoo/dune | 2 +- jsoo/main.ml | 2 +- store/storage_js.ml | 5 +---- test/cram/base_web.t | 2 +- test/cram/simple.t/run.t | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/jsoo/dune b/jsoo/dune index 41175ded2c..b9ac614a3c 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -1,7 +1,7 @@ (executable (name main) (modes js) - (libraries query storage_js brr)) + (libraries brr query)) (rule (alias all) diff --git a/jsoo/main.ml b/jsoo/main.ml index 72d3c6a74a..98e2394c11 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -72,7 +72,7 @@ end let db = Jv.(Decompress_browser.inflate @@ call global "sherlodoc_db" [||]) - |> Fut.map Storage_js.load + |> Fut.map (fun str -> [ Marshal.from_string str 0 ]) let string_of_kind = let open Db.Entry.Kind in diff --git a/store/storage_js.ml b/store/storage_js.ml index ce278a6573..11f8122438 100644 --- a/store/storage_js.ml +++ b/store/storage_js.ml @@ -29,7 +29,4 @@ let save ~db t = let str = Base64.encode_string str in Printf.fprintf db "function sherlodoc_db () { return %S; }\n%!" str -let load str = - (* let str = Base64.decode_exn str in - let str = inflate_string str |> Result.get_ok in *) - [ Marshal.from_string str 0 ] +let load _ = failwith "js database format is unsupported" diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 1c02de306d..708b666747 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -31,7 +31,7 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 140K html/sherlodoc.js + 128K html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index fdfa64d855..c4883e6b96 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 140K sherlodoc.js + 128K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html From 7263e7756d13015da02c837530aa61488ac88258 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 11 Jan 2024 15:37:44 +0100 Subject: [PATCH 231/285] move indexing specific code away from db --- db/db.ml | 47 ----------------------------------- db/db.mli | 11 --------- db/suffix_tree.mli | 11 --------- index/db_writer.ml | 48 ++++++++++++++++++++++++++++++++++++ index/db_writer.mli | 11 +++++++++ index/index.ml | 4 +-- index/load_doc.ml | 6 ++--- index/load_doc.mli | 2 +- {db => index}/suffix_tree.ml | 6 +++-- index/suffix_tree.mli | 11 +++++++++ 10 files changed, 80 insertions(+), 77 deletions(-) delete mode 100644 db/suffix_tree.mli create mode 100644 index/db_writer.ml create mode 100644 index/db_writer.mli rename {db => index}/suffix_tree.ml (98%) create mode 100644 index/suffix_tree.mli diff --git a/db/db.ml b/db/db.ml index adacff387c..94679d5471 100644 --- a/db/db.ml +++ b/db/db.ml @@ -10,50 +10,3 @@ type t = Storage.db = ; db_pos_types : String_automata.t Occurences.t ; db_neg_types : String_automata.t Occurences.t } - -type writer = - { writer_names : Suffix_tree.t - ; buffer_types : Suffix_tree.Buf.t - ; mutable writer_pos_types : Suffix_tree.t Occurences.t - ; mutable writer_neg_types : Suffix_tree.t Occurences.t - } - -let make () = - let buffer_names = Suffix_tree.Buf.make () in - let buffer_types = Suffix_tree.Buf.make () in - { writer_names = Suffix_tree.make buffer_names - ; buffer_types - ; writer_pos_types = Occurences.empty - ; writer_neg_types = Occurences.empty - } - -let export db = - { Storage.db_names = Suffix_tree.export db.writer_names - ; db_pos_types = Occurences.map Suffix_tree.export db.writer_pos_types - ; db_neg_types = Occurences.map Suffix_tree.export db.writer_neg_types - } - -let store db name elt ~count ~polarity = - let st = - match polarity with - | Type_polarity.Sign.Pos -> begin - try Occurences.find count db.writer_pos_types with - | Not_found -> - let st = Suffix_tree.make db.buffer_types in - db.writer_pos_types <- Occurences.add count st db.writer_pos_types ; - st - end - | Type_polarity.Sign.Neg -> begin - try Occurences.find count db.writer_neg_types with - | Not_found -> - let st = Suffix_tree.make db.buffer_types in - db.writer_neg_types <- Occurences.add count st db.writer_neg_types ; - st - end - in - Suffix_tree.add_suffixes st name elt - -let store_type_polarities db elt polarities = - Seq.iter (fun (path, count, polarity) -> store db ~count ~polarity path elt) polarities - -let store_word db word elt = Suffix_tree.add_suffixes db.writer_names word elt diff --git a/db/db.mli b/db/db.mli index 9c2e8df1e8..50035ab2ac 100644 --- a/db/db.mli +++ b/db/db.mli @@ -21,14 +21,3 @@ type t = Storage.db = The [Int_map.t] maps a number of occurences to a set of entries. See {!Occ}. [db_types] still is a suffix tree, so you can search in it only for text. The way we transform types into searchable text is in {!Type_polarity}. *) - -type writer -(** The type that builds a database. You can use it to add things to it, but - you cannot make queries on it. *) - -val make : unit -> writer -(** [make ()] returns an empty search database. *) - -val store_type_polarities : writer -> Entry.t -> Type_polarity.t Seq.t -> unit -val store_word : writer -> string -> Entry.t -> unit -val export : writer -> t diff --git a/db/suffix_tree.mli b/db/suffix_tree.mli deleted file mode 100644 index 1a473a37e7..0000000000 --- a/db/suffix_tree.mli +++ /dev/null @@ -1,11 +0,0 @@ -module Buf : sig - type t - - val make : unit -> t -end - -type t - -val make : Buf.t -> t -val add_suffixes : t -> string -> Entry.t -> unit -val export : t -> String_automata.t diff --git a/index/db_writer.ml b/index/db_writer.ml new file mode 100644 index 0000000000..fd5b155575 --- /dev/null +++ b/index/db_writer.ml @@ -0,0 +1,48 @@ +open Db + +type t = + { writer_names : Suffix_tree.t + ; buffer_types : Suffix_tree.Buf.t + ; mutable writer_pos_types : Suffix_tree.t Occurences.t + ; mutable writer_neg_types : Suffix_tree.t Occurences.t + } + +let make () = + let buffer_names = Suffix_tree.Buf.make () in + let buffer_types = Suffix_tree.Buf.make () in + { writer_names = Suffix_tree.make buffer_names + ; buffer_types + ; writer_pos_types = Occurences.empty + ; writer_neg_types = Occurences.empty + } + +let export db = + { Storage.db_names = Suffix_tree.export db.writer_names + ; db_pos_types = Occurences.map Suffix_tree.export db.writer_pos_types + ; db_neg_types = Occurences.map Suffix_tree.export db.writer_neg_types + } + +let store db name elt ~count ~polarity = + let st = + match polarity with + | Type_polarity.Sign.Pos -> begin + try Occurences.find count db.writer_pos_types with + | Not_found -> + let st = Suffix_tree.make db.buffer_types in + db.writer_pos_types <- Occurences.add count st db.writer_pos_types ; + st + end + | Type_polarity.Sign.Neg -> begin + try Occurences.find count db.writer_neg_types with + | Not_found -> + let st = Suffix_tree.make db.buffer_types in + db.writer_neg_types <- Occurences.add count st db.writer_neg_types ; + st + end + in + Suffix_tree.add_suffixes st name elt + +let store_type_polarities db elt polarities = + Seq.iter (fun (path, count, polarity) -> store db ~count ~polarity path elt) polarities + +let store_word db word elt = Suffix_tree.add_suffixes db.writer_names word elt diff --git a/index/db_writer.mli b/index/db_writer.mli new file mode 100644 index 0000000000..1a28477241 --- /dev/null +++ b/index/db_writer.mli @@ -0,0 +1,11 @@ +type t +(** The type that builds a database. You can use it to add things to it, but + you cannot make queries on it. *) + +val export : t -> Db.t + +val make : unit -> t +(** [make ()] returns an empty search database. *) + +val store_type_polarities : t -> Db.Entry.t -> Db.Type_polarity.t Seq.t -> unit +val store_word : t -> string -> Db.Entry.t -> unit diff --git a/index/index.ml b/index/index.ml index e851b6f73b..44e3ee7b80 100644 --- a/index/index.ml +++ b/index/index.ml @@ -17,7 +17,7 @@ let index_file register filename = let main files file_list index_docstring index_name type_search db_format db_filename = let module Storage = (val Db_store.storage_module db_format) in - let db = Db.make () in + let db = Db_writer.make () in let pkg = Db.Entry.Package.v ~name:"" ~version:"" in let register id () item = List.iter @@ -33,7 +33,7 @@ let main files file_list index_docstring index_name type_search db_format db_fil files @ (file_list |> In_channel.input_all |> String.split_on_char '\n') in List.iter (index_file register) files ; - let t = Db.export db in + let t = Db_writer.export db in Storage.save ~db:h t ; Storage.close_out h diff --git a/index/load_doc.ml b/index/load_doc.ml index 28e6c5838f..d0710e4e4a 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -63,11 +63,11 @@ let with_tokenizer str fn = go 0 let register_doc ~db elt doc_txt = - with_tokenizer doc_txt @@ fun word -> Db.store_word db word elt + with_tokenizer doc_txt @@ fun word -> Db_writer.store_word db word elt let register_full_name ~db (elt : Db.Entry.t) = let name = String.lowercase_ascii elt.name in - Db.store_word db name elt + Db_writer.store_word db name elt let searchable_type_of_constructor args res = let open Odoc_model.Lang in @@ -122,7 +122,7 @@ let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = let register_type_expr ~db elt typ = let type_polarities = Db.Type_polarity.of_typ ~any_is_poly:true ~all_names:true typ in - Db.store_type_polarities db elt type_polarities + Db_writer.store_type_polarities db elt type_polarities let register_kind ~db elt = let open Db.Entry in diff --git a/index/load_doc.mli b/index/load_doc.mli index 5b1591005b..df9b8f4189 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -1,5 +1,5 @@ val register_entry - : db:Db.writer + : db:Db_writer.t -> index_name:bool -> type_search:bool -> index_docstring:bool diff --git a/db/suffix_tree.ml b/index/suffix_tree.ml similarity index 98% rename from db/suffix_tree.ml rename to index/suffix_tree.ml index b8eae934dd..7f7745fed9 100644 --- a/db/suffix_tree.ml +++ b/index/suffix_tree.ml @@ -61,6 +61,8 @@ module Buf = struct start end +module Entry = Db.Entry + module Terminals = struct type t = Entry.t list @@ -342,7 +344,7 @@ let rec export ~cache ~cache_term node = let children = Array.of_list @@ List.map (fun (_, (_, child, _)) -> child) children in let children = if Array.length children = 0 then None else Some children in let node = - { String_automata.start = node.start; len = node.len; terminals; children } + { Db.String_automata.start = node.start; len = node.len; terminals; children } in let result = Uid.make (), node, min_child in Hashtbl.add cache key result ; @@ -353,4 +355,4 @@ let export { buffer; root = t } = let cache = Hashtbl.create 16 in let cache_term = Terminals_cache.create 16 in let _, t, _ = export ~cache ~cache_term t in - { String_automata.str; t } + { Db.String_automata.str; t } diff --git a/index/suffix_tree.mli b/index/suffix_tree.mli new file mode 100644 index 0000000000..986f145d66 --- /dev/null +++ b/index/suffix_tree.mli @@ -0,0 +1,11 @@ +module Buf : sig + type t + + val make : unit -> t +end + +type t + +val make : Buf.t -> t +val add_suffixes : t -> string -> Db.Entry.t -> unit +val export : t -> Db.String_automata.t From 8a3018bf745bb7fe3c8ea268a6e28edd8f6b39d3 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Thu, 11 Jan 2024 16:46:12 +0100 Subject: [PATCH 232/285] remove dependency to printf for smaller sherlodoc.js --- jsoo/main.ml | 21 +++++++++++---------- query/type_parser.mly | 9 ++++++++- test/cram/base_web.t | 2 +- test/cram/simple.t/run.t | 2 +- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/jsoo/main.ml b/jsoo/main.ml index 98e2394c11..ce03730009 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -1,10 +1,14 @@ let print_error e = - let open Jv.Error in - Printf.eprintf - "Error : %s %s\n%s%!" - (Jstr.to_string @@ name e) - (Jstr.to_string @@ message e) - (Jstr.to_string @@ stack e) + print_string + @@ String.concat + "" + [ "Error : " + ; Jstr.to_string @@ Jv.Error.name e + ; " " + ; Jstr.to_string @@ Jv.Error.message e + ; "\n" + ; Jstr.to_string @@ Jv.Error.stack e + ] let new_ cl = Jv.(new' (get global cl)) @@ -135,10 +139,7 @@ let search message = @@ let open Fut.Syntax in let+ db = db in - (* Here we catch any exception and print it. This allows us to keep running - and answer requests that do not trigger exceptions. *) - try Printexc.print (search message) db with - | _ -> () + search message db let main () = let module J' = Jstr in diff --git a/query/type_parser.mly b/query/type_parser.mly index f06836daf3..0838741d23 100644 --- a/query/type_parser.mly +++ b/query/type_parser.mly @@ -1,6 +1,13 @@ -(* Type expressions parser, with error correction to support partially written queries. *) +(* Type expressions parser, with error correction + to support incomplete / partially written user queries. *) %{ + module Printf = struct + (* Without the following placeholder, [menhir_fail] induces + a large dependency to [camlinternalFormat] in the js bundle. *) + let eprintf _ = () + end + open Db.Typexpr %} diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 708b666747..bfcac10cd2 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -31,7 +31,7 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 128K html/sherlodoc.js + 92K html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index c4883e6b96..bcf7e7598c 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 128K sherlodoc.js + 92K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html From fe5275256cb0f28ca0f7ac56ee697c2a776897b0 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Wed, 3 Jan 2024 10:24:19 +0100 Subject: [PATCH 233/285] fix missing www static files --- dune-project | 6 ++-- sherlodoc.opam | 5 ++- www/dune | 11 ++++-- www/packages.ml | 50 ++++++++++++---------------- {static => www/static}/bg.jpg | Bin {static => www/static}/favicon.ico | Bin {static => www/static}/packages.csv | 0 www/static/robots.txt | 3 ++ {static => www/static}/style.css | 0 www/www.ml | 14 +++++--- 10 files changed, 49 insertions(+), 40 deletions(-) rename {static => www/static}/bg.jpg (100%) rename {static => www/static}/favicon.ico (100%) rename {static => www/static}/packages.csv (100%) create mode 100644 www/static/robots.txt rename {static => www/static}/style.css (100%) diff --git a/dune-project b/dune-project index 208b0ec135..d6a267f9f4 100644 --- a/dune-project +++ b/dune-project @@ -1,4 +1,4 @@ -(lang dune 2.9) +(lang dune 3.5) (cram enable) @@ -8,8 +8,7 @@ (name sherlodoc) -(source - (github art-w/sherlodoc)) +(source (github art-w/sherlodoc)) (authors "Arthur Wendling") @@ -31,6 +30,7 @@ (odoc (>= 2.4.0)) (tyxml (>= 4.6.0)) (brr (>= 0.0.6)) + (ppx_blob (>= 0.7.2)) (alcotest :with-test)) (depopts (dream (>= 1.0.0~alpha5)) diff --git a/sherlodoc.opam b/sherlodoc.opam index d0a1b6897d..51ecb6c476 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -7,7 +7,7 @@ license: "MIT" homepage: "https://github.com/art-w/sherlodoc" bug-reports: "https://github.com/art-w/sherlodoc/issues" depends: [ - "dune" {>= "2.9"} + "dune" {>= "3.5"} "ocaml" {>= "4.14.0"} "cmdliner" {>= "1.2.0"} "decompress" {>= "1.5.3"} @@ -18,6 +18,7 @@ depends: [ "odoc" {>= "2.4.0"} "tyxml" {>= "4.6.0"} "brr" {>= "0.0.6"} + "ppx_blob" {>= "0.7.2"} "alcotest" {with-test} ] depopts: [ @@ -33,11 +34,9 @@ build: [ name "-j" jobs - "--promote-install-files=false" "@install" "@runtest" {with-test} "@doc" {with-doc} ] - ["dune" "install" "-p" name "--create-install-files" name] ] dev-repo: "git+https://github.com/art-w/sherlodoc.git" diff --git a/www/dune b/www/dune index f9728d72ef..4d6d725378 100644 --- a/www/dune +++ b/www/dune @@ -1,4 +1,11 @@ (library (name www) - (optional) - (libraries cmdliner dream tyxml db db_store query)) + (libraries cmdliner dream tyxml db db_store query) + (preprocess + (pps ppx_blob)) + (preprocessor_deps + static/bg.jpg + static/favicon.ico + static/packages.csv + static/robots.txt + static/style.css)) diff --git a/www/packages.ml b/www/packages.ml index 06a108c9d5..df8f9d4f85 100644 --- a/www/packages.ml +++ b/www/packages.ml @@ -105,37 +105,31 @@ let unescape str = done ; Buffer.contents buf -let load filename = - let h = open_in filename in - let rec go acc = - match input_line h with - | exception End_of_file -> acc - | line -> - let package = - match String.split_on_char '\t' line with - | [ category; name; description ] -> - { category = pretty category; name; description = unescape description } - | [ name; description ] -> - { category = pretty ""; name; description = unescape description } - | _ -> failwith (Printf.sprintf "invalid package: %S" line) - in - let set = - try M.find package.category acc with - | Not_found -> S.empty - in - let set = S.add package set in - let acc = M.add package.category set acc in - go acc +let parse_str str = + let parse_line acc line = + let package = + match String.split_on_char '\t' line with + | [ category; name; description ] -> + { category = pretty category; name; description = unescape description } + | [ name; description ] -> + { category = pretty ""; name; description = unescape description } + | _ -> failwith (Printf.sprintf "invalid package: %s" line) + in + let set = + try M.find package.category acc with + | Not_found -> S.empty + in + let set = S.add package set in + M.add package.category set acc in - let result = go M.empty in - close_in h ; - result + List.fold_left parse_line M.empty + @@ List.filter (( <> ) "") + @@ String.split_on_char '\n' str + +let packages () = parse_str [%blob "www/static/packages.csv"] let packages () = - List.fold_left - (fun acc p -> M.remove p acc) - (load "./static/packages.csv") - [ "Tezos"; "conf" ] + List.fold_left (fun acc p -> M.remove p acc) (packages ()) [ "Tezos"; "conf" ] open Tyxml.Html diff --git a/static/bg.jpg b/www/static/bg.jpg similarity index 100% rename from static/bg.jpg rename to www/static/bg.jpg diff --git a/static/favicon.ico b/www/static/favicon.ico similarity index 100% rename from static/favicon.ico rename to www/static/favicon.ico diff --git a/static/packages.csv b/www/static/packages.csv similarity index 100% rename from static/packages.csv rename to www/static/packages.csv diff --git a/www/static/robots.txt b/www/static/robots.txt new file mode 100644 index 0000000000..e223f09833 --- /dev/null +++ b/www/static/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: /$ +Disallow: / diff --git a/static/style.css b/www/static/style.css similarity index 100% rename from static/style.css rename to www/static/style.css diff --git a/www/www.ml b/www/www.ml index 436e9db567..c1f74feb21 100644 --- a/www/www.ml +++ b/www/www.ml @@ -78,6 +78,12 @@ let cors_options = Dream.add_header response "Access-Control-Allow-Headers" "*" ; response) +let static ctype contents = Dream.respond ~headers:[ "Content-Type", ctype ] contents +let style_css _ = static "text/css" [%blob "www/static/style.css"] +let favicon_ico _ = static "image/x-icon" [%blob "www/static/favicon.ico"] +let robots_txt _ = static "text/plain" [%blob "www/static/robots.txt"] +let bg_jpg _ = static "image/jpeg" [%blob "www/static/bg.jpg"] + let main cache_max_age db_format db_filename = let module Storage = (val Db_store.storage_module db_format) in let shards = Storage.load db_filename in @@ -96,10 +102,10 @@ let main cache_max_age db_format db_filename = (root (fun params -> let+ result = api ~shards params in string_of_tyxml' result)) - ; Dream.get "/s.css" (Dream.from_filesystem "static" "style.css") - ; Dream.get "/robots.txt" (Dream.from_filesystem "static" "robots.txt") - ; Dream.get "/favicon.ico" (Dream.from_filesystem "static" "favicon.ico") - ; Dream.get "/bg.jpg" (Dream.from_filesystem "static" "bg.jpg") + ; Dream.get "/s.css" style_css + ; Dream.get "/robots.txt" robots_txt + ; Dream.get "/favicon.ico" favicon_ico + ; Dream.get "/bg.jpg" bg_jpg ; cors_options ] From 496d16bc265f303119bee253a653d629f80e1c2b Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 12 Jan 2024 17:07:55 +0100 Subject: [PATCH 234/285] add cli command to produce sherlodoc.js for dune/odoc integration --- cli/dune | 5 ++++- cli/main.ml | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/cli/dune b/cli/dune index 7be3cf6dde..778a083898 100644 --- a/cli/dune +++ b/cli/dune @@ -13,4 +13,7 @@ serve.ml from (www -> serve.available.ml) - (!www -> serve.unavailable.ml)))) + (!www -> serve.unavailable.ml))) + (preprocess + (pps ppx_blob)) + (preprocessor_deps ../jsoo/sherlodoc.js)) diff --git a/cli/main.ml b/cli/main.ml index 745f6be0cd..5951155909 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -60,9 +60,23 @@ let cmd_serve = let info = Cmd.info "serve" ~doc in Cmd.v info (with_db Serve.term db_path) +let cmd_jsoo = + let doc = "For dune/odoc integration, sherlodoc compiled as javascript" in + let info = Cmd.info "js" ~doc in + let target = + let doc = "Name of the file to create" in + Arg.(value & pos 0 string "" & info [] ~docv:"QUERY" ~doc) + in + let emit_js_dep filename = + let close, h = if filename = "" then false, stdout else true, open_out filename in + output_string h [%blob "jsoo/sherlodoc.js"] ; + if close then close_out h + in + Cmd.v info Term.(const emit_js_dep $ target) + let cmd = let doc = "Sherlodoc" in let info = Cmd.info "sherlodoc" ~doc in - Cmd.group info [ cmd_search; cmd_index; cmd_serve ] + Cmd.group info [ cmd_search; cmd_index; cmd_serve; cmd_jsoo ] let () = exit (Cmd.eval cmd) From 99aec7322a2c63b77171f9114fcf2f0e4304645e Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 12 Jan 2024 20:09:25 +0100 Subject: [PATCH 235/285] lower ocaml version requirement to 4.08 --- cli/search.ml | 2 +- dune-project | 3 ++- index/index.ml | 11 ++++++++-- index/load_doc.ml | 8 +++++++- index/suffix_tree.ml | 7 ++++++- query/dynamic_cost.ml | 43 +++++++++++++--------------------------- query/name_cost.ml | 23 +++++++++++++++++++++ query/query.ml | 11 +++++++++- query/succ.ml | 10 +++++++++- query/test/test_array.ml | 4 ++-- query/type_distance.ml | 2 +- sherlodoc.opam | 3 ++- 12 files changed, 86 insertions(+), 41 deletions(-) create mode 100644 query/name_cost.ml diff --git a/cli/search.ml b/cli/search.ml index 4b8bfdbf97..956298570e 100644 --- a/cli/search.ml +++ b/cli/search.ml @@ -51,7 +51,7 @@ let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db = | query -> search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query ; search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db - | None -> print_endline "[Search session ended]" + | exception End_of_file -> Printf.printf "\n%!" let search query print_cost no_rhs static_sort limit pretty_query db_format db_filename = let module Storage = (val Db_store.storage_module db_format) in diff --git a/dune-project b/dune-project index d6a267f9f4..5bc7214940 100644 --- a/dune-project +++ b/dune-project @@ -20,8 +20,9 @@ (name sherlodoc) (synopsis "Fuzzy search in OCaml documentation") (depends - (ocaml (>= 4.14.0)) + (ocaml (>= 4.0.8)) (cmdliner (>= 1.2.0)) + (bigstringaf (>= 0.9.1)) (decompress (>= 1.5.3)) (base64 (>= 3.5.1)) (fpath (>= 0.7.3)) diff --git a/index/index.ml b/index/index.ml index 44e3ee7b80..ecb3cfd72f 100644 --- a/index/index.ml +++ b/index/index.ml @@ -29,8 +29,15 @@ let main files file_list index_docstring index_name type_search db_format db_fil match file_list with | None -> files | Some file_list -> - let file_list = open_in file_list in - files @ (file_list |> In_channel.input_all |> String.split_on_char '\n') + let h = open_in file_list in + let rec read_all acc = + match Stdlib.input_line h with + | exception End_of_file -> List.rev acc + | line -> read_all (line :: acc) + in + let other_files = read_all [] in + close_in h ; + files @ other_files in List.iter (index_file register) files ; let t = Db_writer.export db in diff --git a/index/load_doc.ml b/index/load_doc.ml index d0710e4e4a..23c1e691dd 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -2,6 +2,12 @@ module Entry = Db.Entry module Db_common = Db module ModuleName = Odoc_model.Names.ModuleName +let string_starts_with ~prefix str = + let rec go i = + if i >= String.length prefix then true else prefix.[i] = str.[i] && go (i + 1) + in + String.length prefix <= String.length str && go 0 + let generic_cost ~ignore_no_doc name has_doc = (* name length is important not because short identifier are better in the abstract, but because the shortest result will be close to the query, as @@ -9,7 +15,7 @@ let generic_cost ~ignore_no_doc name has_doc = (String.length name * 6) (* + (5 * List.length path) TODO : restore depth based ordering *) + (if ignore_no_doc || has_doc then 0 else 400) - + if String.starts_with ~prefix:"Stdlib." name then 0 else 100 + + if string_starts_with ~prefix:"Stdlib." name then 0 else 100 let kind_cost = function | Entry.Kind.Doc -> 400 diff --git a/index/suffix_tree.ml b/index/suffix_tree.ml index 7f7745fed9..87a8415f62 100644 --- a/index/suffix_tree.ml +++ b/index/suffix_tree.ml @@ -75,7 +75,12 @@ module Terminals = struct | _ -> x :: xs let hash = Hashtbl.hash - let equal = List.equal Entry.equal + + let rec equal xs ys = + match xs, ys with + | [], [] -> true + | x :: xs, y :: ys when Entry.equal x y -> equal xs ys + | _ -> false let mem x = function | y :: _ -> Entry.equal x y diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index f6ae3a7ad9..efaf984a6e 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -30,44 +30,29 @@ module Reasoning = struct | Lowercase | Doc - let rec is_prefix_at ~sub i s j = - if i >= String.length sub - then true - else if sub.[i] = s.[j] - then is_prefix_at ~sub (i + 1) s (j + 1) - else false - - let is_substring ~sub s = - let rec go j = - if j + String.length sub > String.length s - then false - else if is_prefix_at ~sub 0 s j - then true - else go (j + 1) - in - go 0 - let with_word query_word name = let low_query_word = String.lowercase_ascii query_word in let has_case = low_query_word <> query_word in let name = if not has_case then String.lowercase_ascii name else name in - if String.equal query_word name || String.ends_with ~suffix:("." ^ query_word) name + if String.equal query_word name + || Name_cost.ends_with ~suffix:("." ^ query_word) name then DotSuffix - else if String.starts_with ~prefix:query_word name - || String.ends_with ~suffix:query_word name + else if Name_cost.starts_with ~prefix:query_word name + || Name_cost.ends_with ~suffix:query_word name then PrefixSuffix - else if is_substring ~sub:("(" ^ query_word) name - || is_substring ~sub:(query_word ^ ")") name + else if Name_cost.is_substring ~sub:("(" ^ query_word) name + || Name_cost.is_substring ~sub:(query_word ^ ")") name then PrefixSuffix - else if is_substring ~sub:("." ^ query_word) name - || is_substring ~sub:(query_word ^ ".") name + else if Name_cost.is_substring ~sub:("." ^ query_word) name + || Name_cost.is_substring ~sub:(query_word ^ ".") name then SubDot - else if is_substring ~sub:("_" ^ query_word) name - || is_substring ~sub:(query_word ^ "_") name + else if Name_cost.is_substring ~sub:("_" ^ query_word) name + || Name_cost.is_substring ~sub:(query_word ^ "_") name then SubUnderscore - else if is_substring ~sub:query_word name + else if Name_cost.is_substring ~sub:query_word name then Sub - else if has_case && is_substring ~sub:low_query_word (String.lowercase_ascii name) + else if has_case + && Name_cost.is_substring ~sub:low_query_word (String.lowercase_ascii name) then Lowercase else (* Matches only in the docstring are always worse *) Doc @@ -107,7 +92,7 @@ module Reasoning = struct let is_stdlib entry = let open Entry in - String.starts_with ~prefix:"Stdlib." entry.name + Name_cost.starts_with ~prefix:"Stdlib." entry.name let name_length entry = String.length entry.Entry.name let is_from_module_type entry = entry.Entry.is_from_module_type diff --git a/query/name_cost.ml b/query/name_cost.ml new file mode 100644 index 0000000000..48f29ef93d --- /dev/null +++ b/query/name_cost.ml @@ -0,0 +1,23 @@ +let rec is_prefix_at ~sub i s j = + if i >= String.length sub + then true + else if sub.[i] = s.[j] + then is_prefix_at ~sub (i + 1) s (j + 1) + else false + +let is_substring ~sub s = + let rec go j = + if j + String.length sub > String.length s + then false + else if is_prefix_at ~sub 0 s j + then true + else go (j + 1) + in + go 0 + +let starts_with ~prefix str = + String.length prefix <= String.length str && is_prefix_at ~sub:prefix 0 str 0 + +let ends_with ~suffix str = + let j = String.length str - String.length suffix in + j >= 0 && is_prefix_at ~sub:suffix 0 str j diff --git a/query/query.ml b/query/query.ml index 2017268c2d..b079e5140d 100644 --- a/query/query.ml +++ b/query/query.ml @@ -83,6 +83,15 @@ let match_packages ~packages results = | [] -> results | _ -> Seq.filter (match_packages ~packages) results +let rec seq_take n xs () = + if n = 0 + then Seq.Nil + else begin + match xs () with + | Seq.Nil -> Seq.Nil + | Seq.Cons (x, xs) -> Seq.Cons (x, seq_take (n - 1) xs) + end + let search ~shards ?(dynamic_sort = true) params = let limit = params.limit in let query = Parser.of_string params.query in @@ -94,6 +103,6 @@ let search ~shards ?(dynamic_sort = true) params = let query = Dynamic_cost.of_query query in List.of_seq @@ Top_results.of_seq ~query ~limit results end - else List.of_seq @@ Seq.take params.limit results + else List.of_seq @@ seq_take params.limit results let pretty params = Parser.(to_string @@ of_string params.query) diff --git a/query/succ.ml b/query/succ.ml index b82182ee91..57573e36de 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -100,6 +100,14 @@ let rec first t = let elt_r, r = first r in best_opt elt_l elt_r, Union (l, r) +let seq_of_dispenser fn = + let rec go () = + match fn () with + | None -> Seq.Nil + | Some x -> Seq.Cons (x, go) + in + go + let to_seq t = let state = ref None in let loop () = @@ -114,4 +122,4 @@ let to_seq t = state := Some (elt, t) ; Some elt in - Seq.of_dispenser loop + seq_of_dispenser loop diff --git a/query/test/test_array.ml b/query/test/test_array.ml index 280dfdf51c..04db842956 100644 --- a/query/test/test_array.ml +++ b/query/test/test_array.ml @@ -36,7 +36,7 @@ let () = Random.init 123 let random_array size = let r = - List.init size (fun _ -> Random.full_int (size * 2)) + List.init size (fun _ -> Random.int (size * 2)) |> List.sort_uniq Int.compare |> Array.of_list in @@ -44,7 +44,7 @@ let random_array size = let tests_arr name test = List.init 50 (fun i -> - let elt = Random.full_int ((i * 2) + 1) in + let elt = Random.int ((i * 2) + 1) in let arr = random_array i in let arr_string = if i <= 5 diff --git a/query/type_distance.ml b/query/type_distance.ml index c99dc541e1..66da1d024e 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -124,7 +124,7 @@ let distance xs ys = | [], _ -> 0 | [ "_" ], _ -> 0 | _, [] -> List.length xs - | x :: xs, y :: ys when String.ends_with ~suffix:x y -> memo (i + 1) (j + 1) xs ys + | x :: xs, y :: ys when Name_cost.ends_with ~suffix:x y -> memo (i + 1) (j + 1) xs ys | _, "->1" :: ys -> memo i (j + 1) xs ys | "->1" :: xs, _ -> 1 + memo (i + 1) j xs ys | _ :: xs', _ :: ys' -> diff --git a/sherlodoc.opam b/sherlodoc.opam index 51ecb6c476..9fc84d1ec7 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -8,8 +8,9 @@ homepage: "https://github.com/art-w/sherlodoc" bug-reports: "https://github.com/art-w/sherlodoc/issues" depends: [ "dune" {>= "3.5"} - "ocaml" {>= "4.14.0"} + "ocaml" {>= "4.0.8"} "cmdliner" {>= "1.2.0"} + "bigstringaf" {>= "0.9.1"} "decompress" {>= "1.5.3"} "base64" {>= "3.5.1"} "fpath" {>= "0.7.3"} From a0f215cdc2a1219d53463c2badbb5a2b24048cc1 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 13 Jan 2024 11:33:49 +0100 Subject: [PATCH 236/285] fix memory leaks --- db/typexpr.ml | 21 +++---------- db/typexpr.mli | 9 ++---- index/db_writer.ml | 3 ++ index/db_writer.mli | 1 + index/load_doc.ml | 56 ++++++++++++++-------------------- index/type_cache.ml | 23 ++++++++++++++ index/type_cache.mli | 4 +++ query/test/test_type_parser.ml | 13 ++++---- query/type_distance.ml | 26 +--------------- query/type_parser.mly | 12 ++++---- 10 files changed, 74 insertions(+), 94 deletions(-) create mode 100644 index/type_cache.ml create mode 100644 index/type_cache.mli diff --git a/db/typexpr.ml b/db/typexpr.ml index 34f0052c00..eb93c17ab5 100644 --- a/db/typexpr.ml +++ b/db/typexpr.ml @@ -6,25 +6,10 @@ type t = | Any | Unhandled -let table = Hashtbl.create 256 - -let cache t = - match Hashtbl.find_opt table t with - | Some t -> t - | None -> - Hashtbl.add table t t ; - t - -let any = Any -let unhandled = Unhandled -let arrow a b = cache (Arrow (a, b)) -let constr name args = cache (Constr (name, args)) -let poly name = cache (Poly name) - let tuple = function - | [] -> any + | [] -> Any | [ x ] -> x - | xs -> cache (Tuple xs) + | xs -> Tuple xs let rec show = function | Arrow (a, b) -> show_parens a ^ " -> " ^ show b @@ -53,3 +38,5 @@ and show_tuple = function | x :: xs -> show_parens x ^ " * " ^ show_tuple xs let size typ = typ |> show |> String.length +let equal = Stdlib.( = ) +let hash = Hashtbl.hash diff --git a/db/typexpr.mli b/db/typexpr.mli index 592c06ab01..4c665aadcf 100644 --- a/db/typexpr.mli +++ b/db/typexpr.mli @@ -1,4 +1,4 @@ -type t = private +type t = | Arrow of t * t | Constr of string * t list | Tuple of t list @@ -6,11 +6,8 @@ type t = private | Any | Unhandled -val arrow : t -> t -> t -val constr : string -> t list -> t val tuple : t list -> t -val poly : string -> t -val any : t -val unhandled : t val size : t -> int val show : t -> string +val equal : t -> t -> bool +val hash : t -> int diff --git a/index/db_writer.ml b/index/db_writer.ml index fd5b155575..e69c9dcb4f 100644 --- a/index/db_writer.ml +++ b/index/db_writer.ml @@ -5,6 +5,7 @@ type t = ; buffer_types : Suffix_tree.Buf.t ; mutable writer_pos_types : Suffix_tree.t Occurences.t ; mutable writer_neg_types : Suffix_tree.t Occurences.t + ; type_cache : Type_cache.t } let make () = @@ -14,6 +15,7 @@ let make () = ; buffer_types ; writer_pos_types = Occurences.empty ; writer_neg_types = Occurences.empty + ; type_cache = Type_cache.make () } let export db = @@ -46,3 +48,4 @@ let store_type_polarities db elt polarities = Seq.iter (fun (path, count, polarity) -> store db ~count ~polarity path elt) polarities let store_word db word elt = Suffix_tree.add_suffixes db.writer_names word elt +let type_of_odoc ~db ty = Type_cache.of_odoc ~cache:db.type_cache ty diff --git a/index/db_writer.mli b/index/db_writer.mli index 1a28477241..f3a221ac1e 100644 --- a/index/db_writer.mli +++ b/index/db_writer.mli @@ -7,5 +7,6 @@ val export : t -> Db.t val make : unit -> t (** [make ()] returns an empty search database. *) +val type_of_odoc : db:t -> Odoc_model.Lang.TypeExpr.t -> Db.Typexpr.t val store_type_polarities : t -> Db.Entry.t -> Db.Type_polarity.t Seq.t -> unit val store_word : t -> string -> Db.Entry.t -> unit diff --git a/index/load_doc.ml b/index/load_doc.ml index 23c1e691dd..ea64497416 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -34,17 +34,6 @@ let cost ~name ~kind ~doc_html ~rhs = let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) -let rec typ_of_odoc_typ otyp = - let open Db.Typexpr in - match otyp with - | Odoc_model.Lang.TypeExpr.Var _str -> any - | Any -> any - | Arrow (_lbl, left, right) -> arrow (typ_of_odoc_typ left) (typ_of_odoc_typ right) - | Constr (name, args) -> - constr (Typename.to_string name) (List.map typ_of_odoc_typ args) - | Tuple li -> tuple (List.map typ_of_odoc_typ li) - | _ -> unhandled - let with_tokenizer str fn = let str = String.lowercase_ascii str in let buf = Buffer.create 16 in @@ -78,11 +67,12 @@ let register_full_name ~db (elt : Db.Entry.t) = let searchable_type_of_constructor args res = let open Odoc_model.Lang in match args with - | TypeDecl.Constructor.Tuple args -> - (match args with - | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) - | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) - | _ -> res) + | TypeDecl.Constructor.Tuple args -> begin + match args with + | _ :: _ :: _ -> TypeExpr.(Arrow (None, Tuple args, res)) + | [ arg ] -> TypeExpr.(Arrow (None, arg, res)) + | _ -> res + end | TypeDecl.Constructor.Record fields -> List.fold_left (fun res field -> @@ -93,37 +83,37 @@ let searchable_type_of_constructor args res = fields let searchable_type_of_record parent_type type_ = - let open Odoc_model.Lang in - TypeExpr.Arrow (None, parent_type, type_) + Odoc_model.Lang.TypeExpr.Arrow (None, parent_type, type_) -let convert_kind (Odoc_search.Entry.{ kind; _ } as entry) = +let convert_kind ~db (Odoc_search.Entry.{ kind; _ } as entry) = let open Odoc_search.Entry in match kind with | TypeDecl _ -> Entry.Kind.Type_decl (Odoc_search.Html.typedecl_params_of_entry entry) - | Module -> Entry.Kind.Module | Value { value = _; type_ } -> - let typ = typ_of_odoc_typ type_ in + let typ = Db_writer.type_of_odoc ~db type_ in Entry.Kind.Val typ | Constructor { args; res } -> - let searchable_type = searchable_type_of_constructor args res in - let typ = typ_of_odoc_typ searchable_type in + let typ = searchable_type_of_constructor args res in + let typ = Db_writer.type_of_odoc ~db typ in Entry.Kind.Constructor typ + | ExtensionConstructor { args; res } -> + let typ = searchable_type_of_constructor args res in + let typ = Db_writer.type_of_odoc ~db typ in + Entry.Kind.Extension_constructor typ + | Exception { args; res } -> + let typ = searchable_type_of_constructor args res in + let typ = Db_writer.type_of_odoc ~db typ in + Entry.Kind.Exception typ | Field { mutable_ = _; parent_type; type_ } -> - let typ = type_ |> searchable_type_of_record parent_type |> typ_of_odoc_typ in + 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 - | Exception { args; res } -> - let searchable_type = searchable_type_of_constructor args res in - let typ = typ_of_odoc_typ searchable_type in - Entry.Kind.Exception typ | Class_type _ -> Class_type | Method _ -> Method | Class _ -> Class | TypeExtension _ -> Type_extension - | ExtensionConstructor { args; res } -> - let searchable_type = searchable_type_of_constructor args res in - let typ = typ_of_odoc_typ searchable_type in - Entry.Kind.Extension_constructor typ + | Module -> Entry.Kind.Module | ModuleType -> Module_type let register_type_expr ~db elt typ = @@ -188,7 +178,7 @@ let register_entry | _ -> doc_html in let rhs = Html.rhs_of_kind kind in - let kind = convert_kind entry in + let kind = convert_kind ~db entry in let name = match kind with | Doc -> prefixname id diff --git a/index/type_cache.ml b/index/type_cache.ml new file mode 100644 index 0000000000..6d092ee30c --- /dev/null +++ b/index/type_cache.ml @@ -0,0 +1,23 @@ +open Db.Typexpr +module H = Hashtbl.Make (Db.Typexpr) + +type t = Db.Typexpr.t -> Db.Typexpr.t + +let make () = + let table = H.create 256 in + fun t -> + match H.find_opt table t with + | Some t -> t + | None -> + H.add table t t ; + t + +let rec of_odoc ~cache otyp = + match otyp with + | Odoc_model.Lang.TypeExpr.Var _str -> Any + | Any -> Any + | Arrow (_lbl, left, right) -> cache (Arrow (of_odoc ~cache left, of_odoc ~cache right)) + | Constr (name, args) -> + cache (Constr (Typename.to_string name, List.map (of_odoc ~cache) args)) + | Tuple li -> cache (Tuple (List.map (of_odoc ~cache) li)) + | _ -> Unhandled diff --git a/index/type_cache.mli b/index/type_cache.mli new file mode 100644 index 0000000000..2d7d6efaea --- /dev/null +++ b/index/type_cache.mli @@ -0,0 +1,4 @@ +type t + +val make : unit -> t +val of_odoc : cache:t -> Odoc_model.Lang.TypeExpr.t -> Db.Typexpr.t diff --git a/query/test/test_type_parser.ml b/query/test/test_type_parser.ml index 02b62fcc58..9835dc84e6 100644 --- a/query/test/test_type_parser.ml +++ b/query/test/test_type_parser.ml @@ -1,14 +1,14 @@ open Db.Typexpr let random_elt arr = arr.(Random.int (Array.length arr)) -let random_poly () = poly (random_elt [| "a"; "b"; "c"; "d"; "e" |]) +let random_poly () = Poly (random_elt [| "a"; "b"; "c"; "d"; "e" |]) let random_constr () = - constr (random_elt [| "float"; "int"; "string"; "foo"; "bar"; "t" |]) [] + Constr (random_elt [| "float"; "int"; "string"; "foo"; "bar"; "t" |], []) let rec random_type size = match size with - | 0 | 1 -> random_elt [| random_poly; random_constr; (fun () -> any) |] () + | 0 | 1 -> random_elt [| random_poly; random_constr; (fun () -> Any) |] () | (2 | 3 | 4) when Random.bool () -> random_constr_params size | _ when Random.int 100 < 20 -> let n = 2 + Random.int 3 in @@ -16,13 +16,12 @@ let rec random_type size = | _ when Random.int 100 < 5 -> random_constr_params size | _ -> let size = size / 2 in - arrow (random_type size) (random_type size) + Arrow (random_type size, random_type size) and random_constr_params size = let n_params = 1 + Random.int 3 in - constr - (random_elt [| "list"; "option"; "t"; "result"; "array" |]) - (List.init n_params (fun _i -> random_type (size / n_params))) + let name = random_elt [| "list"; "option"; "t"; "result"; "array" |] in + Constr (name, List.init n_params (fun _i -> random_type (size / n_params))) open Query.Private diff --git a/query/type_distance.ml b/query/type_distance.ml index 66da1d024e..760647535f 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -79,31 +79,7 @@ end = struct @@ args | Unhandled -> [] - let hcons_tbl = Hashtbl.create 16 - let uid_generator = ref 0 - - let rec hcons = function - | [] -> -1, [] - | x :: xs -> - let uid_xs, xs = hcons xs in - (match Hashtbl.find hcons_tbl (uid_xs, x) with - | xxs -> xxs - | exception Not_found -> - let uid = !uid_generator in - uid_generator := uid + 1 ; - let result = uid, x :: xs in - Hashtbl.add hcons_tbl (uid_xs, x) result ; - result) - - (** [of_typ t] is a [string list list] representing - the type [t]. It allows to compute the distance between two types. It is - stored in the database to sort results once they are obtained. *) - let of_typ ~ignore_any typ = - List.map - (fun xs -> - let _, xs = hcons xs in - xs) - (of_typ ~ignore_any ~prefix:[] ~sgn:Pos typ) + let of_typ ~ignore_any t = of_typ ~ignore_any ~prefix:[] ~sgn:Pos t end let distance xs ys = diff --git a/query/type_parser.mly b/query/type_parser.mly index 0838741d23..7e4528051d 100644 --- a/query/type_parser.mly +++ b/query/type_parser.mly @@ -28,7 +28,7 @@ main: typ: | t=typ2 { t } - | a=typ2 ARROW b=typ { arrow a b } + | a=typ2 ARROW b=typ { Arrow (a, b) } ; typ2: @@ -36,17 +36,17 @@ typ2: ; typ1: - | { any } + | { Any } | ts=typs { tuple ts } | ts=typs w=WORD ws=list(WORD) { - List.fold_left (fun acc w -> constr w [acc]) (constr w ts) ws + List.fold_left (fun acc w -> Constr (w, [acc])) (Constr (w, ts)) ws } ; typ0: - | ANY { any } - | w=POLY { poly w } - | w=WORD { constr w [] } + | ANY { Any } + | w=POLY { Poly w } + | w=WORD { Constr (w, []) } ; typs: From ff9e9d2d7bfdb178e40a251621561b1efd4259da Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 13 Jan 2024 13:50:45 +0100 Subject: [PATCH 237/285] improve fuzzy type search --- db/string_automata.ml | 87 ++++++++++++++++++++++++++++++++++-------- db/string_automata.mli | 1 + db/type_polarity.ml | 49 +++++++++--------------- db/type_polarity.mli | 2 +- index/load_doc.ml | 2 +- query/query.ml | 25 ++++++------ test/cram/base_web.t | 4 +- test/cram/cli.t/run.t | 1 + 8 files changed, 109 insertions(+), 62 deletions(-) diff --git a/db/string_automata.ml b/db/string_automata.ml index 87ea165520..e26338dc61 100644 --- a/db/string_automata.ml +++ b/db/string_automata.ml @@ -13,16 +13,16 @@ type t = let array_find ~str chr arr = let rec go i = if i >= Array.length arr - then raise Not_found + then None else begin let node = arr.(i) in - if chr = str.[node.start - 1] then node else go (i + 1) + if chr = str.[node.start - 1] then Some node else go (i + 1) end in go 0 let array_find ~str chr = function - | None -> raise Not_found + | None -> None | Some arr -> array_find ~str chr arr let lcp i_str i j_str j j_len = @@ -39,27 +39,84 @@ let lcp i_str i j_str j j_len = let rec find ~str node pattern i = if i >= String.length pattern - then node - else ( - let chr = pattern.[i] in - let child = array_find ~str chr node.children in - find_lcp ~str child pattern (i + 1)) + then Some node + else begin + match array_find ~str pattern.[i] node.children with + | None -> None + | Some child -> find_lcp ~str child pattern (i + 1) + end and find_lcp ~str child pattern i = let n = lcp pattern i str child.start child.len in if i + n = String.length pattern - then { child with start = child.start + n } + then Some { child with start = child.start + n; len = child.len - n } else if n = child.len then find ~str child pattern (i + n) - else raise Not_found + else None let find t pattern = - let child = find ~str:t.str t.t pattern 0 in - { str = t.str; t = child } + match find_lcp ~str:t.str t.t pattern 0 with + | None -> None + | Some child -> Some { str = t.str; t = child } -let find t pattern = - try Some (find t pattern) with - | Not_found -> None +let advance node = + assert (node.len >= 1) ; + { node with start = node.start + 1; len = node.len - 1 } + +let stepback node = + assert (node.len >= 0) ; + { node with start = node.start - 1; len = node.len + 1 } + +let rec find_skip ~spaces t pattern = + let skip () = + let node = t.t in + if node.len >= 1 + then begin + let spaces = spaces + if t.str.[node.start] = ' ' then 1 else 0 in + if spaces > 1 then [] else find_skip ~spaces { t with t = advance t.t } pattern + end + else begin + match node.children with + | None -> [] + | Some children -> + snd + @@ List.fold_left + (fun (i, acc) child -> + let xs = find_skip ~spaces { t with t = stepback child } pattern in + i + 1, List.rev_append xs acc) + (0, []) + @@ Array.to_list children + end + in + if spaces = 0 + then skip () + else begin + let skip = skip () in + match find t pattern with + | Some here -> here :: skip + | None -> skip + end + +let find_star t pattern = + let rec go t = function + | [] -> [ t ] + | p :: ps -> begin + let ts = find_skip ~spaces:0 t p in + List.fold_left + (fun acc t -> + let xs = go t ps in + List.rev_append xs acc) + [] + ts + end + in + match String.split_on_char ' ' pattern with + | [] -> [] + | p :: ps -> begin + match find t p with + | None -> [] + | Some t -> go t ps + end let min_opt a b = match a, b with diff --git a/db/string_automata.mli b/db/string_automata.mli index 03f11b71b4..2f4d6edb14 100644 --- a/db/string_automata.mli +++ b/db/string_automata.mli @@ -14,4 +14,5 @@ type t = } val find : t -> string -> t option +val find_star : t -> string -> t list val minimum : t -> Entry.t diff --git a/db/type_polarity.ml b/db/type_polarity.ml index 1ed8d6f235..75ed50efbd 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -16,41 +16,28 @@ end let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst -let rec tails = function - | [] -> [] - | _ :: xs as lst -> lst :: tails xs - type t = string * int * Sign.t -let all_type_names name = - name |> String.split_on_char '.' |> tails |> List.map (String.concat ".") - -let rec of_typ ~any_is_poly ~all_names ~prefix ~sgn = function +let rec of_typ ~any_is_poly ~prefix ~sgn = function | Poly _ -> [ sgn, "POLY" :: prefix ] | Any -> if any_is_poly then [ sgn, "POLY" :: prefix ] else [ sgn, prefix ] | Arrow (a, b) -> List.rev_append - (of_typ ~any_is_poly ~all_names ~prefix ~sgn:(Sign.not sgn) a) - (of_typ ~any_is_poly ~all_names ~prefix ~sgn b) - | Constr (name, args) -> - name - |> (if all_names then all_type_names else fun name -> [ name ]) - |> List.map (fun name -> - let prefix = name :: prefix in - begin - match args with - | [] -> [ sgn, prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - of_typ ~any_is_poly ~all_names ~prefix ~sgn arg) - args - end) - |> rev_concat - | Tuple args -> - rev_concat @@ List.map (of_typ ~any_is_poly ~all_names ~prefix ~sgn) @@ args + (of_typ ~any_is_poly ~prefix ~sgn:(Sign.not sgn) a) + (of_typ ~any_is_poly ~prefix ~sgn b) + | Constr (name, args) -> begin + let prefix = name :: prefix in + match args with + | [] -> [ sgn, prefix ] + | _ -> + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = string_of_int i :: prefix in + of_typ ~any_is_poly ~prefix ~sgn arg) + args + end + | Tuple args -> rev_concat @@ List.map (of_typ ~any_is_poly ~prefix ~sgn) @@ args | Unhandled -> [] let regroup lst = @@ -65,9 +52,9 @@ let regroup lst = lst ; Hashtbl.to_seq h -let of_typ ~any_is_poly ~all_names t = +let of_typ ~any_is_poly t = t - |> of_typ ~any_is_poly ~all_names ~prefix:[] ~sgn:Pos + |> of_typ ~any_is_poly ~prefix:[] ~sgn:Pos |> List.map (fun (polarity, path) -> polarity, String.concat " " path) |> regroup |> Seq.map (fun ((polarity, path), count) -> path, count, polarity) diff --git a/db/type_polarity.mli b/db/type_polarity.mli index fcd4a3aa15..50235b80a7 100644 --- a/db/type_polarity.mli +++ b/db/type_polarity.mli @@ -71,7 +71,7 @@ type t = string * int * Sign.t The integer represents the occurences of the polarity, as explained in the toplevel documentation of the module. *) -val of_typ : any_is_poly:bool -> all_names:bool -> Typexpr.t -> t Seq.t +val of_typ : any_is_poly:bool -> Typexpr.t -> t Seq.t (** [of_typ ~ignore_any ~all_names typ] is the list of polarised types corresponding to [typ]. diff --git a/index/load_doc.ml b/index/load_doc.ml index ea64497416..e99057dc22 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -117,7 +117,7 @@ let convert_kind ~db (Odoc_search.Entry.{ kind; _ } as entry) = | ModuleType -> Module_type let register_type_expr ~db elt typ = - let type_polarities = Db.Type_polarity.of_typ ~any_is_poly:true ~all_names:true typ in + let type_polarities = Db.Type_polarity.of_typ ~any_is_poly:true typ in Db_writer.store_type_polarities db elt type_polarities let register_kind ~db elt = diff --git a/query/query.ml b/query/query.ml index b079e5140d..f4f2dfb038 100644 --- a/query/query.ml +++ b/query/query.ml @@ -18,7 +18,7 @@ let polarities typ = List.of_seq @@ Seq.filter (fun (word, _count, _) -> String.length word > 0) - (Db.Type_polarity.of_typ ~any_is_poly:false ~all_names:false typ) + (Db.Type_polarity.of_typ ~any_is_poly:false typ) let find_types ~shard typ = let polarities = polarities typ in @@ -30,17 +30,18 @@ let find_types ~shard typ = | Db.Type_polarity.Sign.Pos -> shard.Db.db_pos_types | Neg -> shard.Db.db_neg_types in - Db.Occurences.fold - (fun occurrences st acc -> - if occurrences < count - then acc - else begin - match Tree.find st name with - | Some trie -> Succ.union acc (Succ.of_automata trie) - | None -> acc - end) - st_occ - Succ.empty) + Succ.union_of_list + @@ Db.Occurences.fold + (fun occurrences st acc -> + if occurrences < count + then acc + else begin + let ts = Tree.find_star st name in + let ss = List.map Succ.of_automata ts in + List.rev_append ss acc + end) + st_occ + []) polarities let find_names ~shard names = diff --git a/test/cram/base_web.t b/test/cram/base_web.t index bfcac10cd2..ba08187481 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -18,8 +18,8 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2540 db.js - 1916 db.js.gz + 2312 db.js + 1744 db.js.gz 1548 megaodocl.gz $ for f in $(find . -name '*.odocl'); do diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index c33944633b..a0f7296f72 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -107,6 +107,7 @@ TODO : get a result for the query bellow val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc search ": ('a -> 'b) -> 'a t -> 'b t" val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t TODO : get a result for the query bellow $ sherlodoc search ": 'a bo" From 819ca4deff93c8d67ce5608fe727f8a660b30e33 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 13 Jan 2024 13:55:19 +0100 Subject: [PATCH 238/285] index types in lowercase --- db/type_polarity.ml | 2 +- test/cram/base_cli.t | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/db/type_polarity.ml b/db/type_polarity.ml index 75ed50efbd..60f4c6b530 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -26,7 +26,7 @@ let rec of_typ ~any_is_poly ~prefix ~sgn = function (of_typ ~any_is_poly ~prefix ~sgn:(Sign.not sgn) a) (of_typ ~any_is_poly ~prefix ~sgn b) | Constr (name, args) -> begin - let prefix = name :: prefix in + let prefix = String.lowercase_ascii name :: prefix in match args with | [] -> [ sgn, prefix ] | _ -> diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 73f3ff13fd..53ce17f4e6 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -228,31 +228,31 @@ 440 val Base.List.find : 'a t -> f:('a -> bool) -> 'a option 440 val Base.List.mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t $ sherlodoc search --print-cost ": list" + 314 val Base.List.rev : 'a t -> 'a t 320 val Base.Map.data : (_, 'v, _) t -> 'v list 320 val Base.Map.keys : ('k, _, _) t -> 'k list + 323 val Base.List.join : 'a t t -> 'a t + 329 val Base.List.drop : 'a t -> int -> 'a t + 329 val Base.List.take : 'a t -> int -> 'a t + 332 val Base.List.map : 'a t -> f:('a -> 'b) -> 'b t + 333 val Base.List.return : 'a -> 'a t + 335 val Base.List.tl_exn : 'a t -> 'a t + 337 val Base.List.concat : 'a t t -> 'a t 337 val Base.Set.to_list : ('a, _) t -> 'a list + 338 val Base.List.sub : 'a t -> pos:int -> len:int -> 'a t + 339 val Base.List.init : int -> f:(int -> 'a) -> 'a t + 341 val Base.List.bind : 'a t -> f:('a -> 'b t) -> 'b t + 344 val Base.List.(>>|) : 'a t -> ('a -> 'b) -> 'b t + 344 val Base.List.append : 'a t -> 'a t -> 'a t 344 val Base.Hashtbl.data : (_, 'b) t -> 'b list 344 val Base.Set.elements : ('a, _) t -> 'a list 344 val Base.Bytes.to_list : t -> char list + 346 val Base.List.(>>=) : 'a t -> ('a -> 'b t) -> 'b t 346 val Base.String.split : t -> on:char -> t list + 347 val Base.List.mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t 348 val Base.Hashtbl.keys : ('a, _) t -> 'a key list - 376 val Base.String.split_lines : t -> t list - 378 val Base.Map.find_multi : ('k, 'v list, 'cmp) t -> 'k -> 'v list - 379 val Base.Hashtbl.Poly.data : (_, 'b) t -> 'b list - 379 val Base.String.to_list_rev : t -> char list - 383 val Base.Hashtbl.Poly.keys : ('a, _) t -> 'a key list - 384 val Base.Pretty_printer.all : unit -> string list - 385 val Base.Hashtbl.to_alist : ('a, 'b) t -> ('a key * 'b) list - 389 val Base.Set.group_by : ('a, 'cmp) t -> equiv:('a -> 'a -> bool) -> ('a, 'cmp) t list - 389 val Base.Sequence.split_n : 'a t -> int -> 'a list * 'a t - 392 val Base.Sequence.group : 'a t -> break:('a -> 'a -> bool) -> 'a list t - 394 val Base.Sequence.to_list_rev : 'a t -> 'a list - 401 val Base.Map.to_alist : ?key_order:[ `Increasing | `Decreasing ] -> ('k, 'v, _) t -> ('k * 'v) list - 403 val Base.Hashtbl.find_multi : ('a, 'b list) t -> 'a key -> 'b list - 404 val Base.Sequence.chunks_exn : 'a t -> int -> 'a list t - 410 val Base.Map.add_multi : ('k, 'v list, 'cmp) t -> key:'k -> data:'v -> ('k, 'v list, 'cmp) t - 412 val Base.List.find_all_dups : 'a t -> compare:('a -> 'a -> int) -> 'a list - 414 val Base.String.split_on_chars : t -> on:char list -> t list + 351 val Base.List.ignore_m : 'a t -> unit t + 353 val Base.List.sort : 'a t -> compare:('a -> 'a -> int) -> 'a t Partial name search: $ sherlodoc search --print-cost "strin" From 26c6ba1c5ff2edd42c863ef120c178f522c2ec84 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sat, 13 Jan 2024 14:58:53 +0100 Subject: [PATCH 239/285] avoid indexing doc paragraphs and functor parameters --- index/load_doc.ml | 90 +++++++++++++++--------------- test/cram/base_cli.t | 6 +- test/cram/base_web.t | 4 +- test/cram/cli.t/run.t | 4 +- test/cram/module_type_cost.t/run.t | 1 - 5 files changed, 50 insertions(+), 55 deletions(-) diff --git a/index/load_doc.ml b/index/load_doc.ml index e99057dc22..9cf747bbde 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -86,7 +86,6 @@ 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 open Odoc_search.Entry in match kind with | TypeDecl _ -> Entry.Kind.Type_decl (Odoc_search.Html.typedecl_params_of_entry entry) | Value { value = _; type_ } -> @@ -126,29 +125,26 @@ let register_kind ~db elt = | None -> () | Some typ -> register_type_expr ~db elt typ -let rec is_from_module_type (id : Odoc_model.Paths.Identifier.Any.t) = +let rec categorize (id : Odoc_model.Paths.Identifier.Any.t) = let open Odoc_model.Paths in match id.iv with - | `CoreType _ | `CoreException _ | `Root _ | `Page _ | `LeafPage _ -> false - | `ModuleType _ -> true + | `CoreType _ | `CoreException _ | `Root _ | `Page _ | `LeafPage _ -> `definition + | `ModuleType _ -> `declaration + | `Parameter _ -> `ignore (* redundant with indexed signature *) | #Identifier.NonSrc.t_pv as x -> let parent = Identifier.label_parent { id with iv = x } in - is_from_module_type (parent :> Identifier.Any.t) - | _ -> false + categorize (parent :> Identifier.Any.t) + | `AssetFile _ | `SourceDir _ | `SourceLocationMod _ | `SourceLocation _ | `SourcePage _ + | `SourceLocationInternal _ -> + `ignore (* unclear what to do with those *) -let is_from_module_type Odoc_search.Entry.{ id; _ } = +let categorize Odoc_search.Entry.{ id; _ } = match id.iv with | `ModuleType (parent, _) -> (* A module type itself is not *from* a module type, but it might be if one of its parents is a module type. *) - is_from_module_type (parent :> Odoc_model.Paths.Identifier.Any.t) - | _ -> is_from_module_type id - -let prefixname id = - let parts = Odoc_model.Paths.Identifier.fullname id in - match List.rev parts with - | [] -> "" - | _ :: prefix -> String.concat "." (List.rev prefix) + categorize (parent :> Odoc_model.Paths.Identifier.Any.t) + | _ -> categorize id let register_entry ~db @@ -156,42 +152,44 @@ let register_entry ~type_search ~index_docstring ~pkg + ~cat (Odoc_search.Entry.{ id; doc; kind } as entry) = let module Sherlodoc_entry = Entry in let open Odoc_search in - let open Odoc_search.Entry in - let is_type_extension = + let name = String.concat "." (Odoc_model.Paths.Identifier.fullname id) in + let doc_txt = Text.of_doc doc in + let doc_html = + match doc_txt with + | "" -> "" + | _ -> string_of_html (Html.of_doc doc) + in + let rhs = Html.rhs_of_kind kind in + let kind = convert_kind ~db entry in + let cost = cost ~name ~kind ~doc_html ~rhs in + let url = Result.get_ok (Html.url id) in + let is_from_module_type = cat <> `definition in + let elt = + Sherlodoc_entry.v ~name ~kind ~rhs ~doc_html ~cost ~url ~is_from_module_type ~pkg () + in + if index_docstring then register_doc ~db elt doc_txt ; + if index_name && kind <> Doc then register_full_name ~db elt ; + if type_search then register_kind ~db elt + +let register_entry + ~db + ~index_name + ~type_search + ~index_docstring + ~pkg + (Odoc_search.Entry.{ id; kind; _ } as entry) + = + let cat = categorize entry in + let is_pure_documentation = match kind with - | TypeExtension _ -> true + | Doc _ -> true | _ -> false in - if Odoc_model.Paths.Identifier.is_internal id || is_type_extension + if is_pure_documentation || cat = `ignore || Odoc_model.Paths.Identifier.is_internal id then () - else begin - let full_name = id |> Odoc_model.Paths.Identifier.fullname |> String.concat "." in - let doc_txt = Text.of_doc doc in - let doc_html = doc |> Html.of_doc |> string_of_html in - let doc_html = - match doc_txt with - | "" -> "" - | _ -> doc_html - in - let rhs = Html.rhs_of_kind kind in - let kind = convert_kind ~db entry in - let name = - match kind with - | Doc -> prefixname id - | _ -> full_name - in - let cost = cost ~name ~kind ~doc_html ~rhs in - let url = Html.url id in - let url = Result.get_ok url in - let is_from_module_type = is_from_module_type entry in - let elt = - Sherlodoc_entry.v ~name ~kind ~rhs ~doc_html ~cost ~url ~is_from_module_type ~pkg () - in - if index_docstring then register_doc ~db elt doc_txt ; - if index_name && kind <> Doc then register_full_name ~db elt ; - if type_search then register_kind ~db elt - end + else register_entry ~db ~index_name ~type_search ~index_docstring ~pkg ~cat entry diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 53ce17f4e6..2e5a576fe5 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -80,15 +80,12 @@ get_key:('r -> 'a key) -> 'r list -> [ `Ok of ('a, 'r) t | `Duplicate_keys of 'a key list ] - 1092 val Base.Map.S_poly.Make_applicative_traversals.A.(<*>) : ('a -> 'b) t -> 'a t -> 'b t 1099 val Base.Hashtbl.S_poly.create_mapped : ?growth_allowed:bool -> ?size:int -> get_key:('r -> 'a key) -> get_data:('r -> 'b) -> 'r list -> [ `Ok of ('a, 'b) t | `Duplicate_keys of 'a key list ] - 1145 mod Base.Map.S_poly.Make_applicative_traversals.A.Applicative_infix - 1218 val Base.Map.S_poly.Make_applicative_traversals.A.Applicative_infix.(<*>) : ('a -> 'b) t -> 'a t -> 'b t 1323 type ('a, 'b) Base.Map.S_poly.t 1323 type 'elt Base.Set.S_poly.t 1337 type ('a, 'cmp) Base.Set.S_poly.set @@ -137,7 +134,10 @@ 1391 val Base.Set.S_poly.of_array : 'a array -> 'a t 1391 val Base.Set.S_poly.to_array : 'a t -> 'a array 1392 val Base.Set.S_poly.singleton : 'a -> 'a t + 1395 val Base.Hashtbl.S_poly.mem : ('a, _) t -> 'a key -> bool + 1395 val Base.Map.S_poly.of_tree : ('k, 'v) tree -> ('k, 'v) t 1395 val Base.Map.S_poly.to_tree : ('k, 'v) t -> ('k, 'v) tree + 1396 val Base.Map.S_poly.nth_exn : ('k, 'v) t -> int -> 'k * 'v $ sherlodoc search --print-cost --no-rhs "group b" 453 val Base.List.group 484 val Base.Sequence.group diff --git a/test/cram/base_web.t b/test/cram/base_web.t index ba08187481..ab33c8f141 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -18,8 +18,8 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2312 db.js - 1744 db.js.gz + 2076 db.js + 1564 db.js.gz 1548 megaodocl.gz $ for f in $(find . -name '*.odocl'); do diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index a0f7296f72..b125e9649e 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -30,7 +30,6 @@ val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo - doc $ sherlodoc search "map" mod Main.Map val Main.List.map : ('a -> 'b) -> 'a t -> 'b t @@ -76,14 +75,13 @@ val Main.List.map : ('a -> 'b) -> 'a t -> 'b t type Main.extensible_type = .. val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + type Main.MyExtension val Main.nesting_priority : foo val Main.consume_2_other : moo -> t -> unit cons Main.MyExtension : moo -> extensible_type val Main.Nest.nesting_priority : foo val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo - doc - doc $ sherlodoc search "qwertyuiopasdfghjklzxcvbnm" [No results] $ sherlodoc search "hidden" diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t index 2cf7b428f3..489086c26d 100644 --- a/test/cram/module_type_cost.t/run.t +++ b/test/cram/module_type_cost.t/run.t @@ -12,7 +12,6 @@ the module type. $ sherlodoc search --print-cost --no-rhs "my_function" 839 val Main.M.my_function 860 val Main.Make.my_function - 874 val Main.Make.M.my_function 1239 val Main.S.my_function Here we expect both the module type and the module to be ranked the same $ sherlodoc search --print-cost "module" From a86841243b51371a81478589ec643884f1b3bc30 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 14 Jan 2024 11:52:04 +0100 Subject: [PATCH 240/285] optimize succ --- query/succ.ml | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/query/succ.ml b/query/succ.ml index 57573e36de..084e7ad822 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -62,28 +62,26 @@ let rec succ ~strictness t elt = | Some e -> assert (Entry.compare elt e <= 0) end ; Priority_queue.minimum pqueue, Pq pqueue - | Union (l, r) -> - let elt_l, l = succ ~strictness l elt in - let elt_r, r = succ ~strictness r elt in - best_opt elt_l elt_r, Union (l, r) + | Union (l, r) -> begin + match succ ~strictness l elt with + | None, _ -> succ ~strictness r elt + | Some elt_l, l when strictness = Ge && Entry.equal elt elt_l -> Some elt, Union (l, r) + | elt_l, l -> + let elt_r, r = succ ~strictness r elt in + best_opt elt_l elt_r, Union (l, r) + end | Inter (l, r) -> let rec loop elt l r = match succ ~strictness:Ge l elt with | None, _ -> None, Empty - | Some elt_l, l -> begin - match succ ~strictness:Ge r elt_l with - | None, _ -> None, Empty - | Some elt_r, r -> - assert (Entry.compare elt_l elt_r <= 0) ; - if Entry.compare elt_l elt_r = 0 - then Some elt_l, Inter (l, r) - else loop elt_r l r - end + | Some elt', l -> + assert (Entry.compare elt elt' <= 0) ; + if Entry.equal elt elt' then Some elt, Inter (l, r) else loop elt' r l in begin match succ ~strictness l elt with | None, _ -> None, Empty - | Some elt, l -> loop elt l r + | Some elt_l, l -> loop elt_l r l end let rec first t = From 2a732157d640d3876c6b763daa8dc375625b9612 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Sun, 14 Jan 2024 17:40:57 +0100 Subject: [PATCH 241/285] fix sorting heuristics --- db/entry.ml | 4 +- db/entry.mli | 2 - db/type_polarity.ml | 2 +- index/load_doc.ml | 47 ++- query/dynamic_cost.ml | 173 +--------- query/name_cost.ml | 68 +++- query/test/test_succ.ml | 11 +- query/top_results.ml | 2 +- query/type_distance.ml | 50 +-- test/cram/base_cli.t | 529 ++++++++++++++--------------- test/cram/base_web.t | 4 +- test/cram/cli.t/run.t | 34 +- test/cram/cli_small.t/run.t | 10 +- test/cram/module_type_cost.t/run.t | 10 +- 14 files changed, 410 insertions(+), 536 deletions(-) diff --git a/db/entry.ml b/db/entry.ml index 0109825771..33d44ac5ee 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -50,7 +50,6 @@ module T = struct ; cost : int ; doc_html : string ; pkg : Package.t - ; is_from_module_type : bool } let string_compare_shorter a b = @@ -125,7 +124,7 @@ let link t = in pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name -let v ~name ~kind ~cost ~rhs ~doc_html ~url ~is_from_module_type ~pkg () = +let v ~name ~kind ~cost ~rhs ~doc_html ~url ~pkg () = { name = non_empty_string name ; kind ; url = non_empty_string url @@ -133,5 +132,4 @@ let v ~name ~kind ~cost ~rhs ~doc_html ~url ~is_from_module_type ~pkg () = ; doc_html = non_empty_string doc_html ; pkg ; rhs = Option.map non_empty_string rhs - ; is_from_module_type } diff --git a/db/entry.mli b/db/entry.mli index 1529d49d7d..53856413b8 100644 --- a/db/entry.mli +++ b/db/entry.mli @@ -36,7 +36,6 @@ type t = ; cost : int ; doc_html : string ; pkg : Package.t - ; is_from_module_type : bool } val v @@ -46,7 +45,6 @@ val v -> rhs:string option -> doc_html:string -> url:string - -> is_from_module_type:bool -> pkg:Package.t -> unit -> t diff --git a/db/type_polarity.ml b/db/type_polarity.ml index 60f4c6b530..61067bcf01 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -55,6 +55,6 @@ let regroup lst = let of_typ ~any_is_poly t = t |> of_typ ~any_is_poly ~prefix:[] ~sgn:Pos - |> List.map (fun (polarity, path) -> polarity, String.concat " " path) + |> List.map (fun (polarity, path) -> polarity, String.concat " " (List.rev path)) |> regroup |> Seq.map (fun ((polarity, path), count) -> path, count, polarity) diff --git a/index/load_doc.ml b/index/load_doc.ml index 9cf747bbde..f00da85061 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -8,29 +8,29 @@ let string_starts_with ~prefix str = in String.length prefix <= String.length str && go 0 -let generic_cost ~ignore_no_doc name has_doc = - (* name length is important not because short identifier are better in the - abstract, but because the shortest result will be close to the query, as - the suffix tree does not return results shorter than the query*) - (String.length name * 6) - (* + (5 * List.length path) TODO : restore depth based ordering *) - + (if ignore_no_doc || has_doc then 0 else 400) - + if string_starts_with ~prefix:"Stdlib." name then 0 else 100 +let path_length str = + let rec go i acc = + if i >= String.length str + then acc + else go (i + 1) (if str.[i] = '.' then acc + 1 else acc) + in + go 0 0 let kind_cost = function - | Entry.Kind.Doc -> 400 - | _ -> 0 - -let cost ~name ~kind ~doc_html ~rhs = - let ignore_no_doc = - match kind with - | Entry.Kind.Module | Module_type -> true - | _ -> false - in - let has_doc = doc_html <> "" in - generic_cost ~ignore_no_doc name has_doc - + kind_cost kind + | Entry.Kind.Constructor _ | Entry.Kind.Exception _ | Entry.Kind.Extension_constructor _ + | Entry.Kind.Field _ | Entry.Kind.Type_decl _ | Entry.Kind.Type_extension + | Entry.Kind.Val _ -> + 0 + | _ -> 50 + +let cost ~name ~kind ~doc_html ~rhs ~cat = + String.length name + + (5 * path_length name) + + (if string_starts_with ~prefix:"Stdlib." name then 0 else 20) + String.length (Option.value ~default:"" rhs) + + kind_cost kind + + (if cat = `definition then 0 else 100) + + if doc_html <> "" then 0 else 100 let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) @@ -166,12 +166,9 @@ let register_entry in let rhs = Html.rhs_of_kind kind in let kind = convert_kind ~db entry in - let cost = cost ~name ~kind ~doc_html ~rhs in + let cost = cost ~name ~kind ~doc_html ~rhs ~cat in let url = Result.get_ok (Html.url id) in - let is_from_module_type = cat <> `definition in - let elt = - Sherlodoc_entry.v ~name ~kind ~rhs ~doc_html ~cost ~url ~is_from_module_type ~pkg () - 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 ; if type_search then register_kind ~db elt diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index efaf984a6e..1e4268f2d4 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -13,164 +13,19 @@ let of_query { Query_parser.name; typ } = in { name; type_paths } -module Reasoning = struct - (** The [Reasoning] module contains a representation that include every reason - for which a search entry would be ranked higher or lower. It does not - decide which reason is more important. *) - - module Name_match = struct - (** [Name_match.t] represents how good of a match there is between the query - and the name of an entry. *) - type t = - | DotSuffix - | PrefixSuffix - | SubDot - | SubUnderscore - | Sub - | Lowercase - | Doc - - let with_word query_word name = - let low_query_word = String.lowercase_ascii query_word in - let has_case = low_query_word <> query_word in - let name = if not has_case then String.lowercase_ascii name else name in - if String.equal query_word name - || Name_cost.ends_with ~suffix:("." ^ query_word) name - then DotSuffix - else if Name_cost.starts_with ~prefix:query_word name - || Name_cost.ends_with ~suffix:query_word name - then PrefixSuffix - else if Name_cost.is_substring ~sub:("(" ^ query_word) name - || Name_cost.is_substring ~sub:(query_word ^ ")") name - then PrefixSuffix - else if Name_cost.is_substring ~sub:("." ^ query_word) name - || Name_cost.is_substring ~sub:(query_word ^ ".") name - then SubDot - else if Name_cost.is_substring ~sub:("_" ^ query_word) name - || Name_cost.is_substring ~sub:(query_word ^ "_") name - then SubUnderscore - else if Name_cost.is_substring ~sub:query_word name - then Sub - else if has_case - && Name_cost.is_substring ~sub:low_query_word (String.lowercase_ascii name) - then Lowercase - else (* Matches only in the docstring are always worse *) Doc - - let with_words query_words entry = - match entry.Entry.kind with - | Entry.Kind.Doc -> List.map (fun _ : t -> Doc) query_words - | _ -> List.map (fun word -> with_word word entry.Entry.name) query_words - end - - type t = - { is_stdlib : bool - ; name_length : int - ; has_doc : bool - ; name_matches : Name_match.t list - ; type_distance : int option - ; type_in_query : bool - ; type_in_entry : bool - ; kind : Entry.Kind.t - ; is_from_module_type : bool - } - - let type_distance query_type entry = - match query_type, Entry.Kind.get_type entry.Entry.kind with - | Some query_paths, Some entry_type -> - Some (Type_distance.v ~query_paths ~entry:entry_type) - | _ -> None - - let type_in_query = function - | Some _ -> true - | _ -> false - - let type_in_entry entry = - let open Entry in - match Entry.Kind.get_type entry.kind with - | Some _ -> true - | None -> false - - let is_stdlib entry = - let open Entry in - Name_cost.starts_with ~prefix:"Stdlib." entry.name - - let name_length entry = String.length entry.Entry.name - let is_from_module_type entry = entry.Entry.is_from_module_type - let has_doc e = e.Entry.doc_html <> "" - - (** Compute the reasoning for the cost of an entry *) - let v { name = query_words; type_paths = query_type } entry = - { is_stdlib = is_stdlib entry - ; has_doc = has_doc entry - ; name_matches = Name_match.with_words query_words entry - ; type_distance = type_distance query_type entry - ; type_in_entry = type_in_entry entry - ; type_in_query = type_in_query query_type - ; kind = entry.kind - ; name_length = name_length entry - ; is_from_module_type = is_from_module_type entry - } -end - -(** [cost_of_reasoning r] is the cost of a entry according to the reasons - contained in [r]. *) -let cost_of_reasoning - Reasoning. - { is_stdlib - ; has_doc - ; name_matches - ; type_distance - ; type_in_entry - ; type_in_query - ; kind - ; name_length - ; is_from_module_type - } - = - let ignore_no_doc = - match kind with - | Module | Module_type -> true - | _ -> false - in - let kind = - match kind with - | Val _ | Module | Module_type | Constructor _ | Field _ | Type_decl _ -> 0 - | Exception _ -> 30 - | Class_type | Class | Type_extension -> 40 - | Extension_constructor _ | Method | Doc -> 50 - in - let name_matches = - let open Reasoning.Name_match in - name_matches - |> List.map (function - | DotSuffix -> 0 - | PrefixSuffix -> 103 - | SubDot -> 104 - | SubUnderscore -> 105 - | Sub -> 106 - | Lowercase -> 107 - | Doc -> 1000) - |> List.fold_left ( + ) 0 - in +let type_distance query_type entry = + match query_type, Entry.Kind.get_type entry.Entry.kind with + | Some query_paths, Some entry_type -> + Some (Type_distance.v ~query_paths ~entry:entry_type) + | Some _, None -> Some 1000 + | _ -> None + +let score query entry = + let found, not_found = Name_cost.best_matches query.name entry.Db.Entry.name in + let name_matches = found + not_found in let type_cost = - if type_in_entry && type_in_query - then Option.get type_distance - else if type_in_entry - then 0 - else if type_in_query - then - (* If query request a type, elements which do not have one should never - appear. *) - assert false - else 0 + match type_distance query.type_paths entry with + | Some cost -> cost + | None -> 0 in - let is_from_module_type_cost = if is_from_module_type then 400 else 0 in - (if is_stdlib then 0 else 100) - + (if has_doc || ignore_no_doc then 0 else 100) - + name_matches - + type_cost - + kind - + name_length - + is_from_module_type_cost - -let cost_of_entry query entry = cost_of_reasoning (Reasoning.v query entry) + 10 * (name_matches + type_cost) diff --git a/query/name_cost.ml b/query/name_cost.ml index 48f29ef93d..1081cdbb00 100644 --- a/query/name_cost.ml +++ b/query/name_cost.ml @@ -1,23 +1,59 @@ -let rec is_prefix_at ~sub i s j = +let rec prefix_at ~case ~sub i s j = if i >= String.length sub - then true + then Some case else if sub.[i] = s.[j] - then is_prefix_at ~sub (i + 1) s (j + 1) - else false + then prefix_at ~case ~sub (i + 1) s (j + 1) + else if sub.[i] = Char.lowercase_ascii s.[j] + then prefix_at ~case:(case + 5) ~sub (i + 1) s (j + 1) + else if Char.lowercase_ascii sub.[i] = s.[j] + then prefix_at ~case:(case + 10) ~sub (i + 1) s (j + 1) + else None -let is_substring ~sub s = - let rec go j = +let prefix_at ~sub s j = prefix_at ~case:0 ~sub 0 s j + +let find_all ~sub s = + let rec go j acc = if j + String.length sub > String.length s - then false - else if is_prefix_at ~sub 0 s j - then true - else go (j + 1) + then acc + else begin + let acc = + match prefix_at ~sub s j with + | None -> acc + | Some cost -> (j, cost) :: acc + in + go (j + 1) acc + end in - go 0 + go 0 [] + +let is_substring ~sub s = find_all ~sub s <> [] + +let word_boundary s i = + if i < 0 + then 0 + else if i >= String.length s || List.mem s.[i] [ '.'; '('; ')' ] + then 1 + else if s.[i] = '_' + then 3 + else 10 -let starts_with ~prefix str = - String.length prefix <= String.length str && is_prefix_at ~sub:prefix 0 str 0 +let best_match ~sub str = + List.fold_left + (fun acc (i, case_cost) -> + let left = word_boundary str (i - 1) in + let right = word_boundary str (i + String.length sub) in + let cost = case_cost + left + right in + match acc with + | Some cost' when cost' < cost -> acc + | _ -> Some cost) + None + (find_all ~sub str) -let ends_with ~suffix str = - let j = String.length str - String.length suffix in - j >= 0 && is_prefix_at ~sub:suffix 0 str j +let best_matches words str = + List.fold_left + (fun (found, not_found) sub -> + match best_match ~sub str with + | Some cost -> found + cost, not_found + | None -> found, not_found + String.length sub + 50) + (0, 0) + words diff --git a/query/test/test_succ.ml b/query/test/test_succ.ml index 5adaca5299..ed3868437d 100644 --- a/query/test/test_succ.ml +++ b/query/test/test_succ.ml @@ -3,16 +3,7 @@ open Query.Private let pkg = Db.Entry.Package.v ~name:"" ~version:"" let elt cost = - Db.Entry.v - ~cost - ~name:"" - ~kind:Db.Entry.Kind.Doc - ~rhs:None - ~doc_html:"" - ~url:"" - ~is_from_module_type:false - ~pkg - () + Db.Entry.v ~cost ~name:"" ~kind:Db.Entry.Kind.Doc ~rhs:None ~doc_html:"" ~url:"" ~pkg () (** This module does the same thing as Succ, but its correctness is obvious and its performance terrible. *) diff --git a/query/top_results.ml b/query/top_results.ml index 13e1981411..deac4a968e 100644 --- a/query/top_results.ml +++ b/query/top_results.ml @@ -12,7 +12,7 @@ type step = | Stop of t let update_entry query entry = - let extra_cost = Dynamic_cost.cost_of_entry query entry in + let extra_cost = Dynamic_cost.score query entry in Db.Entry.{ entry with cost = entry.cost + extra_cost } let add ~query ~limit elt t = diff --git a/query/type_distance.ml b/query/type_distance.ml index 760647535f..94543081ca 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -41,25 +41,25 @@ end = struct let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst - let rec of_typ ~ignore_any ~prefix ~sgn t = + let rec of_typ ~ignore_any ~prefix t = match t with | Db.Typexpr.Poly _ -> let poly = "POLY" in - [ poly :: Sign.to_string sgn :: prefix ] + [ poly :: prefix ] | Any -> if ignore_any - then [ prefix ] + then [ "_" :: prefix ] else ( let poly = "POLY" in - [ poly :: Sign.to_string sgn :: prefix ]) + [ poly :: prefix ]) | Arrow (a, b) -> let prefix_left = "->0" :: prefix in let prefix_right = "->1" :: prefix in List.rev_append - (of_typ ~ignore_any ~prefix:prefix_left ~sgn:(Sign.not sgn) a) - (of_typ ~ignore_any ~prefix:prefix_right ~sgn b) + (of_typ ~ignore_any ~prefix:prefix_left a) + (of_typ ~ignore_any ~prefix:prefix_right b) | Constr (name, args) -> - let prefix = name :: Sign.to_string sgn :: prefix in + let prefix = name :: prefix in begin match args with | [] -> [ prefix ] @@ -68,20 +68,23 @@ end = struct @@ List.mapi (fun i arg -> let prefix = string_of_int i :: prefix in - of_typ ~ignore_any ~prefix ~sgn arg) + of_typ ~ignore_any ~prefix arg) args end | Tuple args -> rev_concat @@ List.mapi (fun i arg -> let prefix = (string_of_int i ^ "*") :: prefix in - of_typ ~ignore_any ~prefix ~sgn arg) + of_typ ~ignore_any ~prefix arg) @@ args | Unhandled -> [] - let of_typ ~ignore_any t = of_typ ~ignore_any ~prefix:[] ~sgn:Pos t + let of_typ ~ignore_any t = List.map List.rev @@ of_typ ~ignore_any ~prefix:[] t end +let skip_query x = 10 * String.length x +let skip_entry _ = 15 + let distance xs ys = let len_xs = List.length xs in let len_ys = List.length ys in @@ -97,17 +100,24 @@ let distance xs ys = end and go i j xs ys = match xs, ys with + | [], [] -> 0 | [], _ -> 0 | [ "_" ], _ -> 0 - | _, [] -> List.length xs - | x :: xs, y :: ys when Name_cost.ends_with ~suffix:x y -> memo (i + 1) (j + 1) xs ys + | x :: xs, y :: ys when x = y -> memo (i + 1) (j + 1) xs ys | _, "->1" :: ys -> memo i (j + 1) xs ys | "->1" :: xs, _ -> 1 + memo (i + 1) j xs ys - | _ :: xs', _ :: ys' -> - 7 - + min - (memo (i + 1) (j + 1) xs' ys') - (min (memo (i + 1) j xs' ys) (memo i (j + 1) xs ys')) + | xs, [] -> List.fold_left (fun acc x -> acc + skip_query x) 0 xs + | x :: xs', y :: ys' -> + let skip_x = skip_query x in + let skip_y = skip_entry y in + let cost = + match Name_cost.best_match ~sub:x y with + | None -> skip_x + skip_y + | Some cost -> cost + in + min + (cost + memo (i + 1) (j + 1) xs' ys') + (min (skip_x + memo (i + 1) j xs' ys) (skip_y + memo i (j + 1) xs ys')) in go 0 0 xs ys @@ -177,10 +187,6 @@ let v ~query_paths ~entry = | _, [] | [], _ -> 0 | _ -> let arr = - List.map - (fun p -> - let p = List.rev p in - List.map (fun q -> distance (List.rev q) p) query_paths) - entry_paths + List.map (fun p -> List.map (fun q -> distance q p) query_paths) entry_paths in minimize arr diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 2e5a576fe5..51af0f5e7c 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -9,155 +9,140 @@ $ export SHERLODOC_FORMAT=ancient $ sherlodoc index --index-docstring=false $(find . -name '*.odocl') 2> /dev/null $ sherlodoc search --print-cost --limit 100 "S_poly" - 305 sig Base.Map.S_poly - 305 sig Base.Set.S_poly - 333 sig Base.Hashtbl.S_poly - 851 mod Base.Set.S_poly.Named - 858 val Base.Set.S_poly.mem : 'a t -> 'a -> bool - 875 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t - 895 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list - 899 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list - 908 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t - 908 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option - 911 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit - 923 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option - 927 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] - 929 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b - 934 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t - 935 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list - 936 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool - 937 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit - 939 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit - 940 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit - 942 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b - 947 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit - 951 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc - 953 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list - 957 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit - 958 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit - 963 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit - 964 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t - 974 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b - 983 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b - 985 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option - 986 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t - 990 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t - 1005 mod Base.Map.S_poly.Make_applicative_traversals - 1006 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t - 1012 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t - 1013 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit - 1015 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b - 1018 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option - 1019 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit - 1026 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> - dst:('k, 'b) t -> - f:(key:'k key -> 'a -> 'b option -> 'b Merge_into_action.t) -> - unit - 1026 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> + 195 val Base.Set.S_poly.mem : 'a t -> 'a -> bool + 202 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list + 206 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + 212 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t + 212 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b + 213 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b + 215 sig Base.Map.S_poly + 215 sig Base.Set.S_poly + 215 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option + 218 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option + 218 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list + 219 sig Base.Hashtbl.S_poly + 221 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t + 222 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit + 222 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit + 224 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit + 224 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 226 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option + 235 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit + 235 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit + 235 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t + 236 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit + 236 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit + 237 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool + 238 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit + 239 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b + 240 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] + 241 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t + 242 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit + 242 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b + 244 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b + 245 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t + 246 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit + 254 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b + 255 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t + 258 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc + 259 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t + 259 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option + 265 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t + 272 type ('a, 'b) Base.Map.S_poly.t + 272 type 'elt Base.Set.S_poly.t + 274 type ('a, 'cmp) Base.Set.S_poly.set + 275 type ('a, 'b) Base.Map.S_poly.tree + 275 type 'elt Base.Set.S_poly.tree + 276 type ('a, 'b) Base.Hashtbl.S_poly.t + 279 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> 'a key -> if_found:('b -> 'c) -> if_not_found:('a key -> 'c) -> 'c - 1027 val Base.Hashtbl.S_poly.merge : ('k, 'a) t -> - ('k, 'b) t -> - f: - (key:'k key -> - [ `Left of 'a | `Right of 'b | `Both of 'a * 'b ] -> - 'c option) -> - ('k, 'c) t - 1036 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> + 283 val Base.Set.S_poly.empty : 'a t + 283 type 'a Base.Hashtbl.S_poly.key = 'a + 283 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t - 1037 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b - 1055 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> + 288 val Base.Map.S_poly.empty : ('k, _) t + 289 type Base.Map.S_poly.comparator_witness + 289 type Base.Set.S_poly.comparator_witness + 290 val Base.Set.S_poly.length : _ t -> int + 293 val Base.Set.S_poly.is_empty : _ t -> bool + 293 val Base.Set.S_poly.singleton : 'a -> 'a t + 294 val Base.Set.S_poly.choose_exn : 'a t -> 'a + 295 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t + 295 val Base.Map.S_poly.length : (_, _) t -> int + 295 val Base.Set.S_poly.max_elt_exn : 'a t -> 'a + 295 val Base.Set.S_poly.min_elt_exn : 'a t -> 'a + 296 val Base.Set.S_poly.of_list : 'a list -> 'a t + 296 val Base.Set.S_poly.of_tree : 'a tree -> 'a t + 296 val Base.Set.S_poly.to_list : 'a t -> 'a list + 296 val Base.Set.S_poly.to_tree : 'a t -> 'a tree + 296 val Base.Set.S_poly.invariants : 'a t -> bool + 297 val Base.Set.S_poly.choose : 'a t -> 'a option + 297 val Base.Set.S_poly.elements : 'a t -> 'a list + 297 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> + dst:('k, 'b) t -> + f:(key:'k key -> 'a -> 'b option -> 'b Merge_into_action.t) -> + unit + 298 val Base.Map.S_poly.data : (_, 'v) t -> 'v list + 298 val Base.Map.S_poly.keys : ('k, _) t -> 'k list + 298 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t + 298 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t + 298 val Base.Set.S_poly.max_elt : 'a t -> 'a option + 298 val Base.Set.S_poly.min_elt : 'a t -> 'a option + 298 val Base.Map.S_poly.is_empty : (_, _) t -> bool + 298 val Base.Set.S_poly.of_array : 'a array -> 'a t + 298 val Base.Set.S_poly.to_array : 'a t -> 'a array + 299 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool + 299 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t + 299 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t + 299 val Base.Hashtbl.S_poly.clear : (_, _) t -> unit + 299 val Base.Hashtbl.S_poly.length : (_, _) t -> int + 299 val Base.Hashtbl.S_poly.hashable : 'a Hashable.t + 300 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool + 301 val Base.Set.S_poly.nth : 'a t -> int -> 'a option + 301 val Base.Set.S_poly.union_list : 'a t list -> 'a t + 302 val Base.Map.S_poly.invariants : ('k, 'v) t -> bool + 302 val Base.Hashtbl.S_poly.is_empty : (_, _) t -> bool + 302 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> 'a key -> a:'d -> if_found:('b -> 'd -> 'c) -> if_not_found:('a key -> 'd -> 'c) -> 'c - 1088 val Base.Hashtbl.S_poly.create_with_key : ?growth_allowed:bool -> - ?size:int -> - get_key:('r -> 'a key) -> - 'r list -> - [ `Ok of ('a, 'r) t | `Duplicate_keys of 'a key list ] - 1099 val Base.Hashtbl.S_poly.create_mapped : ?growth_allowed:bool -> - ?size:int -> - get_key:('r -> 'a key) -> - get_data:('r -> 'b) -> - 'r list -> - [ `Ok of ('a, 'b) t | `Duplicate_keys of 'a key list ] - 1323 type ('a, 'b) Base.Map.S_poly.t - 1323 type 'elt Base.Set.S_poly.t - 1337 type ('a, 'cmp) Base.Set.S_poly.set - 1344 type ('a, 'b) Base.Map.S_poly.tree - 1344 type 'elt Base.Set.S_poly.tree - 1351 type ('a, 'b) Base.Hashtbl.S_poly.t - 1358 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t - 1358 val Base.Set.S_poly.empty : 'a t - 1363 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool - 1363 val Base.Map.S_poly.empty : ('k, _) t - 1364 val Base.Set.S_poly.nth : 'a t -> int -> 'a option - 1367 val Base.Map.S_poly.data : (_, 'v) t -> 'v list - 1367 val Base.Map.S_poly.keys : ('k, _) t -> 'k list - 1367 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t - 1370 type 'a Base.Hashtbl.S_poly.key = 'a - 1371 val Base.Set.S_poly.length : _ t -> int - 1374 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool - 1374 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t - 1374 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t - 1376 val Base.Map.S_poly.find : ('k, 'v) t -> 'k -> 'v option - 1376 val Base.Map.S_poly.rank : ('k, _) t -> 'k -> int option - 1376 val Base.Map.S_poly.length : (_, _) t -> int - 1377 val Base.Map.S_poly.nth : ('k, 'v) t -> int -> ('k * 'v) option - 1377 val Base.Set.S_poly.iter : 'a t -> f:('a -> unit) -> unit - 1378 val Base.Set.S_poly.choose : 'a t -> 'a option - 1379 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t - 1382 val Base.Map.S_poly.iter : (_, 'v) t -> f:('v -> unit) -> unit - 1382 val Base.Set.S_poly.find : 'a t -> f:('a -> bool) -> 'a option - 1383 val Base.Set.S_poly.count : 'a t -> f:('a -> bool) -> int - 1383 val Base.Set.S_poly.of_list : 'a list -> 'a t - 1383 val Base.Set.S_poly.of_tree : 'a tree -> 'a t - 1383 val Base.Set.S_poly.to_list : 'a t -> 'a list - 1383 val Base.Set.S_poly.to_tree : 'a t -> 'a tree - 1384 val Base.Map.S_poly.map : ('k, 'v1) t -> f:('v1 -> 'v2) -> ('k, 'v2) t - 1385 val Base.Map.S_poly.set : ('k, 'v) t -> key:'k -> data:'v -> ('k, 'v) t - 1385 val Base.Set.S_poly.max_elt : 'a t -> 'a option - 1385 val Base.Set.S_poly.min_elt : 'a t -> 'a option - 1386 val Base.Set.S_poly.is_empty : _ t -> bool - 1389 val Base.Map.S_poly.count : ('k, 'v) t -> f:('v -> bool) -> int - 1390 val Base.Set.S_poly.elements : 'a t -> 'a list - 1391 val Base.Set.S_poly.split : 'a t -> 'a -> 'a t * 'a option * 'a t - 1391 val Base.Map.S_poly.remove : ('k, 'v) t -> 'k -> ('k, 'v) t - 1391 val Base.Set.S_poly.exists : 'a t -> f:('a -> bool) -> bool - 1391 val Base.Set.S_poly.filter : 'a t -> f:('a -> bool) -> 'a t - 1391 val Base.Map.S_poly.is_empty : (_, _) t -> bool - 1391 val Base.Set.S_poly.of_array : 'a array -> 'a t - 1391 val Base.Set.S_poly.to_array : 'a t -> 'a array - 1392 val Base.Set.S_poly.singleton : 'a -> 'a t - 1395 val Base.Hashtbl.S_poly.mem : ('a, _) t -> 'a key -> bool - 1395 val Base.Map.S_poly.of_tree : ('k, 'v) tree -> ('k, 'v) t - 1395 val Base.Map.S_poly.to_tree : ('k, 'v) t -> ('k, 'v) tree - 1396 val Base.Map.S_poly.nth_exn : ('k, 'v) t -> int -> 'k * 'v + 304 val Base.Map.S_poly.find_exn : ('k, 'v) t -> 'k -> 'v + 305 val Base.Map.S_poly.singleton : 'k -> 'v -> ('k, 'v) t + 305 val Base.Set.S_poly.remove_index : 'a t -> int -> 'a t + 306 val Base.Hashtbl.S_poly.copy : ('a, 'b) t -> ('a, 'b) t + 306 val Base.Map.S_poly.max_elt_exn : ('k, 'v) t -> 'k * 'v + 306 val Base.Map.S_poly.min_elt_exn : ('k, 'v) t -> 'k * 'v + 306 val Base.Set.S_poly.of_sequence : 'a Sequence.t -> 'a t + 306 val Base.Set.S_poly.are_disjoint : 'a t -> 'a t -> bool + 307 val Base.Map.S_poly.find : ('k, 'v) t -> 'k -> 'v option + 307 val Base.Map.S_poly.rank : ('k, _) t -> 'k -> int option + 307 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int $ sherlodoc search --print-cost --no-rhs "group b" - 453 val Base.List.group - 484 val Base.Sequence.group - 514 val Base.List.Assoc.group - 571 val Base.List.groupi - 589 val Base.Hashtbl.group - 590 val Base.Set.group_by - 620 val Base.List.sort_and_group - 681 val Base.List.Assoc.sort_and_group - 1052 val Base.Hashtbl.Creators.group - 1109 val Base.Set.Poly.group_by - 1114 val Base.Hashtbl.Poly.group - 1136 val Base.Hashtbl.S_without_submodules.group - 1145 val Base.Hashtbl.Creators.group - 1209 val Base.Set.Using_comparator.group_by - 1244 val Base.Set.Using_comparator.Tree.group_by - 1523 val Base.Set.S_poly.group_by - 1528 val Base.Hashtbl.S_poly.group - 1624 val Base.Set.Accessors_generic.group_by - 1715 val Base.Set.Creators_and_accessors_generic.group_by + 260 val Base.List.group + 267 val Base.Sequence.group + 281 val Base.Set.group_by + 290 val Base.List.Assoc.group + 290 val Base.List.sort_and_group + 320 val Base.List.Assoc.sort_and_group + 358 val Base.List.groupi + 375 val Base.Set.Poly.group_by + 378 val Base.Hashtbl.group + 403 val Base.Set.Using_comparator.group_by + 413 val Base.Set.Using_comparator.Tree.group_by + 477 val Base.Set.S_poly.group_by + 478 val Base.Hashtbl.Poly.group + 485 val Base.Hashtbl.Creators.group + 492 val Base.Hashtbl.Creators.group + 504 val Base.Hashtbl.S_without_submodules.group + 512 val Base.Set.Accessors_generic.group_by + 525 val Base.Set.Creators_and_accessors_generic.group_by + 580 val Base.Hashtbl.S_poly.group $ sherlodoc search --no-rhs "group by" val Base.Set.group_by val Base.Set.Poly.group_by @@ -167,143 +152,151 @@ val Base.Set.Accessors_generic.group_by val Base.Set.Creators_and_accessors_generic.group_by $ sherlodoc search --print-cost "map2" - 504 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 527 mod Base.Applicative.Make_using_map2 - 534 sig Base.Applicative.Basic_using_map2 - 534 mod Base.Applicative.Make2_using_map2 - 534 mod Base.Applicative.Make3_using_map2 - 538 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 541 sig Base.Applicative.Basic2_using_map2 - 541 sig Base.Applicative.Basic3_using_map2 - 571 mod Base.Applicative.Make_using_map2_local - 578 sig Base.Applicative.Basic_using_map2_local - 578 mod Base.Applicative.Make2_using_map2_local - 578 mod Base.Applicative.Make3_using_map2_local - 585 sig Base.Applicative.Basic2_using_map2_local - 585 sig Base.Applicative.Basic3_using_map2_local - 607 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 650 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 654 mod Base.Applicative.Make_using_map2.Applicative_infix - 661 mod Base.Applicative.Make2_using_map2.Applicative_infix - 661 mod Base.Applicative.Make3_using_map2.Applicative_infix - 697 mod Base.Applicative.Make_using_map2_local.Applicative_infix - 704 mod Base.Applicative.Make2_using_map2_local.Applicative_infix - 704 mod Base.Applicative.Make3_using_map2_local.Applicative_infix - 733 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 776 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 857 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - $ sherlodoc search --print-cost --no-rhs --static-sort "List map2" - 277 val Base.List.rev_map2_exn - 650 val Base.List.map2 - 653 val Base.List.map2_exn - 674 val Base.List.rev_map2 - 737 val Base.List.Cartesian_product.map2 + 142 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 150 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 157 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 173 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 176 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 199 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 211 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 213 val Base.Or_error.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 226 val Base.Applicative.Pair.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 229 val Base.Applicative.Compose.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 229 val Base.Applicative.S2_to_S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 229 val Base.Applicative.S3_to_S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 229 val Base.Applicative.Make_using_map2.return : 'a -> 'a X.t + 230 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 232 val Base.Applicative.Make.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t + 232 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 233 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 234 val Base.Array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 235 val Base.Applicative.Make2_using_map2.return : 'a -> ('a, _) X.t + 236 val Base.Applicative.Of_monad.map2 : 'a M.t -> 'b M.t -> f:('a -> 'b -> 'c) -> 'c M.t + 238 val Base.Applicative.Make3_using_map2.return : 'a -> ('a, _, _) X.t + 240 val Base.Either.First.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t + 240 val Base.Applicative.Make_using_map2.all : 'a X.t list -> 'a list X.t + 241 val Base.Either.Second.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t + 243 val Base.Applicative.Make_using_map2.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t + + $ sherlodoc search --print-cost --static-sort "List map2" + 97 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 193 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 210 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 212 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 214 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + + $ sherlodoc search --print-cost "List map2" + 177 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 250 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 252 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 253 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 274 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t $ sherlodoc search --no-rhs "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group $ sherlodoc search --print-cost "list" - 263 mod Base.List - 263 mod Caml.List - 326 mod Shadow_stdlib.List - 409 mod Base.List.Assoc - 409 mod Base.List.Infix - 409 mod Base.ListLabels - 409 mod Caml.ListLabels - 410 val Base.List.rev : 'a t -> 'a t - 419 val Base.List.join : 'a t t -> 'a t - 422 val Base.List.last : 'a t -> 'a option - 424 val Base.List.drop : 'a t -> int -> 'a t - 424 val Base.List.take : 'a t -> int -> 'a t - 426 val Base.List.map : 'a t -> f:('a -> 'b) -> 'b t - 429 val Base.List.hd_exn : 'a t -> 'a - 429 val Base.List.return : 'a -> 'a t - 431 val Base.List.tl_exn : 'a t -> 'a t - 432 val Base.List.sub : 'a t -> pos:int -> len:int -> 'a t - 433 val Base.List.init : int -> f:(int -> 'a) -> 'a t - 433 val Base.List.concat : 'a t t -> 'a t - 435 val Base.List.bind : 'a t -> f:('a -> 'b t) -> 'b t - 438 val Base.List.(>>|) : 'a t -> ('a -> 'b) -> 'b t - 438 val Base.Set.to_list : ('a, _) t -> 'a list - 439 val Base.List.append : 'a t -> 'a t -> 'a t - 440 val Base.List.find : 'a t -> f:('a -> bool) -> 'a option - 440 val Base.List.mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t + 105 val Base.Bytes.to_list : t -> char list + 106 val Base.Queue.of_list : 'a list -> 'a t + 106 val Base.Stack.of_list : 'a list -> 'a t + 109 val Base.Set.to_list : ('a, _) t -> 'a list + 110 val Base.Bytes.of_char_list : char list -> t + 113 val Base.Linked_queue.of_list : 'a list -> 'a t + 121 val Base.Info.of_list : ?trunc_after:int -> t list -> t + 122 val Base.Error.of_list : ?trunc_after:int -> t list -> t + 128 val Base.List.rev : 'a t -> 'a t + 129 val Base.List.hd_exn : 'a t -> 'a + 129 val Base.List.return : 'a -> 'a t + 130 val Base.Array.of_list_rev : 'a list -> 'a t + 130 val Base.String.to_list_rev : t -> char list + 131 val Base.List.join : 'a t t -> 'a t + 131 val Base.List.tl_exn : 'a t -> 'a t + 131 val Base.Sequence.shift_right_with_list : 'a t -> 'a list -> 'a t + 133 val Base.List.concat : 'a t t -> 'a t + 133 val Base.Sequence.to_list_rev : 'a t -> 'a list + 134 val Base.List.last : 'a t -> 'a option + 135 val Base.List.ignore_m : 'a t -> unit t + 136 val Base.List.drop : 'a t -> int -> 'a t + 136 val Base.List.take : 'a t -> int -> 'a t + 136 val Base.Sequence.cycle_list_exn : 'a list -> 'a t + 137 val Base.List.nth_exn : 'a t -> int -> 'a + 139 val Base.List.append : 'a t -> 'a t -> 'a t $ sherlodoc search --print-cost ": list" - 314 val Base.List.rev : 'a t -> 'a t - 320 val Base.Map.data : (_, 'v, _) t -> 'v list - 320 val Base.Map.keys : ('k, _, _) t -> 'k list - 323 val Base.List.join : 'a t t -> 'a t - 329 val Base.List.drop : 'a t -> int -> 'a t - 329 val Base.List.take : 'a t -> int -> 'a t - 332 val Base.List.map : 'a t -> f:('a -> 'b) -> 'b t - 333 val Base.List.return : 'a -> 'a t - 335 val Base.List.tl_exn : 'a t -> 'a t - 337 val Base.List.concat : 'a t t -> 'a t - 337 val Base.Set.to_list : ('a, _) t -> 'a list - 338 val Base.List.sub : 'a t -> pos:int -> len:int -> 'a t - 339 val Base.List.init : int -> f:(int -> 'a) -> 'a t - 341 val Base.List.bind : 'a t -> f:('a -> 'b t) -> 'b t - 344 val Base.List.(>>|) : 'a t -> ('a -> 'b) -> 'b t - 344 val Base.List.append : 'a t -> 'a t -> 'a t - 344 val Base.Hashtbl.data : (_, 'b) t -> 'b list - 344 val Base.Set.elements : ('a, _) t -> 'a list - 344 val Base.Bytes.to_list : t -> char list - 346 val Base.List.(>>=) : 'a t -> ('a -> 'b t) -> 'b t - 346 val Base.String.split : t -> on:char -> t list - 347 val Base.List.mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t - 348 val Base.Hashtbl.keys : ('a, _) t -> 'a key list - 351 val Base.List.ignore_m : 'a t -> unit t - 353 val Base.List.sort : 'a t -> compare:('a -> 'a -> int) -> 'a t + 95 val Base.Bytes.to_list : t -> char list + 97 val Base.String.split_lines : t -> t list + 100 val Base.String.to_list_rev : t -> char list + 103 val Base.Sequence.to_list_rev : 'a t -> 'a list + 105 val Base.Pretty_printer.all : unit -> string list + 109 val Base.Set.to_list : ('a, _) t -> 'a list + 110 val Base.Hashtbl.data : (_, 'b) t -> 'b list + 110 val Base.Set.elements : ('a, _) t -> 'a list + 112 val Base.String.split : t -> on:char -> t list + 114 val Base.Hashtbl.keys : ('a, _) t -> 'a key list + 119 val Base.Map.data : (_, 'v, _) t -> 'v list + 119 val Base.Map.keys : ('k, _, _) t -> 'k list + 120 val Base.Hashtbl.Poly.data : (_, 'b) t -> 'b list + 124 val Base.Hashtbl.Poly.keys : ('a, _) t -> 'a key list + 126 val Base.String.split_on_chars : t -> on:char list -> t list + 136 val Base.Hashtbl.to_alist : ('a, 'b) t -> ('a key * 'b) list + 138 val Base.List.rev : 'a t -> 'a t + 139 val Base.List.return : 'a -> 'a t + 139 val Base.String.Search_pattern.split_on : t -> string -> string list + 141 val Base.List.join : 'a t t -> 'a t + 141 val Base.List.tl_exn : 'a t -> 'a t + 142 val Base.Hashtbl.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 143 val Base.List.concat : 'a t t -> 'a t + 145 val Base.List.ignore_m : 'a t -> unit t + 146 val Base.Hashtbl.Poly.to_alist : ('a, 'b) t -> ('a key * 'b) list Partial name search: $ sherlodoc search --print-cost "strin" - 381 mod Base.String - 381 mod Caml.String - 409 mod Base.Stringable - 418 val Base.String.rev : t -> t - 423 val Base.String.(^) : t -> t -> t - 423 mod Base.StringLabels - 423 sig Base.Stringable.S - 423 mod Caml.StringLabels - 427 val Base.String.hash : t -> int - 436 val Base.String.map : t -> f:(elt -> elt) -> t - 440 val Base.String.equal : t -> t -> bool - 444 val Base.String.append : t -> t -> t - 444 mod Base.String.Caseless - 444 mod Base.String.Escaping - 444 mod Shadow_stdlib.String - 445 val Base.String.init : int -> f:(int -> elt) -> t - 445 val Base.Exn.to_string : t -> string - 445 val Base.Sexp.of_string : unit - 445 mod Base.Bytes.To_string - 446 val Base.String.tr : target:char -> replacement:char -> t -> t - 446 val Base.String.prefix : t -> int -> t - 446 val Base.String.suffix : t -> int -> t - 446 val Base.String.escaped : t -> t - 447 val Base.String.iter : t -> f:(elt -> unit) -> unit - 448 val Base.String.split : t -> on:char -> t list + 186 val Base.Sexp.of_string : unit + 192 val Base.Exn.to_string : t -> string + 192 val Base.Sys.max_string_length : int + 194 val Base.Float.to_string : t -> string + 197 val Base.Exn.to_string_mach : t -> string + 197 val Base.Info.to_string_hum : t -> string + 197 val Base.Sign.to_string_hum : t -> string + 198 val Base.Error.to_string_hum : t -> string + 198 val Base.Info.to_string_mach : t -> string + 199 val Base.Error.to_string_mach : t -> string + 202 val Base.Or_error.error_string : string -> _ t + 204 val Base.Buffer.add_string : t -> string -> unit + 204 val Base.Sign_or_nan.to_string_hum : t -> string + 208 val Base.Info.to_string_hum_deprecated : t -> string + 209 val Base.Error.to_string_hum_deprecated : t -> string + 209 val Base.Float.to_padded_compact_string : t -> string + 209 val Base.Source_code_position.to_string : t -> string + 214 val Base.String.rev : t -> t + 215 val Base.Int.to_string_hum : ?delimiter:char -> t -> string + 217 val Base.String.hash : t -> int + 217 val Base.Int32.to_string_hum : ?delimiter:char -> t -> string + 217 val Base.Int63.to_string_hum : ?delimiter:char -> t -> string + 217 val Base.Int64.to_string_hum : ?delimiter:char -> t -> string + 218 val Base.String.escaped : t -> t + 218 val Base.String.max_length : int $ sherlodoc search --print-cost "tring" - 380 mod Base.String - 380 mod Caml.String - 411 mod Base.Stringable - 418 val Base.String.rev : t -> t - 423 val Base.String.(^) : t -> t -> t - 425 mod Base.StringLabels - 425 sig Base.Stringable.S - 425 mod Caml.StringLabels - 427 val Base.String.hash : t -> int - 436 val Base.String.map : t -> f:(elt -> elt) -> t - 440 val Base.String.equal : t -> t -> bool - 443 val Base.Exn.to_string : t -> string - 443 val Base.Sexp.of_string : unit - 443 mod Base.Bytes.To_string - 443 mod Shadow_stdlib.String - 444 val Base.String.append : t -> t -> t - 444 mod Base.String.Caseless - 444 mod Base.String.Escaping - 445 val Base.String.init : int -> f:(int -> elt) -> t - 446 val Base.String.tr : target:char -> replacement:char -> t -> t - 446 val Base.String.prefix : t -> int -> t - 446 val Base.String.suffix : t -> int -> t - 446 val Base.String.escaped : t -> t - 447 val Base.String.iter : t -> f:(elt -> unit) -> unit - 448 val Base.String.split : t -> on:char -> t list + 164 val Base.String.rev : t -> t + 166 val Base.Sexp.of_string : unit + 167 val Base.String.hash : t -> int + 168 val Base.String.escaped : t -> t + 168 val Base.String.max_length : int + 169 val Base.String.(^) : t -> t -> t + 170 val Base.String.uppercase : t -> t + 171 val Base.String.capitalize : t -> t + 172 val Base.Exn.to_string : t -> string + 172 val Base.String.append : t -> t -> t + 174 val Base.String.equal : t -> t -> bool + 174 val Base.String.prefix : t -> int -> t + 174 val Base.String.suffix : t -> int -> t + 174 val Base.Float.to_string : t -> string + 175 val Base.String.compare : t -> t -> int + 177 val Base.String.ascending : t -> t -> int + 177 val Base.String.split_lines : t -> t list + 179 val Base.String.drop_prefix : t -> int -> t + 179 val Base.String.drop_suffix : t -> int -> t + 179 val Base.String.common_prefix : t list -> t + 179 val Base.String.common_suffix : t list -> t + 180 val Base.String.to_list_rev : t -> char list + 180 val Base.String.common_prefix2 : t -> t -> t + 180 val Base.String.common_suffix2 : t -> t -> t + 182 val Base.Or_error.error_string : string -> _ t diff --git a/test/cram/base_web.t b/test/cram/base_web.t index ab33c8f141..1d93201aea 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -18,8 +18,8 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2076 db.js - 1564 db.js.gz + 2220 db.js + 1676 db.js.gz 1548 megaodocl.gz $ for f in $(find . -name '*.odocl'); do diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index b125e9649e..c01f40e487 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -16,24 +16,24 @@ val Main.multiple_hit_2 : foo val Main.multiple_hit_3 : foo $ sherlodoc search --print-cost "name_conflict" - 832 val Main.name_conflict : foo - 832 type Main.name_conflict = foo + 169 val Main.name_conflict : foo + 169 type Main.name_conflict = foo $ sherlodoc search "nesting_priority" val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo $ sherlodoc search "list" - mod Main.List type 'a Main.list - type 'a Main.List.t = 'a list val Main.Map.to_list : foo + type 'a Main.List.t = 'a list val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + mod Main.List val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo $ sherlodoc search "map" - mod Main.Map val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.Map.to_list : foo + mod Main.Map val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo @@ -56,30 +56,30 @@ val Main.value : moo $ sherlodoc search ":moo -> _" val Main.consume : moo -> unit + cons Main.MyExtension : moo -> extensible_type val Main.consume_2 : moo -> moo -> unit val Main.consume_2_other : moo -> t -> unit - cons Main.MyExtension : moo -> extensible_type $ sherlodoc search "modtype" sig Main.Modtype val Main.Modtype.v_modtype : foo $ sherlodoc search "S" sig Main.S - mod Main.List - mod Main.Nest mod Main.S_to_S1 type 'a Main.list + type Main.MyExtension + type Main.extensible_type = .. type 'a Main.List.t = 'a list val Main.consume : moo -> unit val Main.Map.to_list : foo - val Main.consume_2 : moo -> moo -> unit - val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - type Main.extensible_type = .. - val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - type Main.MyExtension val Main.nesting_priority : foo + val Main.consume_2 : moo -> moo -> unit + val Main.Nest.nesting_priority : foo val Main.consume_2_other : moo -> t -> unit cons Main.MyExtension : moo -> extensible_type - val Main.Nest.nesting_priority : foo + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + mod Main.List + mod Main.Nest + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo $ sherlodoc search "qwertyuiopasdfghjklzxcvbnm" @@ -94,19 +94,19 @@ TODO : get a result for the query bellow $ sherlodoc search ":'a" val Main.poly_1 : 'a -> 'b -> 'c val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c - val Main.poly_param : 'a boo val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + val Main.poly_param : 'a boo $ sherlodoc search ": 'a -> 'b -> 'c " val Main.poly_1 : 'a -> 'b -> 'c val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c - val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list $ sherlodoc search ": ('a -> 'b) -> 'a t -> 'b t" val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list TODO : get a result for the query bellow $ sherlodoc search ": 'a bo" val Main.poly_param : 'a boo diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index fce70d25ce..95daa0756a 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -8,10 +8,10 @@ $ export SHERLODOC_FORMAT=ancient $ sherlodoc index $(find . -name '*.odocl') $ sherlodoc search --print-cost "list" - 263 mod Main.List - 763 type 'a Main.list - 891 type 'a Main.List.t = 'a list - 923 val Main.List.empty : 'a t * 'b t - 924 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 154 type 'a Main.list + 221 type 'a Main.List.t = 'a list + 229 val Main.List.empty : 'a t * 'b t + 242 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 254 mod Main.List $ sherlodoc search ": (int, 'a) result" val Main.ok_zero : (int, 'a) result diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t index 489086c26d..9c499626d4 100644 --- a/test/cram/module_type_cost.t/run.t +++ b/test/cram/module_type_cost.t/run.t @@ -10,10 +10,10 @@ Here we expect to have the `my_function` from the module be above the one from the module type. $ sherlodoc search --print-cost --no-rhs "my_function" - 839 val Main.M.my_function - 860 val Main.Make.my_function - 1239 val Main.S.my_function + 181 val Main.M.my_function + 184 val Main.Make.my_function + 281 val Main.S.my_function Here we expect both the module type and the module to be ranked the same $ sherlodoc search --print-cost "module" - 416 mod Main.Module_nype - 416 sig Main.Module_type + 281 mod Main.Module_nype + 281 sig Main.Module_type From 6850f595714ac9a176ae40ddab1cd96404cb4d00 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Mon, 15 Jan 2024 11:35:50 +0100 Subject: [PATCH 242/285] prefer names that match query words in order --- query/dynamic_cost.ml | 3 +-- query/name_cost.ml | 26 +++++++++++++++----------- query/type_distance.ml | 2 +- test/cram/base_cli.t | 24 ++++++++++++------------ 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 1e4268f2d4..9c19d3e89d 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -21,8 +21,7 @@ let type_distance query_type entry = | _ -> None let score query entry = - let found, not_found = Name_cost.best_matches query.name entry.Db.Entry.name in - let name_matches = found + not_found in + let name_matches = Name_cost.best_matches query.name entry.Db.Entry.name in let type_cost = match type_distance query.type_paths entry with | Some cost -> cost diff --git a/query/name_cost.ml b/query/name_cost.ml index 1081cdbb00..650a12404e 100644 --- a/query/name_cost.ml +++ b/query/name_cost.ml @@ -37,23 +37,27 @@ let word_boundary s i = then 3 else 10 -let best_match ~sub str = +let best_match ?(after = 0) ~sub str = List.fold_left (fun acc (i, case_cost) -> let left = word_boundary str (i - 1) in let right = word_boundary str (i + String.length sub) in - let cost = case_cost + left + right in + let is_after = if i >= after then 0 else 10 in + let cost = case_cost + left + right + is_after in match acc with - | Some cost' when cost' < cost -> acc - | _ -> Some cost) + | Some (_, cost') when cost' < cost -> acc + | _ -> Some (i, cost)) None (find_all ~sub str) let best_matches words str = - List.fold_left - (fun (found, not_found) sub -> - match best_match ~sub str with - | Some cost -> found + cost, not_found - | None -> found, not_found + String.length sub + 50) - (0, 0) - words + let _, found, not_found = + List.fold_left + (fun (i, found, not_found) sub -> + match best_match ~after:i ~sub str with + | Some (i, cost) -> i + String.length sub, found + cost, not_found + | None -> i, found, not_found + String.length sub + 50) + (0, 0, 0) + words + in + found + not_found diff --git a/query/type_distance.ml b/query/type_distance.ml index 94543081ca..a8f32164ff 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -113,7 +113,7 @@ let distance xs ys = let cost = match Name_cost.best_match ~sub:x y with | None -> skip_x + skip_y - | Some cost -> cost + | Some (_, cost) -> cost in min (cost + memo (i + 1) (j + 1) xs' ys') diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 51af0f5e7c..e4e5c73045 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -124,25 +124,25 @@ 307 val Base.Map.S_poly.rank : ('k, _) t -> 'k -> int option 307 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int $ sherlodoc search --print-cost --no-rhs "group b" - 260 val Base.List.group - 267 val Base.Sequence.group 281 val Base.Set.group_by - 290 val Base.List.Assoc.group - 290 val Base.List.sort_and_group - 320 val Base.List.Assoc.sort_and_group - 358 val Base.List.groupi + 360 val Base.List.group + 367 val Base.Sequence.group 375 val Base.Set.Poly.group_by - 378 val Base.Hashtbl.group + 390 val Base.List.Assoc.group + 390 val Base.List.sort_and_group 403 val Base.Set.Using_comparator.group_by 413 val Base.Set.Using_comparator.Tree.group_by + 420 val Base.List.Assoc.sort_and_group + 458 val Base.List.groupi 477 val Base.Set.S_poly.group_by - 478 val Base.Hashtbl.Poly.group - 485 val Base.Hashtbl.Creators.group - 492 val Base.Hashtbl.Creators.group - 504 val Base.Hashtbl.S_without_submodules.group + 478 val Base.Hashtbl.group 512 val Base.Set.Accessors_generic.group_by 525 val Base.Set.Creators_and_accessors_generic.group_by - 580 val Base.Hashtbl.S_poly.group + 578 val Base.Hashtbl.Poly.group + 585 val Base.Hashtbl.Creators.group + 592 val Base.Hashtbl.Creators.group + 604 val Base.Hashtbl.S_without_submodules.group + 680 val Base.Hashtbl.S_poly.group $ sherlodoc search --no-rhs "group by" val Base.Set.group_by val Base.Set.Poly.group_by From c14665ada39f1f254f97e947e904cbc1c3091499 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Mon, 15 Jan 2024 12:07:43 +0100 Subject: [PATCH 243/285] remove unused array_succ --- query/array_succ.ml | 80 ---------------------------------------- query/query.ml | 1 - query/query.mli | 1 - query/test/test.ml | 7 +--- query/test/test_array.ml | 63 ------------------------------- query/test/test_succ.ml | 11 +++--- 6 files changed, 7 insertions(+), 156 deletions(-) delete mode 100644 query/array_succ.ml delete mode 100644 query/test/test_array.ml diff --git a/query/array_succ.ml b/query/array_succ.ml deleted file mode 100644 index a0eb3106db..0000000000 --- a/query/array_succ.ml +++ /dev/null @@ -1,80 +0,0 @@ -(** This module allows searching for the successor of a value in a sorted array. - The array are assumed to be sorted : this is not checked. As this is tricky - code, it is unit-tested. *) - -let get = Array.get - -let rec succ_ge ~compare elt arr lo hi = - let elt_lo = get arr lo in - if compare elt_lo elt >= 0 - then elt_lo - else if lo = hi - then (* in that case, above branch should have been triggered *) - assert false - else if lo = hi - 1 - then ( - let elt_hi = get arr hi in - assert (compare elt_hi elt >= 0) ; - elt_hi) - else ( - let mid = (lo + hi) / 2 in - let elt' = get arr mid in - let comp = compare elt' elt in - if comp = 0 - then elt' - else if comp > 0 - then succ_ge ~compare elt arr lo mid - else succ_ge ~compare elt arr mid hi) - -let succ_ge ~compare elt arr = - if Array.length arr = 0 - then None - else ( - let lo = 0 - and hi = Array.length arr in - if not (compare (get arr (hi - 1)) elt >= 0) - then None - else Some (succ_ge ~compare elt arr lo hi)) - -let rec succ_gt ~compare elt arr lo hi = - let elt_lo = get arr lo in - if compare elt_lo elt > 0 - then elt_lo - else if lo = hi - then (* in that case, above branch should have been triggered *) - assert false - else if lo = hi - 1 - then ( - (* lo is already checked above *) - let elt_hi = get arr hi in - assert (compare elt_hi elt > 0) ; - elt_hi) - else ( - let mid = (lo + hi) / 2 in - let elt' = get arr mid in - let comp = compare elt' elt in - if comp = 0 - then get arr (mid + 1) - else if comp > 0 - then succ_gt ~compare elt arr lo mid - else succ_gt ~compare elt arr mid hi) - -let succ_gt ~compare elt arr = - if Array.length arr = 0 - then None - else ( - let lo = 0 - and hi = Array.length arr in - if not (compare (get arr (hi - 1)) elt > 0) - then None - else Some (succ_gt ~compare elt arr lo hi)) - -let succ_gt_exn ~compare elt arr = - match succ_gt ~compare elt arr with - | None -> raise Not_found - | Some v -> v - -let succ_ge_exn ~compare elt arr = - match succ_ge ~compare elt arr with - | None -> raise Not_found - | Some v -> v diff --git a/query/query.ml b/query/query.ml index f4f2dfb038..134b6be1cb 100644 --- a/query/query.ml +++ b/query/query.ml @@ -4,7 +4,6 @@ module Storage = Db.Storage module Tree = Db.String_automata module Private = struct - module Array_succ = Array_succ module Succ = Succ module Type_parser = struct diff --git a/query/query.mli b/query/query.mli index f81141e058..7f9442410b 100644 --- a/query/query.mli +++ b/query/query.mli @@ -34,7 +34,6 @@ val pretty : t -> string (** For testing *) module Private : sig - module Array_succ = Array_succ module Succ = Succ module Type_parser : sig diff --git a/query/test/test.ml b/query/test/test.ml index 8a45d3e7ac..11fcf5cf4b 100644 --- a/query/test/test.ml +++ b/query/test/test.ml @@ -1,8 +1,3 @@ let () = let open Alcotest in - run - "Query" - [ "Array_succ", Test_array.tests_succ_ge @ Test_array.tests_succ_gt - ; "Succ", Test_succ.tests_to_seq - ; "Type_parser", Test_type_parser.tests - ] + run "Query" [ "Succ", Test_succ.tests_to_seq; "Type_parser", Test_type_parser.tests ] diff --git a/query/test/test_array.ml b/query/test/test_array.ml deleted file mode 100644 index 04db842956..0000000000 --- a/query/test/test_array.ml +++ /dev/null @@ -1,63 +0,0 @@ -open Query.Private - -let rec succ_ge_reference i ~compare elt arr = - Printf.printf "ref_succ_ge %i\n%!" i ; - if i = Array.length arr - then None - else if compare arr.(i) elt >= 0 - then Some arr.(i) - else succ_ge_reference (i + 1) ~compare elt arr - -let rec succ_gt_reference i ~compare elt arr = - if i = Array.length arr - then None - else if compare arr.(i) elt > 0 - then Some arr.(i) - else succ_gt_reference (i + 1) ~compare elt arr - -let succ_ge_reference ~compare elt arr = succ_ge_reference 0 ~compare elt arr -let succ_gt_reference ~compare elt arr = succ_gt_reference 0 ~compare elt arr - -let test_succ_ge elt arr () = - Alcotest.(check (option int)) - "same int option" - (succ_ge_reference ~compare:Int.compare elt arr) - (Array_succ.succ_ge ~compare:Int.compare elt arr) - -let test_succ_gt elt arr () = - Alcotest.(check (option int)) - "same int option" - (succ_gt_reference ~compare:Int.compare elt arr) - (Array_succ.succ_gt ~compare:Int.compare elt arr) - -let () = Random.init 123 - -(* The tests *) - -let random_array size = - let r = - List.init size (fun _ -> Random.int (size * 2)) - |> List.sort_uniq Int.compare - |> Array.of_list - in - r - -let tests_arr name test = - List.init 50 (fun i -> - let elt = Random.int ((i * 2) + 1) in - let arr = random_array i in - let arr_string = - if i <= 5 - then - "[|" - ^ (arr |> Array.to_list |> List.map string_of_int |> String.concat "; ") - ^ "|]" - else "[|...|]" - in - Alcotest.test_case - (Printf.sprintf "%s %i %s " name elt arr_string) - `Quick - (test elt arr)) - -let tests_succ_ge = tests_arr "succ_ge" test_succ_ge -let tests_succ_gt = tests_arr "succ_gt" test_succ_gt diff --git a/query/test/test_succ.ml b/query/test/test_succ.ml index ed3868437d..3650a52f34 100644 --- a/query/test/test_succ.ml +++ b/query/test/test_succ.ml @@ -31,17 +31,18 @@ let extra_succ = (inter (of_array [| 0; 1 |]) (of_array [| 0; 1 |])) (inter (of_array [| 0; 2; 3 |]) (of_array [| 1; 3; 5; 7 |])) +let random_array size = + List.init size (fun _ -> elt @@ Random.int (size * 2)) + |> List.sort_uniq Db.Entry.compare + |> Array.of_list + let rec random_set ~empty ~union ~inter ~of_array size = let random_set = random_set ~empty ~union ~inter ~of_array in if size = 0 then empty else ( match Random.int 3 with - | 0 -> - let arr = Test_array.random_array size in - let arr = Array.map elt arr in - Array.sort Db.Entry.compare arr ; - of_array arr + | 0 -> of_array @@ random_array size | 1 -> inter (random_set (size / 2)) (random_set (size / 2)) | 2 -> union (random_set (size / 2)) (random_set (size / 2)) | _ -> assert false) From beb8c3d219aadf2aae2f2c3e956b890a03ad2af7 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Mon, 15 Jan 2024 15:40:36 +0100 Subject: [PATCH 244/285] fix jsoo odoc_html_frontend leading dot --- jsoo/odoc_html_frontend.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jsoo/odoc_html_frontend.ml b/jsoo/odoc_html_frontend.ml index c44af2a2ad..c24c6ba2f8 100644 --- a/jsoo/odoc_html_frontend.ml +++ b/jsoo/odoc_html_frontend.ml @@ -18,9 +18,10 @@ let of_strings ~kind ~prefix_name ~name ~rhs ~typedecl_params ~doc = ] and prefix_name = match prefix_name with + | None -> [] + | Some "" -> [] | Some prefix_name -> [ span ~a:[ a_class [ "prefix-name" ] ] [ txt (prefix_name ^ ".") ] ] - | None -> [] and name = match name with | Some name -> [ span ~a:[ a_class [ "entry-name" ] ] [ txt name ] ] From b7a87cf1cad6b48467bb60ff529b061e8a0d0423 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 15 Jan 2024 17:22:47 +0100 Subject: [PATCH 245/285] Update type_polarity.mli comment --- db/type_polarity.mli | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/db/type_polarity.mli b/db/type_polarity.mli index 50235b80a7..49d4b742f0 100644 --- a/db/type_polarity.mli +++ b/db/type_polarity.mli @@ -14,7 +14,7 @@ Once you have computed the polarities of the type of an entry [e], you can register each polarity as corresponding to [e] in the search database. Then, when the user queries for a type, we compute the polarities of the query -type, and search for the entries. The +type, and search for the entries. We then return the result corresponding to intersection of each polarity: if the user queries for [int -> string], we want to have every entry which consumes an @@ -40,11 +40,11 @@ user explicitely asked for two integers to be consumed. To fix this issue, we track the number of occurences of each polarity. The polarities for [int -> int -> string], become [(-int, 2)] and [(+string, -1)], and allows us to filter entries according to this information. The exact -mechanism for this is explained in {!Occ}. +1)], and allows us to filter entries according to this information. There is a mechanism for types with parameters like ['a list]. I might explain it in the future. +TODO : Give an example even if not the full explanation. *) module Sign : sig @@ -76,11 +76,11 @@ val of_typ : any_is_poly:bool -> Typexpr.t -> t Seq.t corresponding to [typ]. - If [any_is_poly] is true, the type [_] will be treated like a type variable - ['a], other it will be represented solely by its sign ("+" or "-"). + ['a], otherwise it will be represented solely by its sign ("+" or "-"). - If [all_names] is true, extra polarities are added for every "possible name" of each type constructor. For instance the possible names of [Stdlib.Int64.t] are ["t"], ["Int64.t"] and ["Stdlib.Int64.t"]. This allows - for the user to use any of the possible name. It is important to set this + the user to use any of the possible name. It is important to set this when registering entries in the database, but you not need it when computing the polarities of a query. *) From 4200c91e44e30d54085f25f5e4b45fe49cf514bc Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 16 Jan 2024 11:45:59 +0100 Subject: [PATCH 246/285] remove fullfilled todo --- test/cram/cli.t/run.t | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index c01f40e487..d1ea3a6bab 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -86,7 +86,6 @@ [No results] $ sherlodoc search "hidden" [No results] -TODO : get a result for the query bellow $ sherlodoc search ":mo" val Main.value : moo val Main.produce : unit -> moo @@ -107,7 +106,6 @@ TODO : get a result for the query bellow val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list -TODO : get a result for the query bellow $ sherlodoc search ": 'a bo" val Main.poly_param : 'a boo $ sherlodoc search ":extensible_type" From ce7a0dee7a4ac78eb96d513ecc061288ef402f19 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 16 Jan 2024 18:17:37 +0100 Subject: [PATCH 247/285] fixes and test empty project bug --- db/string_automata.ml | 2 ++ db/string_automata.mli | 1 + index/suffix_tree.ml | 13 ++++++++----- test/cram/empty.t/dune | 3 +++ test/cram/empty.t/dune-project | 4 ++++ test/cram/empty.t/foo.ml | 1 + test/cram/empty.t/run.t | 9 +++++++++ 7 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 test/cram/empty.t/dune create mode 100644 test/cram/empty.t/dune-project create mode 100644 test/cram/empty.t/foo.ml create mode 100644 test/cram/empty.t/run.t diff --git a/db/string_automata.ml b/db/string_automata.ml index e26338dc61..a0047a20a0 100644 --- a/db/string_automata.ml +++ b/db/string_automata.ml @@ -10,6 +10,8 @@ type t = ; t : node } +let empty = { str = ""; t = { start = 0; len = 0; terminals = None; children = None } } + let array_find ~str chr arr = let rec go i = if i >= Array.length arr diff --git a/db/string_automata.mli b/db/string_automata.mli index 2f4d6edb14..4b4ad60a88 100644 --- a/db/string_automata.mli +++ b/db/string_automata.mli @@ -13,6 +13,7 @@ type t = ; t : node } +val empty : t val find : t -> string -> t option val find_star : t -> string -> t list val minimum : t -> Entry.t diff --git a/index/suffix_tree.ml b/index/suffix_tree.ml index 87a8415f62..b6b123564e 100644 --- a/index/suffix_tree.ml +++ b/index/suffix_tree.ml @@ -356,8 +356,11 @@ let rec export ~cache ~cache_term node = result let export { buffer; root = t } = - let str = Buf.contents buffer in - let cache = Hashtbl.create 16 in - let cache_term = Terminals_cache.create 16 in - let _, t, _ = export ~cache ~cache_term t in - { Db.String_automata.str; t } + if Char_map.is_empty t.children + then Db.String_automata.empty + else ( + let str = Buf.contents buffer in + let cache = Hashtbl.create 16 in + let cache_term = Terminals_cache.create 16 in + let _, t, _ = export ~cache ~cache_term t in + { Db.String_automata.str; t }) diff --git a/test/cram/empty.t/dune b/test/cram/empty.t/dune new file mode 100644 index 0000000000..d5b98e5629 --- /dev/null +++ b/test/cram/empty.t/dune @@ -0,0 +1,3 @@ +(executable + (name foo) + (public_name foo)) diff --git a/test/cram/empty.t/dune-project b/test/cram/empty.t/dune-project new file mode 100644 index 0000000000..82632eb46c --- /dev/null +++ b/test/cram/empty.t/dune-project @@ -0,0 +1,4 @@ +(lang dune 3.7) + +(package + (name foo)) diff --git a/test/cram/empty.t/foo.ml b/test/cram/empty.t/foo.ml new file mode 100644 index 0000000000..8b3c77862e --- /dev/null +++ b/test/cram/empty.t/foo.ml @@ -0,0 +1 @@ +let a = 123 \ No newline at end of file diff --git a/test/cram/empty.t/run.t b/test/cram/empty.t/run.t new file mode 100644 index 0000000000..3073cd3974 --- /dev/null +++ b/test/cram/empty.t/run.t @@ -0,0 +1,9 @@ +This test checkes that project that is empty despite not looking empty does not +crash sherlodoc. + $ export PATH=.:$PATH + $ export OCAMLRUNPARAM=b + $ dune build @doc + $ sherlodoc index ./_build/default/_doc/_odocls/foo/page-index.odocl --format=marshal --db=db.marshal + $ sherlodoc search --db=db.marshal lorem + [No results] + From 421ab5e3f01f25ec6ae965a92f9919062ee55073 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 16 Jan 2024 18:54:56 +0100 Subject: [PATCH 248/285] delete odocls and use odig instead --- dune-project | 4 +- sherlodoc.opam | 2 + test/cram/base_benchmark.t | 157 +++++++++++++- test/cram/base_cli.t | 193 +++++++++++++++--- .../base_odocls/base_internalhash_types.odocl | Bin 3119 -> 0 bytes test/cram/base_odocls/caml.odocl | Bin 28618 -> 0 bytes test/cram/base_odocls/md5_lib.odocl | Bin 2250 -> 0 bytes test/cram/base_odocls/page-index.odocl | Bin 36960 -> 0 bytes test/cram/base_odocls/shadow_stdlib.odocl | Bin 81021 -> 0 bytes test/cram/base_web.t | 171 ++++++++++++++-- test/cram/simple.t/run.t | 2 +- 11 files changed, 479 insertions(+), 50 deletions(-) delete mode 100644 test/cram/base_odocls/base_internalhash_types.odocl delete mode 100644 test/cram/base_odocls/caml.odocl delete mode 100644 test/cram/base_odocls/md5_lib.odocl delete mode 100644 test/cram/base_odocls/page-index.odocl delete mode 100644 test/cram/base_odocls/shadow_stdlib.odocl diff --git a/dune-project b/dune-project index 5bc7214940..ddae2e1186 100644 --- a/dune-project +++ b/dune-project @@ -32,7 +32,9 @@ (tyxml (>= 4.6.0)) (brr (>= 0.0.6)) (ppx_blob (>= 0.7.2)) - (alcotest :with-test)) + (alcotest :with-test) + (odig :with-test) + (base (and :with-test (= v0.16.3)))) (depopts (dream (>= 1.0.0~alpha5)) (ancient (>= 0.9.1)))) diff --git a/sherlodoc.opam b/sherlodoc.opam index 9fc84d1ec7..27831cef24 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -21,6 +21,8 @@ depends: [ "brr" {>= "0.0.6"} "ppx_blob" {>= "0.7.2"} "alcotest" {with-test} + "odig" {with-test} + "base" {with-test & = "v0.16.3"} ] depopts: [ "dream" {>= "1.0.0~alpha5"} diff --git a/test/cram/base_benchmark.t b/test/cram/base_benchmark.t index a3bfbe9472..a8639b2496 100644 --- a/test/cram/base_benchmark.t +++ b/test/cram/base_benchmark.t @@ -1,13 +1,154 @@ This test will fail, it is not deterministic. Please just check that the values are not crazy and discard the changes - $ find . -name '*.odocl' | sort - ./base_odocls/base.odocl - ./base_odocls/base_internalhash_types.odocl - ./base_odocls/caml.odocl - ./base_odocls/md5_lib.odocl - ./base_odocls/page-index.odocl - ./base_odocls/shadow_stdlib.odocl - $ sherlodoc index --format=js --db=db.js $(find . -name '*.odocl') + $ mkdir docs +Generating odocls for base with odig. This might give an error on some +dependencies so we do not display error (one was encountered with yojson) + $ odig odoc --cache-dir=docs base 2> /dev/null + Updating documentation, this may take some time... + $ find ./docs/odoc/base/ -name '*.odocl' | sort + ./docs/odoc/base/base.odocl + ./docs/odoc/base/base__.odocl + ./docs/odoc/base/base__Applicative.odocl + ./docs/odoc/base/base__Applicative_intf.odocl + ./docs/odoc/base/base__Array.odocl + ./docs/odoc/base/base__Array0.odocl + ./docs/odoc/base/base__Array_permute.odocl + ./docs/odoc/base/base__Avltree.odocl + ./docs/odoc/base/base__Backtrace.odocl + ./docs/odoc/base/base__Binary_search.odocl + ./docs/odoc/base/base__Binary_searchable.odocl + ./docs/odoc/base/base__Binary_searchable_intf.odocl + ./docs/odoc/base/base__Blit.odocl + ./docs/odoc/base/base__Blit_intf.odocl + ./docs/odoc/base/base__Bool.odocl + ./docs/odoc/base/base__Bool0.odocl + ./docs/odoc/base/base__Buffer.odocl + ./docs/odoc/base/base__Buffer_intf.odocl + ./docs/odoc/base/base__Bytes.odocl + ./docs/odoc/base/base__Bytes0.odocl + ./docs/odoc/base/base__Bytes_tr.odocl + ./docs/odoc/base/base__Char.odocl + ./docs/odoc/base/base__Char0.odocl + ./docs/odoc/base/base__Comparable.odocl + ./docs/odoc/base/base__Comparable_intf.odocl + ./docs/odoc/base/base__Comparator.odocl + ./docs/odoc/base/base__Comparisons.odocl + ./docs/odoc/base/base__Container.odocl + ./docs/odoc/base/base__Container_intf.odocl + ./docs/odoc/base/base__Either.odocl + ./docs/odoc/base/base__Either0.odocl + ./docs/odoc/base/base__Either_intf.odocl + ./docs/odoc/base/base__Equal.odocl + ./docs/odoc/base/base__Error.odocl + ./docs/odoc/base/base__Exn.odocl + ./docs/odoc/base/base__Field.odocl + ./docs/odoc/base/base__Fieldslib.odocl + ./docs/odoc/base/base__Float.odocl + ./docs/odoc/base/base__Float0.odocl + ./docs/odoc/base/base__Floatable.odocl + ./docs/odoc/base/base__Fn.odocl + ./docs/odoc/base/base__Formatter.odocl + ./docs/odoc/base/base__Globalize.odocl + ./docs/odoc/base/base__Hash.odocl + ./docs/odoc/base/base__Hash_intf.odocl + ./docs/odoc/base/base__Hash_set.odocl + ./docs/odoc/base/base__Hash_set_intf.odocl + ./docs/odoc/base/base__Hashable.odocl + ./docs/odoc/base/base__Hashable_intf.odocl + ./docs/odoc/base/base__Hasher.odocl + ./docs/odoc/base/base__Hashtbl.odocl + ./docs/odoc/base/base__Hashtbl_intf.odocl + ./docs/odoc/base/base__Hex_lexer.odocl + ./docs/odoc/base/base__Identifiable.odocl + ./docs/odoc/base/base__Identifiable_intf.odocl + ./docs/odoc/base/base__Import.odocl + ./docs/odoc/base/base__Import0.odocl + ./docs/odoc/base/base__Indexed_container.odocl + ./docs/odoc/base/base__Indexed_container_intf.odocl + ./docs/odoc/base/base__Info.odocl + ./docs/odoc/base/base__Info_intf.odocl + ./docs/odoc/base/base__Int.odocl + ./docs/odoc/base/base__Int0.odocl + ./docs/odoc/base/base__Int32.odocl + ./docs/odoc/base/base__Int63.odocl + ./docs/odoc/base/base__Int63_emul.odocl + ./docs/odoc/base/base__Int64.odocl + ./docs/odoc/base/base__Int_conversions.odocl + ./docs/odoc/base/base__Int_intf.odocl + ./docs/odoc/base/base__Int_math.odocl + ./docs/odoc/base/base__Intable.odocl + ./docs/odoc/base/base__Invariant.odocl + ./docs/odoc/base/base__Invariant_intf.odocl + ./docs/odoc/base/base__Lazy.odocl + ./docs/odoc/base/base__Linked_queue.odocl + ./docs/odoc/base/base__Linked_queue0.odocl + ./docs/odoc/base/base__List.odocl + ./docs/odoc/base/base__List0.odocl + ./docs/odoc/base/base__List1.odocl + ./docs/odoc/base/base__Map.odocl + ./docs/odoc/base/base__Map_intf.odocl + ./docs/odoc/base/base__Maybe_bound.odocl + ./docs/odoc/base/base__Monad.odocl + ./docs/odoc/base/base__Monad_intf.odocl + ./docs/odoc/base/base__Nativeint.odocl + ./docs/odoc/base/base__Nothing.odocl + ./docs/odoc/base/base__Obj_array.odocl + ./docs/odoc/base/base__Obj_local.odocl + ./docs/odoc/base/base__Option.odocl + ./docs/odoc/base/base__Option_array.odocl + ./docs/odoc/base/base__Or_error.odocl + ./docs/odoc/base/base__Ordered_collection_common.odocl + ./docs/odoc/base/base__Ordered_collection_common0.odocl + ./docs/odoc/base/base__Ordering.odocl + ./docs/odoc/base/base__Poly0.odocl + ./docs/odoc/base/base__Popcount.odocl + ./docs/odoc/base/base__Pow_overflow_bounds.odocl + ./docs/odoc/base/base__Ppx_compare_lib.odocl + ./docs/odoc/base/base__Ppx_enumerate_lib.odocl + ./docs/odoc/base/base__Ppx_hash_lib.odocl + ./docs/odoc/base/base__Pretty_printer.odocl + ./docs/odoc/base/base__Printf.odocl + ./docs/odoc/base/base__Queue.odocl + ./docs/odoc/base/base__Queue_intf.odocl + ./docs/odoc/base/base__Random.odocl + ./docs/odoc/base/base__Random_repr.odocl + ./docs/odoc/base/base__Ref.odocl + ./docs/odoc/base/base__Result.odocl + ./docs/odoc/base/base__Sequence.odocl + ./docs/odoc/base/base__Set.odocl + ./docs/odoc/base/base__Set_intf.odocl + ./docs/odoc/base/base__Sexp.odocl + ./docs/odoc/base/base__Sexp_with_comparable.odocl + ./docs/odoc/base/base__Sexpable.odocl + ./docs/odoc/base/base__Sign.odocl + ./docs/odoc/base/base__Sign0.odocl + ./docs/odoc/base/base__Sign_or_nan.odocl + ./docs/odoc/base/base__Source_code_position.odocl + ./docs/odoc/base/base__Source_code_position0.odocl + ./docs/odoc/base/base__Stack.odocl + ./docs/odoc/base/base__Stack_intf.odocl + ./docs/odoc/base/base__Staged.odocl + ./docs/odoc/base/base__String.odocl + ./docs/odoc/base/base__String0.odocl + ./docs/odoc/base/base__Stringable.odocl + ./docs/odoc/base/base__Sys.odocl + ./docs/odoc/base/base__Sys0.odocl + ./docs/odoc/base/base__T.odocl + ./docs/odoc/base/base__Type_equal.odocl + ./docs/odoc/base/base__Uchar.odocl + ./docs/odoc/base/base__Uchar0.odocl + ./docs/odoc/base/base__Uniform_array.odocl + ./docs/odoc/base/base__Unit.odocl + ./docs/odoc/base/base__Variant.odocl + ./docs/odoc/base/base__Variantslib.odocl + ./docs/odoc/base/base__With_return.odocl + ./docs/odoc/base/base__Word_size.odocl + ./docs/odoc/base/base_internalhash_types/base_internalhash_types.odocl + ./docs/odoc/base/caml/caml.odocl + ./docs/odoc/base/md5/md5_lib.odocl + ./docs/odoc/base/page-index.odocl + ./docs/odoc/base/shadow_stdlib/shadow_stdlib.odocl + $ sherlodoc index --format=js --db=db.js $(find ./docs/odoc/base/ -name '*.odocl') > /dev/null diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index e4e5c73045..8d289a6529 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -1,13 +1,154 @@ - $ find . -name '*.odocl' | sort - ./base_odocls/base.odocl - ./base_odocls/base_internalhash_types.odocl - ./base_odocls/caml.odocl - ./base_odocls/md5_lib.odocl - ./base_odocls/page-index.odocl - ./base_odocls/shadow_stdlib.odocl + $ mkdir docs +Generating odocls for base with odig. This might give an error on some +dependencies so we do not display error (one was encountered with yojson) + $ odig odoc --cache-dir=docs base 2> /dev/null + Updating documentation, this may take some time... + $ find ./docs/odoc/base/ -name '*.odocl' | sort + ./docs/odoc/base/base.odocl + ./docs/odoc/base/base__.odocl + ./docs/odoc/base/base__Applicative.odocl + ./docs/odoc/base/base__Applicative_intf.odocl + ./docs/odoc/base/base__Array.odocl + ./docs/odoc/base/base__Array0.odocl + ./docs/odoc/base/base__Array_permute.odocl + ./docs/odoc/base/base__Avltree.odocl + ./docs/odoc/base/base__Backtrace.odocl + ./docs/odoc/base/base__Binary_search.odocl + ./docs/odoc/base/base__Binary_searchable.odocl + ./docs/odoc/base/base__Binary_searchable_intf.odocl + ./docs/odoc/base/base__Blit.odocl + ./docs/odoc/base/base__Blit_intf.odocl + ./docs/odoc/base/base__Bool.odocl + ./docs/odoc/base/base__Bool0.odocl + ./docs/odoc/base/base__Buffer.odocl + ./docs/odoc/base/base__Buffer_intf.odocl + ./docs/odoc/base/base__Bytes.odocl + ./docs/odoc/base/base__Bytes0.odocl + ./docs/odoc/base/base__Bytes_tr.odocl + ./docs/odoc/base/base__Char.odocl + ./docs/odoc/base/base__Char0.odocl + ./docs/odoc/base/base__Comparable.odocl + ./docs/odoc/base/base__Comparable_intf.odocl + ./docs/odoc/base/base__Comparator.odocl + ./docs/odoc/base/base__Comparisons.odocl + ./docs/odoc/base/base__Container.odocl + ./docs/odoc/base/base__Container_intf.odocl + ./docs/odoc/base/base__Either.odocl + ./docs/odoc/base/base__Either0.odocl + ./docs/odoc/base/base__Either_intf.odocl + ./docs/odoc/base/base__Equal.odocl + ./docs/odoc/base/base__Error.odocl + ./docs/odoc/base/base__Exn.odocl + ./docs/odoc/base/base__Field.odocl + ./docs/odoc/base/base__Fieldslib.odocl + ./docs/odoc/base/base__Float.odocl + ./docs/odoc/base/base__Float0.odocl + ./docs/odoc/base/base__Floatable.odocl + ./docs/odoc/base/base__Fn.odocl + ./docs/odoc/base/base__Formatter.odocl + ./docs/odoc/base/base__Globalize.odocl + ./docs/odoc/base/base__Hash.odocl + ./docs/odoc/base/base__Hash_intf.odocl + ./docs/odoc/base/base__Hash_set.odocl + ./docs/odoc/base/base__Hash_set_intf.odocl + ./docs/odoc/base/base__Hashable.odocl + ./docs/odoc/base/base__Hashable_intf.odocl + ./docs/odoc/base/base__Hasher.odocl + ./docs/odoc/base/base__Hashtbl.odocl + ./docs/odoc/base/base__Hashtbl_intf.odocl + ./docs/odoc/base/base__Hex_lexer.odocl + ./docs/odoc/base/base__Identifiable.odocl + ./docs/odoc/base/base__Identifiable_intf.odocl + ./docs/odoc/base/base__Import.odocl + ./docs/odoc/base/base__Import0.odocl + ./docs/odoc/base/base__Indexed_container.odocl + ./docs/odoc/base/base__Indexed_container_intf.odocl + ./docs/odoc/base/base__Info.odocl + ./docs/odoc/base/base__Info_intf.odocl + ./docs/odoc/base/base__Int.odocl + ./docs/odoc/base/base__Int0.odocl + ./docs/odoc/base/base__Int32.odocl + ./docs/odoc/base/base__Int63.odocl + ./docs/odoc/base/base__Int63_emul.odocl + ./docs/odoc/base/base__Int64.odocl + ./docs/odoc/base/base__Int_conversions.odocl + ./docs/odoc/base/base__Int_intf.odocl + ./docs/odoc/base/base__Int_math.odocl + ./docs/odoc/base/base__Intable.odocl + ./docs/odoc/base/base__Invariant.odocl + ./docs/odoc/base/base__Invariant_intf.odocl + ./docs/odoc/base/base__Lazy.odocl + ./docs/odoc/base/base__Linked_queue.odocl + ./docs/odoc/base/base__Linked_queue0.odocl + ./docs/odoc/base/base__List.odocl + ./docs/odoc/base/base__List0.odocl + ./docs/odoc/base/base__List1.odocl + ./docs/odoc/base/base__Map.odocl + ./docs/odoc/base/base__Map_intf.odocl + ./docs/odoc/base/base__Maybe_bound.odocl + ./docs/odoc/base/base__Monad.odocl + ./docs/odoc/base/base__Monad_intf.odocl + ./docs/odoc/base/base__Nativeint.odocl + ./docs/odoc/base/base__Nothing.odocl + ./docs/odoc/base/base__Obj_array.odocl + ./docs/odoc/base/base__Obj_local.odocl + ./docs/odoc/base/base__Option.odocl + ./docs/odoc/base/base__Option_array.odocl + ./docs/odoc/base/base__Or_error.odocl + ./docs/odoc/base/base__Ordered_collection_common.odocl + ./docs/odoc/base/base__Ordered_collection_common0.odocl + ./docs/odoc/base/base__Ordering.odocl + ./docs/odoc/base/base__Poly0.odocl + ./docs/odoc/base/base__Popcount.odocl + ./docs/odoc/base/base__Pow_overflow_bounds.odocl + ./docs/odoc/base/base__Ppx_compare_lib.odocl + ./docs/odoc/base/base__Ppx_enumerate_lib.odocl + ./docs/odoc/base/base__Ppx_hash_lib.odocl + ./docs/odoc/base/base__Pretty_printer.odocl + ./docs/odoc/base/base__Printf.odocl + ./docs/odoc/base/base__Queue.odocl + ./docs/odoc/base/base__Queue_intf.odocl + ./docs/odoc/base/base__Random.odocl + ./docs/odoc/base/base__Random_repr.odocl + ./docs/odoc/base/base__Ref.odocl + ./docs/odoc/base/base__Result.odocl + ./docs/odoc/base/base__Sequence.odocl + ./docs/odoc/base/base__Set.odocl + ./docs/odoc/base/base__Set_intf.odocl + ./docs/odoc/base/base__Sexp.odocl + ./docs/odoc/base/base__Sexp_with_comparable.odocl + ./docs/odoc/base/base__Sexpable.odocl + ./docs/odoc/base/base__Sign.odocl + ./docs/odoc/base/base__Sign0.odocl + ./docs/odoc/base/base__Sign_or_nan.odocl + ./docs/odoc/base/base__Source_code_position.odocl + ./docs/odoc/base/base__Source_code_position0.odocl + ./docs/odoc/base/base__Stack.odocl + ./docs/odoc/base/base__Stack_intf.odocl + ./docs/odoc/base/base__Staged.odocl + ./docs/odoc/base/base__String.odocl + ./docs/odoc/base/base__String0.odocl + ./docs/odoc/base/base__Stringable.odocl + ./docs/odoc/base/base__Sys.odocl + ./docs/odoc/base/base__Sys0.odocl + ./docs/odoc/base/base__T.odocl + ./docs/odoc/base/base__Type_equal.odocl + ./docs/odoc/base/base__Uchar.odocl + ./docs/odoc/base/base__Uchar0.odocl + ./docs/odoc/base/base__Uniform_array.odocl + ./docs/odoc/base/base__Unit.odocl + ./docs/odoc/base/base__Variant.odocl + ./docs/odoc/base/base__Variantslib.odocl + ./docs/odoc/base/base__With_return.odocl + ./docs/odoc/base/base__Word_size.odocl + ./docs/odoc/base/base_internalhash_types/base_internalhash_types.odocl + ./docs/odoc/base/caml/caml.odocl + ./docs/odoc/base/md5/md5_lib.odocl + ./docs/odoc/base/page-index.odocl + ./docs/odoc/base/shadow_stdlib/shadow_stdlib.odocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=ancient - $ sherlodoc index --index-docstring=false $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc index --index-docstring=false $(find ./docs/odoc/base/ -name "*.odocl") > /dev/null $ sherlodoc search --print-cost --limit 100 "S_poly" 195 val Base.Set.S_poly.mem : 'a t -> 'a -> bool 202 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list @@ -225,6 +366,7 @@ 97 val Base.String.split_lines : t -> t list 100 val Base.String.to_list_rev : t -> char list 103 val Base.Sequence.to_list_rev : 'a t -> 'a list + 105 val Caml.(@) : 'a list -> 'a list -> 'a list 105 val Base.Pretty_printer.all : unit -> string list 109 val Base.Set.to_list : ('a, _) t -> 'a list 110 val Base.Hashtbl.data : (_, 'b) t -> 'b list @@ -245,13 +387,20 @@ 142 val Base.Hashtbl.find_multi : ('a, 'b list) t -> 'a key -> 'b list 143 val Base.List.concat : 'a t t -> 'a t 145 val Base.List.ignore_m : 'a t -> unit t - 146 val Base.Hashtbl.Poly.to_alist : ('a, 'b) t -> ('a key * 'b) list Partial name search: $ sherlodoc search --print-cost "strin" + 169 val Caml.string_of_int : int -> string + 171 val Caml.string_of_bool : bool -> string + 173 val Caml.string_of_float : float -> string 186 val Base.Sexp.of_string : unit + 189 val Caml.prerr_string : string -> unit + 189 val Caml.print_string : string -> unit + 189 val Caml.int_of_string : string -> int + 191 val Caml.bool_of_string : string -> bool 192 val Base.Exn.to_string : t -> string 192 val Base.Sys.max_string_length : int + 193 val Caml.float_of_string : string -> float 194 val Base.Float.to_string : t -> string 197 val Base.Exn.to_string_mach : t -> string 197 val Base.Info.to_string_hum : t -> string @@ -259,21 +408,13 @@ Partial name search: 198 val Base.Error.to_string_hum : t -> string 198 val Base.Info.to_string_mach : t -> string 199 val Base.Error.to_string_mach : t -> string + 200 val Caml.int_of_string_opt : string -> int option + 201 val Caml.string_of_format : ('a, 'b, 'c, 'd, 'e, 'f) format6 -> string + 202 val Caml.bool_of_string_opt : string -> bool option 202 val Base.Or_error.error_string : string -> _ t 204 val Base.Buffer.add_string : t -> string -> unit + 204 val Caml.float_of_string_opt : string -> float option 204 val Base.Sign_or_nan.to_string_hum : t -> string - 208 val Base.Info.to_string_hum_deprecated : t -> string - 209 val Base.Error.to_string_hum_deprecated : t -> string - 209 val Base.Float.to_padded_compact_string : t -> string - 209 val Base.Source_code_position.to_string : t -> string - 214 val Base.String.rev : t -> t - 215 val Base.Int.to_string_hum : ?delimiter:char -> t -> string - 217 val Base.String.hash : t -> int - 217 val Base.Int32.to_string_hum : ?delimiter:char -> t -> string - 217 val Base.Int63.to_string_hum : ?delimiter:char -> t -> string - 217 val Base.Int64.to_string_hum : ?delimiter:char -> t -> string - 218 val Base.String.escaped : t -> t - 218 val Base.String.max_length : int $ sherlodoc search --print-cost "tring" 164 val Base.String.rev : t -> t 166 val Base.Sexp.of_string : unit @@ -281,10 +422,15 @@ Partial name search: 168 val Base.String.escaped : t -> t 168 val Base.String.max_length : int 169 val Base.String.(^) : t -> t -> t + 169 val Caml.prerr_string : string -> unit + 169 val Caml.print_string : string -> unit + 169 val Caml.int_of_string : string -> int 170 val Base.String.uppercase : t -> t + 171 val Caml.bool_of_string : string -> bool 171 val Base.String.capitalize : t -> t 172 val Base.Exn.to_string : t -> string 172 val Base.String.append : t -> t -> t + 173 val Caml.float_of_string : string -> float 174 val Base.String.equal : t -> t -> bool 174 val Base.String.prefix : t -> int -> t 174 val Base.String.suffix : t -> int -> t @@ -294,9 +440,4 @@ Partial name search: 177 val Base.String.split_lines : t -> t list 179 val Base.String.drop_prefix : t -> int -> t 179 val Base.String.drop_suffix : t -> int -> t - 179 val Base.String.common_prefix : t list -> t 179 val Base.String.common_suffix : t list -> t - 180 val Base.String.to_list_rev : t -> char list - 180 val Base.String.common_prefix2 : t -> t -> t - 180 val Base.String.common_suffix2 : t -> t -> t - 182 val Base.Or_error.error_string : string -> _ t diff --git a/test/cram/base_odocls/base_internalhash_types.odocl b/test/cram/base_odocls/base_internalhash_types.odocl deleted file mode 100644 index 74916f84bd0be14f7f9d6ea9ea2bedc89ef7b144..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3119 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 diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 1d93201aea..5a70e1ef24 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -1,14 +1,155 @@ - $ find . -name '*.odocl' | sort - ./base_odocls/base.odocl - ./base_odocls/base_internalhash_types.odocl - ./base_odocls/caml.odocl - ./base_odocls/md5_lib.odocl - ./base_odocls/page-index.odocl - ./base_odocls/shadow_stdlib.odocl - $ cat $(find . -name '*.odocl') > megaodocl + $ mkdir docs +Generating odocls for base with odig. This might give an error on some +dependencies so we do not display error (one was encountered with yojson) + $ odig odoc --cache-dir=docs base 2> /dev/null + Updating documentation, this may take some time... + $ find ./docs/odoc/base/ -name '*.odocl' | sort + ./docs/odoc/base/base.odocl + ./docs/odoc/base/base__.odocl + ./docs/odoc/base/base__Applicative.odocl + ./docs/odoc/base/base__Applicative_intf.odocl + ./docs/odoc/base/base__Array.odocl + ./docs/odoc/base/base__Array0.odocl + ./docs/odoc/base/base__Array_permute.odocl + ./docs/odoc/base/base__Avltree.odocl + ./docs/odoc/base/base__Backtrace.odocl + ./docs/odoc/base/base__Binary_search.odocl + ./docs/odoc/base/base__Binary_searchable.odocl + ./docs/odoc/base/base__Binary_searchable_intf.odocl + ./docs/odoc/base/base__Blit.odocl + ./docs/odoc/base/base__Blit_intf.odocl + ./docs/odoc/base/base__Bool.odocl + ./docs/odoc/base/base__Bool0.odocl + ./docs/odoc/base/base__Buffer.odocl + ./docs/odoc/base/base__Buffer_intf.odocl + ./docs/odoc/base/base__Bytes.odocl + ./docs/odoc/base/base__Bytes0.odocl + ./docs/odoc/base/base__Bytes_tr.odocl + ./docs/odoc/base/base__Char.odocl + ./docs/odoc/base/base__Char0.odocl + ./docs/odoc/base/base__Comparable.odocl + ./docs/odoc/base/base__Comparable_intf.odocl + ./docs/odoc/base/base__Comparator.odocl + ./docs/odoc/base/base__Comparisons.odocl + ./docs/odoc/base/base__Container.odocl + ./docs/odoc/base/base__Container_intf.odocl + ./docs/odoc/base/base__Either.odocl + ./docs/odoc/base/base__Either0.odocl + ./docs/odoc/base/base__Either_intf.odocl + ./docs/odoc/base/base__Equal.odocl + ./docs/odoc/base/base__Error.odocl + ./docs/odoc/base/base__Exn.odocl + ./docs/odoc/base/base__Field.odocl + ./docs/odoc/base/base__Fieldslib.odocl + ./docs/odoc/base/base__Float.odocl + ./docs/odoc/base/base__Float0.odocl + ./docs/odoc/base/base__Floatable.odocl + ./docs/odoc/base/base__Fn.odocl + ./docs/odoc/base/base__Formatter.odocl + ./docs/odoc/base/base__Globalize.odocl + ./docs/odoc/base/base__Hash.odocl + ./docs/odoc/base/base__Hash_intf.odocl + ./docs/odoc/base/base__Hash_set.odocl + ./docs/odoc/base/base__Hash_set_intf.odocl + ./docs/odoc/base/base__Hashable.odocl + ./docs/odoc/base/base__Hashable_intf.odocl + ./docs/odoc/base/base__Hasher.odocl + ./docs/odoc/base/base__Hashtbl.odocl + ./docs/odoc/base/base__Hashtbl_intf.odocl + ./docs/odoc/base/base__Hex_lexer.odocl + ./docs/odoc/base/base__Identifiable.odocl + ./docs/odoc/base/base__Identifiable_intf.odocl + ./docs/odoc/base/base__Import.odocl + ./docs/odoc/base/base__Import0.odocl + ./docs/odoc/base/base__Indexed_container.odocl + ./docs/odoc/base/base__Indexed_container_intf.odocl + ./docs/odoc/base/base__Info.odocl + ./docs/odoc/base/base__Info_intf.odocl + ./docs/odoc/base/base__Int.odocl + ./docs/odoc/base/base__Int0.odocl + ./docs/odoc/base/base__Int32.odocl + ./docs/odoc/base/base__Int63.odocl + ./docs/odoc/base/base__Int63_emul.odocl + ./docs/odoc/base/base__Int64.odocl + ./docs/odoc/base/base__Int_conversions.odocl + ./docs/odoc/base/base__Int_intf.odocl + ./docs/odoc/base/base__Int_math.odocl + ./docs/odoc/base/base__Intable.odocl + ./docs/odoc/base/base__Invariant.odocl + ./docs/odoc/base/base__Invariant_intf.odocl + ./docs/odoc/base/base__Lazy.odocl + ./docs/odoc/base/base__Linked_queue.odocl + ./docs/odoc/base/base__Linked_queue0.odocl + ./docs/odoc/base/base__List.odocl + ./docs/odoc/base/base__List0.odocl + ./docs/odoc/base/base__List1.odocl + ./docs/odoc/base/base__Map.odocl + ./docs/odoc/base/base__Map_intf.odocl + ./docs/odoc/base/base__Maybe_bound.odocl + ./docs/odoc/base/base__Monad.odocl + ./docs/odoc/base/base__Monad_intf.odocl + ./docs/odoc/base/base__Nativeint.odocl + ./docs/odoc/base/base__Nothing.odocl + ./docs/odoc/base/base__Obj_array.odocl + ./docs/odoc/base/base__Obj_local.odocl + ./docs/odoc/base/base__Option.odocl + ./docs/odoc/base/base__Option_array.odocl + ./docs/odoc/base/base__Or_error.odocl + ./docs/odoc/base/base__Ordered_collection_common.odocl + ./docs/odoc/base/base__Ordered_collection_common0.odocl + ./docs/odoc/base/base__Ordering.odocl + ./docs/odoc/base/base__Poly0.odocl + ./docs/odoc/base/base__Popcount.odocl + ./docs/odoc/base/base__Pow_overflow_bounds.odocl + ./docs/odoc/base/base__Ppx_compare_lib.odocl + ./docs/odoc/base/base__Ppx_enumerate_lib.odocl + ./docs/odoc/base/base__Ppx_hash_lib.odocl + ./docs/odoc/base/base__Pretty_printer.odocl + ./docs/odoc/base/base__Printf.odocl + ./docs/odoc/base/base__Queue.odocl + ./docs/odoc/base/base__Queue_intf.odocl + ./docs/odoc/base/base__Random.odocl + ./docs/odoc/base/base__Random_repr.odocl + ./docs/odoc/base/base__Ref.odocl + ./docs/odoc/base/base__Result.odocl + ./docs/odoc/base/base__Sequence.odocl + ./docs/odoc/base/base__Set.odocl + ./docs/odoc/base/base__Set_intf.odocl + ./docs/odoc/base/base__Sexp.odocl + ./docs/odoc/base/base__Sexp_with_comparable.odocl + ./docs/odoc/base/base__Sexpable.odocl + ./docs/odoc/base/base__Sign.odocl + ./docs/odoc/base/base__Sign0.odocl + ./docs/odoc/base/base__Sign_or_nan.odocl + ./docs/odoc/base/base__Source_code_position.odocl + ./docs/odoc/base/base__Source_code_position0.odocl + ./docs/odoc/base/base__Stack.odocl + ./docs/odoc/base/base__Stack_intf.odocl + ./docs/odoc/base/base__Staged.odocl + ./docs/odoc/base/base__String.odocl + ./docs/odoc/base/base__String0.odocl + ./docs/odoc/base/base__Stringable.odocl + ./docs/odoc/base/base__Sys.odocl + ./docs/odoc/base/base__Sys0.odocl + ./docs/odoc/base/base__T.odocl + ./docs/odoc/base/base__Type_equal.odocl + ./docs/odoc/base/base__Uchar.odocl + ./docs/odoc/base/base__Uchar0.odocl + ./docs/odoc/base/base__Uniform_array.odocl + ./docs/odoc/base/base__Unit.odocl + ./docs/odoc/base/base__Variant.odocl + ./docs/odoc/base/base__Variantslib.odocl + ./docs/odoc/base/base__With_return.odocl + ./docs/odoc/base/base__Word_size.odocl + ./docs/odoc/base/base_internalhash_types/base_internalhash_types.odocl + ./docs/odoc/base/caml/caml.odocl + ./docs/odoc/base/md5/md5_lib.odocl + ./docs/odoc/base/page-index.odocl + ./docs/odoc/base/shadow_stdlib/shadow_stdlib.odocl + $ cat $(find ./docs/odoc/base/ -name '*.odocl') > megaodocl $ du -sh megaodocl - 4.8M megaodocl - $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $(find . -name '*.odocl') + 6.2M megaodocl + $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $(find ./docs/odoc/base/ -name '*.odocl') > /dev/null $ gzip -k db.js @@ -18,9 +159,9 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2220 db.js - 1676 db.js.gz - 1548 megaodocl.gz + 2284 db.js + 1724 db.js.gz + 1776 megaodocl.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f @@ -31,7 +172,7 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 92K html/sherlodoc.js + 96K html/sherlodoc.js $ ls html base db.js @@ -39,8 +180,10 @@ a previous run. .js files built by dune are read only. highlight.pack.js katex.min.css katex.min.js + ocaml odoc.css odoc_search.js + sexplib0 sherlodoc.js indent to see results $ cp -r html /tmp diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index bcf7e7598c..0f1733bbe5 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 92K sherlodoc.js + 96K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html From fc5374232d759b84c576970b39a7c850869643a7 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 17 Jan 2024 11:23:32 +0100 Subject: [PATCH 249/285] delete review.md --- review.md | 138 ------------------------------------------------------ 1 file changed, 138 deletions(-) delete mode 100644 review.md diff --git a/review.md b/review.md deleted file mode 100644 index fd5a70f7e7..0000000000 --- a/review.md +++ /dev/null @@ -1,138 +0,0 @@ -# review sherlodoc - -# TODO - -- Tester de virer la compression? - > Verifier si la double compression a de l'interet - > tester que gzip -> Not done before vacation. Important ! This one is blocking for a release. - -- Have something more robust than sizes in tests. Remove them, and use - current-bench or just a manual benchmark. - > Not done before vacation. I do not know how to do this, and I believe that - size is critical and size changes should make the tests fail. - A manual benchmark could be used for test/cram/base_benchmark.t were time to - build the db is tested. - -- Have a benchmark of the cli - -- la limitation sur le packages de query n'est plus vraiment fonctionelle -> demander a arthur, pas bloquant pour un release mais a nettoyer a un moment - -- `Index.Load_doc.with_tokenizer`: think of which character form a word -> Not done before vacation. I agree that it could be expanded. - -- Maybe store all "arbitrary constants" relative to the cost function somewhere -> I think it is fine as is for now. - - -# To discuss - -- Type extensions: we might want to search for all extensions of a given extensible type. - -# done - -- Réfléchir à `ancient`: enlever pour de bon, rétablir le support ? -Support is reestablished - -- `sherlodoc_index` `--db` pourrait avoir pour alias `-o` done - -- piper les test avec find dans sort: more robust tests? - -- About search-uri: either remove or precise comment (see "If they are relative, -they are interpreted as relative to the `-o` option") - -- gérer les typedecl_param dans la CLI? - -- Factor or reuse kind to string function in cli to use odoc conversion. Put it in `elt.ml`? - > No because db does not have a dep on odoc, and it arguably does not need one - -- Make it one single type in `succ.mli` (builder vs t) - -- Option prendre un fichier contenant la liste des `odocl` ? - -- `index` supprimer les `.db` - -- `succ.ml` : remove `All` - -- `succ.ml` : soit catcher uniquement StackOverflow, soit catcher tout mais moins profondément !? Dans le jsoo sans doute. - -- `Succ.All` is used in `query.ml` - -- Documenter parser/lexer de query. - -- It would be cool to be able to see the string corresponding to types, and also of the intermediate string list list -> Some examples were added - -- refactor `Query.paths_arrow` vs `index/load_doc.type_distance_paths` - `Query.paths_arrow` is the right implementation, load_doc should tranform the - odoc typeexpr into a sherlodoc query ast typeexpr and then only compute the - path. - Be careful about hash consing. - -- separate pretty_query from the api function - -- Try to support `_ -> int` with dynamic cost ? -> Done, but with polarities. `_` in a query has polarity `"+"` or `"-"`. - Previously the two possibilities were `"+POLY"`/`"-POLY"` or nothing. - - -- Rewrite the type parser in a more flexible framework than menhir (combinator or recursive descent) -> Not needed in the end - -# Explications commentée - -## Index - -- shard est la liste des parties éclatée de la bdd, pour des raisons de mémoire - plus que de performcances. Maintenant il n'y en a toujours plus qu'un mais ça - a été gardé. Functionel, mais index n'est plus capable de générer des shards... -- `With_elts` -> pour la partie type-agnostic de la recherche -- `With_occ` -> pour la partie purely type-dependent de la recherche - -## Indexation - -## Hierarchy structure - -Folders: - -- `db/` is for the db datastructure. Two datastructures: one for the type - agnostic part (`db_names`, or `with_elts`) and one for the type-centric part - of the query (`db_types`, or `with_occs`) -- `index/` is for the action of indexing. Includes a binary. -- `jsoo` the js access to perform query. Compile to a js file to run on a webworker. Read the (marhsalled, - compressed) db from a global variable: `sherlodoc_db`. -- `cli/` the `cli` access to perform queries. Load the db from a file. -- `store/` is the access to the database. The two directories above (`jsoo` and - `cli`) use the `storage_js` and `storage_marshal` modules for their purpose. -- `www/` for the webserver running on . -- `static/` static files also for the webserver -- `test/` self-explained -- `query/` defines queries and perform them - -# Notes personnelles/explications/... - -## Index - - - -### Indexation - -Pour les textes, c'est facile : -- On crée le payload à partir de la search entry -- On ajoute ça au writer - -Pour les types, ça marche pareil mais on doit transformer le type en une string. -Cela est fait par les fonctions suivantes: -- `Load_doc.type_paths` qui prend - - en entrée le type vu par odoc, un prefix (?) et un signe - - en sortie, une string list list. Un élément de la liste est une "feuille", l'ordre n'ayant pas d'importance. -- `Db.store_type_path` qui transforme la `string list list` en "concaténant les - path regroupés !" (qui compte les occurrences de chaque type) - - - - - - - From df8b04d74ec18977850b85d12688dcce4928fb97 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 17 Jan 2024 11:34:26 +0100 Subject: [PATCH 250/285] update readme --- README.md | 28 +++++++++++++--------------- cli/main.ml | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 31b39a3c40..d01fd458b2 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,10 @@ opam install sherlodoc ## Generating a search-database The first step to using sherlodoc is generating a search-database. You do this -with the command `sherlodoc_index` : +with the command `sherlodoc index` : ```bash -sherlodoc_index --format=marshal -o db.bin a.odocl b.odocl +sherlodoc index --format=marshal -o db.marshal a.odocl b.odocl ``` The `--format` option determines in which format the database is outputted. The @@ -43,15 +43,15 @@ uses. There is a third format : `ancient`, that is only available if the package `ancient` is installed. It is more complicated than the other two, you can read on it [here](https://github.com/UnixJunkie/ocaml-ancient). It is used for the -[online](https://doc.sherlocode.com) version of sherlodoc, and is a mandatory -dependency of the `sherlodoc-www` package. +[online](https://doc.sherlocode.com) version of sherlodoc, and is an optional +dependency of the `sherlodoc` package. The `-o` option is the filename of the output. Then you need to provide a list of .odocl files that contains the signatures items that are going to be searchable. They are build artifacts of odoc. -There are others options that are documented by `sherlodoc_index --help`. +There are others options that are documented by `sherlodoc index --help`. ## Queries @@ -101,7 +101,7 @@ If you have a search database in `marshal` format, you can search on the command line : ```bash -sherlodoc --db=db.bin "blabla : int -> string" +sherlodoc --db=db.marshal "blabla : int -> string" ``` `--db` is the filename of the search database. If absent, the environment @@ -128,13 +128,13 @@ odig odoc Generate the search database : ```bash -sherlodoc_index --format=marshal -o db.bin $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc -name "*.odocl") +sherlodoc index --format=marshal -o db.marshal $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc -name "*.odocl") ``` Enjoy searching : ```bash -sherlodoc --db-db.bin +sherlodoc search --db=db.marshal ``` ## Searching from an odoc search bar @@ -151,7 +151,7 @@ Be sure to copy the two js files in the output directory given to the html-generate command : ```bash -cp $OPAM_SWITCH_PREFIX/share/sherlodoc/sherlodoc.js html_output/sherlodoc.js ; +sherlodoc js html_output/sherlodoc.js ; cp db.js html_output/db.js ; ``` @@ -162,20 +162,18 @@ If you want to, you can test it, it should work. It is still work in progress. ## Sherlodoc online If you want to use sherlodoc as a server, like on -[doc.sherlocode.com](https://doc.sherlocode.com), you can. This is packaged -separately in `sherlodoc-www`, but also lives in this repo. +[doc.sherlocode.com](https://doc.sherlocode.com) it is also possible. -Once you have installed `sherlodoc-www`, you need to generate your search -database : +As usual, generate your search database : ```bash -sherlodoc_index --format=ancient --db=db.bin $(find /path/to/doc -name "*.odocl") +sherlodoc index --format=ancient -o db.ancient $(find /path/to/doc -name "*.odocl") ``` Then you can run the website : ```bash -sherlodoc-www db.bin +sherlodoc serve db.ancient ``` The real magic for [doc.sherlocode.com](https://doc.sherlocode.com) is all the diff --git a/cli/main.ml b/cli/main.ml index 5951155909..e8856faca9 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -30,7 +30,7 @@ let db_filename = let doc = "The database to query" in Cmd.Env.info "SHERLODOC_DB" ~doc in - Arg.(required & opt (some string) None & info [ "db" ] ~docv:"DB" ~env) + Arg.(required & opt (some string) None & info [ "db"; "o" ] ~docv:"DB" ~env) let db_path = let env = From bb6d459320594e588b6ee1a2089159dccfc48b79 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Thu, 18 Jan 2024 16:01:01 +0100 Subject: [PATCH 251/285] updates polarity mli comment --- db/type_polarity.mli | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/db/type_polarity.mli b/db/type_polarity.mli index 49d4b742f0..f199d8b510 100644 --- a/db/type_polarity.mli +++ b/db/type_polarity.mli @@ -77,10 +77,4 @@ val of_typ : any_is_poly:bool -> Typexpr.t -> t Seq.t - If [any_is_poly] is true, the type [_] will be treated like a type variable ['a], otherwise it will be represented solely by its sign ("+" or "-"). - - - If [all_names] is true, extra polarities are added for every "possible name" - of each type constructor. For instance the possible names of - [Stdlib.Int64.t] are ["t"], ["Int64.t"] and ["Stdlib.Int64.t"]. This allows - the user to use any of the possible name. It is important to set this - when registering entries in the database, but you not need it when computing - the polarities of a query. *) + *) From 106f8e76e41ae7093b198feeb278e347c53a58c4 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 16 Jan 2024 20:34:56 +0100 Subject: [PATCH 252/285] performances and bugs fix thanks to voodoo testing --- README.md | 191 +++-------- cli/dune | 1 + cli/search.ml | 47 ++- db/entry.ml | 159 ++++----- db/entry.mli | 13 - db/string_automata.ml | 95 +++--- db/string_automata.mli | 10 +- db/type_polarity.ml | 6 +- db/type_polarity.mli | 5 +- dune-project | 19 +- dune-workspace | 3 + index/db_writer.ml | 47 ++- index/db_writer.mli | 3 +- index/index.ml | 28 +- index/load_doc.ml | 29 +- index/suffix_tree.ml | 134 ++++++-- index/suffix_tree.mli | 2 +- jsoo/dune | 8 - jsoo/main.ml | 18 +- query/dune | 2 +- query/dynamic_cost.ml | 6 +- query/io.ml | 40 +++ query/name_cost.ml | 4 +- query/priority_queue.ml | 83 +++-- query/priority_queue.mli | 4 +- query/query.ml | 52 +-- query/query.mli | 48 +-- query/query_parser.ml | 9 +- query/succ.ml | 178 +++++----- query/succ.mli | 1 + query/top_results.ml | 36 ++- query/top_results.mli | 10 +- query/type_distance.ml | 222 ++++++------- query/type_distance.mli | 8 +- sherlodoc.opam | 17 +- store/db_store.default.ml | 4 +- test/cram/base_cli.t | 502 ++++++++++++++--------------- test/cram/base_web.t | 8 +- test/cram/cli.t/run.t | 38 +-- test/cram/cli_small.t/run.t | 10 +- test/cram/module_type_cost.t/run.t | 10 +- test/cram/simple.t/run.t | 2 +- www/dune | 3 +- www/static/style.css | 42 ++- www/ui.ml | 26 +- www/www.ml | 15 +- 46 files changed, 1200 insertions(+), 998 deletions(-) create mode 100644 dune-workspace create mode 100644 query/io.ml diff --git a/README.md b/README.md index d01fd458b2..240aaca154 100644 --- a/README.md +++ b/README.md @@ -1,182 +1,91 @@ **Try it online at [doc.sherlocode.com](https://doc.sherlocode.com) !** -A Hoogle-like search engine for OCaml documentation. It can be used in -differents ways, [online](https://doc.sherlocode.com), or offline with -the dev version of odoc. +Sherlodoc is a search engine for OCaml documentation (inspired by [Hoogle](https://hoogle.haskell.org/)), which allows you to search through OCaml libraries by names and approximate type signatures: -It has fuzzy type search supported by a polarity search. As an example, the type -`string -> int -> char` gets simplified to `{ -string, -int, +char }` which -means that it consumes a `string` and an `int` and produces a `char` -(irrespective of the order of the arguments). This polarity search is fast -enough and yields good candidates which are then sorted by similarity with the -query. The sort is slower but the number of candidates is small. +- Search by name: [`list map`](https://doc.sherlocode.com/?q=list%20map) +- Search inside documentation comments: [`raise Not_found`](https://doc.sherlocode.com/?q=raise%20Not_found) +- Fuzzy type search is introduced with a colon, e.g. [`: map -> list`](https://doc.sherlocode.com/?q=%3A%20map%20-%3E%20list) +- Search by name and type with a colon separator [`Bogue : Button.t`](https://doc.sherlocode.com/?q=Bogue%20%3A%20Button.t) +- An underscore `_` can be used as a wildcard in type queries: [`(int -> _) -> list -> _`](https://doc.sherlocode.com/?q=(int%20-%3E%20_)%20-%3E%20list%20-%3E%20_) +- Type search supports products and reordering of function arguments: [`array -> ('a * int -> bool) -> array`](https://doc.sherlocode.com/?q=%3A%20array%20-%3E%20(%27a%20*%20int%20-%3E%20bool)%20-%3E%20array) -You can search for anything that can exists in an MLI files : values, types, -modules, exceptions, constructors etc... +## Local usage -Fuzzy type search is available for values, sum-types constructors, exceptions, -and record fields. - -# Usage - -First, install sherlodoc : +First, install sherlodoc and odig: ```bash -opam pin add https://github.com/art-w/sherlodoc.git#jsoo -opam install sherlodoc -``` +$ opam pin add 'https://github.com/art-w/sherlodoc.git' # optional -## Generating a search-database - -The first step to using sherlodoc is generating a search-database. You do this -with the command `sherlodoc index` : - -```bash -sherlodoc index --format=marshal -o db.marshal a.odocl b.odocl +$ opam install sherlodoc odig ``` -The `--format` option determines in which format the database is outputted. The -available format are `marshal`, `js`. The `js` format, for -javascript, is the one compatible with odoc, and the `marshal` for most other -uses. - -There is a third format : `ancient`, that is only available if the package - `ancient` is installed. It is more complicated than the other two, you can read -on it [here](https://github.com/UnixJunkie/ocaml-ancient). It is used for the -[online](https://doc.sherlocode.com) version of sherlodoc, and is an optional -dependency of the `sherlodoc` package. - -The `-o` option is the filename of the output. - -Then you need to provide a list of .odocl files that contains the signatures -items that are going to be searchable. They are build artifacts of odoc. - -There are others options that are documented by `sherlodoc index --help`. - -## Queries +[Odig](https://erratique.ch/software/odig) can generate the odoc documentation of your current switch with: -To query sherlodoc, be it on the command-line or in a web interface, you need -to input a string query. A query is a list of words, separated by spaces. -Results will be entries that have every word of the list present in them. - -``` -"list map" -``` - -The above query will return entries that have both `list` and `map` in them. - -You can also add `: ` at the end of your query, and in that case, results -will only be results whose type match . This can only be a value, an -exception, a constructor or a record field. - -Matching a type is fuzzy, if you do the following query : - -``` -"blabla : string" +```bash +$ odig odoc # followed by `odig doc` to browse your switch documentation ``` -It could return `val blablabla : int -> string` and `val blabla2 : string`. +Which sherlodoc can then index to create a search database: -You can have just the type-part of the query : `": string -> int"` is a valid -query. +```bash +# name your sherlodoc database +$ export SHERLODOC_DB=/tmp/sherlodoc.marshal -You can use wildcards : +# if you are using OCaml 4, we recommend the `ancient` database format: +$ opam install ancient +$ export SHERLODOC_DB=/tmp/sherlodoc.ancient +# index all odoc files generated by odig for your current switch: +$ sherlodoc index $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc -name '*.odocl') ``` -": string -> _" -``` - -will only return functions that take a string a argument, no matter what they -return. - -There is limited support for polymorphism : you cannot search for `'a -> 'a` and -get every function `int -> int`, `string -> string` etc. However it will return -a function whose literal type is `'a -> 'a`. Having the first behaviour would -be a lot harder to program, and probably not a good idea, as it would be -impossible to search for polymorphic functions. -## Searching on the command line - -If you have a search database in `marshal` format, you can search on the command -line : +Enjoy searching from the command-line or run the webserver: ```bash -sherlodoc --db=db.marshal "blabla : int -> string" -``` - -`--db` is the filename of the search database. If absent, the environment -variable `SHERLODOC_DB` will be used instead. +$ sherlodoc search "map : list" +$ sherlodoc search # interactice cli -In my example, I gave a query, but if you give none, sherlodoc enter an -interactive mode where you can enter queries until you decide to quit. +$ opam install dream +$ sherlodoc serve # webserver at http://localhost:1234 +``` -There are more option documented by `sherlodoc --help`, some of them are for -debugging/testing purposes, others might be useful. +The different commands support a `--help` argument for more details/options. -### Search your switch +In particular, sherlodoc supports three different file formats for its database, which can be specified either in the filename extension or through the `--db-format=` flag: +- `ancient` for fast database loading using mmap, but is only compatible with OCaml 4. +- `marshal` for when ancient is unavailable, with slower database opening. +- `js` for integration with odoc static html documentation for client-side search without a server. -A reasonable use of sherlodoc on the cli is to search for signatures items from -your whole switch. Since odig can generate the documentation of the switch, we -can get the .odocl files with it : +## Integration with Odoc -Generate the documentation of your switch : +Odoc 2.4.0 adds a search bar inside the statically generated html documentation. [Integration with dune is in progress](https://github.com/ocaml/dune/pull/9772), you can try it inside a fresh opam switch with: (warning! this will recompile any installed package that depends on dune!) ```bash -odig odoc -``` - -Generate the search database : +$ opam pin https://github.com/emileTrotignon/dune.git#search-odoc-new -```bash -sherlodoc index --format=marshal -o db.marshal $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc -name "*.odocl") +$ dune build @doc # in your favorite project ``` -Enjoy searching : +Otherwise, manual integration with odoc requires to add to every call of `odoc html-generate` the flags `--search-uri sherlodoc.js --search-uri db.js` to activate the search bar. You'll also need to generate a search database `db.js` and provide the `sherlodoc.js` dependency (a version of the sherlodoc search engine with odoc support, compiled to javascript): ```bash -sherlodoc search --db=db.marshal -``` +$ sherlodoc index --db=_build/default/_doc/_html/YOUR_LIB/db.js \ + $(find _build/default/_doc/_odocls/YOUR_LIB -name '*.odocl') -## Searching from an odoc search bar - -The latest unreleased version of odoc is compatible with sherlodoc. This allows -you to upload the documentation of a package with a search for this package -embedded. - -For this to work, you need to generate a search database with format `js`, and -then add to every call of `odoc html-generate` the flags `--search-uri -sherlodoc.js --search-uri db.js`. - -Be sure to copy the two js files in the output directory given to the -html-generate command : - -```bash -sherlodoc js html_output/sherlodoc.js ; -cp db.js html_output/db.js ; +$ sherlodoc js > _build/default/_doc/_html/sherlodoc.js ``` -Obviously, most people use dune, and do not call `odoc html-generate`. A patch -for dune is being [worked on](https://github.com/emileTrotignon/dune/tree/search-odoc-new). -If you want to, you can test it, it should work. It is still work in progress. +## How it works -## Sherlodoc online +The sherlodoc database uses [Suffix Trees](https://en.wikipedia.org/wiki/Suffix_tree) to search for substrings in value names, documentation and types. During indexation, the suffix trees are compressed to state machine automatas. The children of every node are also sorted, such that a sub-tree can be used as a priority queue during search enumeration. -If you want to use sherlodoc as a server, like on -[doc.sherlocode.com](https://doc.sherlocode.com) it is also possible. +To rank the search results, sherlodoc computes a static evaluation of each candidate during indexation. This static scoring biases the search to favor short names, short types, the presence of documentation, etc. When searching, a dynamic evaluation dependent on the user query is used to adjust the static ordering of the results: -As usual, generate your search database : +- How similar is the result name to the search query? (to e.g. prefer results which respect the case: [`map`](https://doc.sherlocode.com/?q=map) vs [`Map`](https://doc.sherlocode.com/?q=Map)) +- How similar are the types? (using a tree diff algorithm, as for example [`('a -> 'b -> 'a) -> 'a -> 'b list -> 'a`](https://doc.sherlocode.com/?q=(%27a%20-%3E%20%27b%20-%3E%20%27a)%20-%3E%20%27a%20-%3E%20%27b%20list%20-%3E%20%27a) and [`('a -> 'b -> 'b) -> 'a list -> 'b -> 'b`](https://doc.sherlocode.com/?q=(%27a%20-%3E%20%27b%20-%3E%20%27b)%20-%3E%20%27a%20list%20-%3E%20%27b%20-%3E%20%27b) are isomorphic yet point to `fold_left` and `fold_right` respectively) -```bash -sherlodoc index --format=ancient -o db.ancient $(find /path/to/doc -name "*.odocl") -``` - -Then you can run the website : +For fuzzy type search, sherlodoc aims to provide good results without requiring a precise search query, on the basis that the user doesn't know the exact type of the things they are looking for (e.g. [`string -> file_descr`](https://doc.sherlocode.com/?q=string%20-%3E%20file_descr) is incomplete but should still point in the right direction). In particular when exploring a package documentation, the common question "how do I produce a value of type `foo`" can be answered with the query `: foo` (and "which functions consume a value of type `bar`" with `: bar -> _`). This should also work when the type can only be produced indirectly through a callback (for example [`: Eio.Switch.t`](https://doc.sherlocode.com/?q=%3A%20Eio.Switch.t) has no direct constructor). To achieve this, sherlodoc performs a type decomposition based on the polarity of each term: A value produced by a function is said to be positive, while an argument consumed by a function is negative. This simplifies away the tree shape of types, allowing their indexation in the suffix trees. The cardinality of each value type is also indexed, to e.g. differentiate between [`list -> list`](https://doc.sherlocode.com/?q=list%20-%3E%20list) and [`list -> list -> list`](https://doc.sherlocode.com/?q=list%20-%3E%20list%20-%3E%20list). -```bash -sherlodoc serve db.ancient -``` +While the polarity search results are satisfying, sherlodoc offers very limited support for polymorphic variables, type aliases and true type isomorphisms. You should check out the extraordinary [Dowsing](https://github.com/Drup/dowsing) project for this! -The real magic for [doc.sherlocode.com](https://doc.sherlocode.com) is all the -.odocl artifacts of the package documentation generated for -[`ocaml.org/packages`](https://ocaml.org/packages), which I got my hands on -thanks to insider trading (but don't have the bandwidth to share back... sorry!) +And if you speak French, a more detailed [presentation of Sherlodoc](https://www.irill.org/videos/OUPS/2023-03/wendling.html) (and [Sherlocode](https://sherlocode.com)) was given at the [OCaml Users in PariS (OUPS)](https://oups.frama.io/) in March 2023. diff --git a/cli/dune b/cli/dune index 778a083898..2b1d3ffa9a 100644 --- a/cli/dune +++ b/cli/dune @@ -9,6 +9,7 @@ index query db_store + unix (select serve.ml from diff --git a/cli/search.ml b/cli/search.ml index 956298570e..46a5263277 100644 --- a/cli/search.ml +++ b/cli/search.ml @@ -36,31 +36,46 @@ let print_result ~print_cost ~no_rhs (elt : Db.Entry.t) = in Format.printf "%s%s %s%s%a@." cost kind typedecl_params name pp_rhs elt.rhs -let search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query = +let search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query ~time query = let query = Query.{ query; packages = []; limit } in if pretty_query then print_endline (Query.pretty query) ; - match Query.search ~shards:db ~dynamic_sort:(not static_sort) query with + let t0 = Unix.gettimeofday () in + let r = Query.Blocking.search ~shards:db ~dynamic_sort:(not static_sort) query in + let t1 = Unix.gettimeofday () in + match r with | [] -> print_endline "[No results]" | _ :: _ as results -> List.iter (print_result ~print_cost ~no_rhs) results ; - flush stdout + flush stdout ; + if time then Format.printf "Search in %f@." (t1 -. t0) -let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db = +let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~time ~db = Printf.printf "%ssearch>%s %!" "\027[0;36m" "\027[0;0m" ; match Stdlib.input_line stdin with | query -> - search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query query ; - search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db + search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query ~time query ; + search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~time ~db | exception End_of_file -> Printf.printf "\n%!" -let search query print_cost no_rhs static_sort limit pretty_query db_format db_filename = +let search + query + print_cost + no_rhs + static_sort + limit + pretty_query + time + db_format + db_filename + = let module Storage = (val Db_store.storage_module db_format) in let db = Storage.load db_filename in match query with | None -> print_endline header ; - search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db - | Some query -> search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~db query + search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~time ~db + | Some query -> + search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~time ~db query open Cmdliner @@ -76,6 +91,10 @@ let print_cost = let doc = "For debugging purposes: prints the cost of each result" in Arg.(value & flag & info [ "print-cost" ] ~doc) +let print_time = + let doc = "For debugging purposes: prints the search time" in + Arg.(value & flag & info [ "print-time" ] ~doc) + let static_sort = let doc = "Sort the results without looking at the query.\n\ @@ -93,4 +112,12 @@ let pretty_query = Arg.(value & flag & info [ "pretty-query" ] ~doc) let term = - Term.(const search $ query $ print_cost $ no_rhs $ static_sort $ limit $ pretty_query) + Term.( + const search + $ query + $ print_cost + $ no_rhs + $ static_sort + $ limit + $ pretty_query + $ print_time) diff --git a/db/entry.ml b/db/entry.ml index 33d44ac5ee..17c9c1c901 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -1,5 +1,8 @@ let empty_string = String.make 0 '_' -let non_empty_string s = if s = "" then empty_string else s + +let non_empty_string s = + (* to protect against `ancient` segfaulting on statically allocated values *) + if s = "" then empty_string else s module Kind = struct type t = @@ -38,91 +41,101 @@ module Package = struct { name = non_empty_string name; version = non_empty_string version } let compare a b = String.compare a.name b.name - let link { name; version } = Printf.sprintf "https://ocaml.org/p/%s/%s" name version + let link { name; version } = "https://ocaml.org/p/" ^ name ^ "/" ^ version end -module T = struct - type t = - { name : string - ; rhs : string option - ; url : string - ; kind : Kind.t - ; cost : int - ; doc_html : string - ; pkg : Package.t - } +type t = + { name : string + ; rhs : string option + ; url : string + ; kind : Kind.t + ; cost : int + ; doc_html : string + ; pkg : Package.t + } - let string_compare_shorter a b = - match Int.compare (String.length a) (String.length b) with - | 0 -> String.compare a b - | c -> c +let string_compare_shorter a b = + match Int.compare (String.length a) (String.length b) with + | 0 -> String.compare a b + | c -> c - let structural_compare a b = - match string_compare_shorter a.name b.name with +let structural_compare a b = + match string_compare_shorter a.name b.name with + | 0 -> begin + match Package.compare a.pkg b.pkg with | 0 -> begin - match Package.compare a.pkg b.pkg with + match Stdlib.compare a.kind b.kind with | 0 -> begin - match Stdlib.compare a.kind b.kind with - | 0 -> begin - match string_compare_shorter a.doc_html b.doc_html with - | 0 -> String.compare a.url b.url - | c -> c - end + match string_compare_shorter a.doc_html b.doc_html with + | 0 -> String.compare a.url b.url | c -> c end | c -> c end | c -> c - - let compare a b = - if a == b - then 0 - else begin - match Int.compare a.cost b.cost with - | 0 -> structural_compare a b - | cmp -> cmp - end - - let equal a b = compare a b = 0 -end - -include T -module Set = Set.Make (T) - -(** Array of elts. For use in functors that require a type [t] and not ['a t].*) -module Array = struct - type elt = t - type t = elt array option - - let is_empty = function - | None -> true - | Some arr -> - assert (Array.length arr > 0) ; - false - - let empty = None - - let minimum = function - | None -> None - | Some arr -> Some arr.(0) - - let of_list arr = - let arr = Array.of_list arr in - Array.sort compare arr ; - if Array.length arr = 0 then empty else Some arr - - let equal_elt = T.equal - let compare_elt = T.compare -end + end + | c -> c + +let compare a b = + if a == b + then 0 + else begin + match Int.compare a.cost b.cost with + | 0 -> structural_compare a b + | cmp -> cmp + end + +let equal a b = compare a b = 0 + +let stdlib_link ~name t = + let path, hashref = + match List.rev name, String.index_opt t.url '#' with + | _ :: path, Some idx -> + let idx = idx + 1 in + let tgt = + match String.index_from_opt t.url idx '-' with + | None -> String.sub t.url idx (String.length t.url - idx) + | Some jdx -> + let kind = String.sub t.url idx (jdx - idx) in + let jdx = jdx + 1 in + let target = String.sub t.url jdx (String.length t.url - jdx) in + String.uppercase_ascii kind ^ target + in + path, "#" ^ tgt + | path, _ -> path, "" + in + let path = String.concat "." (List.rev path) in + "https://v2.ocaml.org/releases/5.1/api/" ^ path ^ ".html" ^ hashref let link t = - let pkg_link = Package.link t.pkg in - let name, path = - match List.rev (String.split_on_char '.' t.name) with - | name :: path -> name, String.concat "/" (List.rev path) - | _ -> "", "" - in - pkg_link ^ "/doc/" ^ path ^ "/index.html#val-" ^ name + let fullname = String.split_on_char '.' t.name in + match fullname with + | "Stdlib" :: name -> stdlib_link ~name t + | _ -> + let pkg_link = Package.link t.pkg in + let rec align n ys = + match ys with + | _ when n = 0 -> [] + | [] -> [] + | y :: ys -> y :: align (n - 1) ys + in + let length = List.length fullname in + let length = + match String.index_opt t.url '#' with + | None -> length + 1 + | Some idx -> + let tgt = String.sub t.url idx (String.length t.url - idx) in + let count = ref 0 in + String.iter + (function + | '.' -> incr count + | _ -> ()) + tgt ; + length - !count + in + let path = align length (List.rev (String.split_on_char '/' t.url)) in + let path = String.concat "/" (List.rev path) in + pkg_link ^ "/doc/" ^ path let v ~name ~kind ~cost ~rhs ~doc_html ~url ~pkg () = { name = non_empty_string name diff --git a/db/entry.mli b/db/entry.mli index 53856413b8..4cc1904ea2 100644 --- a/db/entry.mli +++ b/db/entry.mli @@ -52,16 +52,3 @@ val v val link : t -> string val compare : t -> t -> int val equal : t -> t -> bool - -module Set : Set.S with type elt = t - -module Array : sig - type elt = t - type t = elt array option - - val of_list : elt list -> t - val is_empty : t -> bool - val minimum : t -> elt option - val equal_elt : elt -> elt -> bool - val compare_elt : elt -> elt -> int -end diff --git a/db/string_automata.ml b/db/string_automata.ml index a0047a20a0..5866aed57b 100644 --- a/db/string_automata.ml +++ b/db/string_automata.ml @@ -1,7 +1,13 @@ +type terminals = + | Empty + | Terminals of Entry.t array + | Summary of Entry.t array + type node = { start : int ; len : int - ; terminals : Entry.Array.t + ; size : int + ; terminals : terminals ; children : node array option } @@ -10,7 +16,12 @@ type t = ; t : node } -let empty = { str = ""; t = { start = 0; len = 0; terminals = None; children = None } } +let size t = t.t.size + +let minimum { t; _ } = + match t.terminals with + | Empty -> assert false + | Terminals arr | Summary arr -> arr.(0) let array_find ~str chr arr = let rec go i = @@ -32,9 +43,10 @@ let lcp i_str i j_str j j_len = let rec go_lcp i j = if i >= String.length i_str || j >= j_stop then i - else ( + else begin let i_chr, j_chr = i_str.[i], j_str.[j] in - if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1)) + if i_chr <> j_chr then i else go_lcp (i + 1) (j + 1) + end in let i' = go_lcp i j in i' - i @@ -69,77 +81,54 @@ let stepback node = assert (node.len >= 0) ; { node with start = node.start - 1; len = node.len + 1 } -let rec find_skip ~spaces t pattern = +let rec find_skip ~spaces t pattern yield = let skip () = let node = t.t in if node.len >= 1 then begin let spaces = spaces + if t.str.[node.start] = ' ' then 1 else 0 in - if spaces > 1 then [] else find_skip ~spaces { t with t = advance t.t } pattern + if spaces > 1 + then () + else find_skip ~spaces { t with t = advance t.t } pattern yield end else begin match node.children with - | None -> [] + | None -> () | Some children -> - snd - @@ List.fold_left - (fun (i, acc) child -> - let xs = find_skip ~spaces { t with t = stepback child } pattern in - i + 1, List.rev_append xs acc) - (0, []) - @@ Array.to_list children + Array.iter + (fun child -> find_skip ~spaces { t with t = stepback child } pattern yield) + children end in if spaces = 0 then skip () + else if spaces = 1 && pattern = Type_polarity.poly + then begin + match find t pattern with + | None -> () + | Some here -> yield here + end else begin - let skip = skip () in + skip () ; match find t pattern with - | Some here -> here :: skip - | None -> skip + | None -> () + | Some here -> yield here end -let find_star t pattern = +let find_star t pattern yield = let rec go t = function - | [] -> [ t ] - | p :: ps -> begin - let ts = find_skip ~spaces:0 t p in - List.fold_left - (fun acc t -> - let xs = go t ps in - List.rev_append xs acc) - [] - ts - end + | [] -> yield t + | p :: ps -> find_skip ~spaces:0 t p @@ fun t -> go t ps in match String.split_on_char ' ' pattern with - | [] -> [] + | [] -> () | p :: ps -> begin match find t p with - | None -> [] + | None -> () | Some t -> go t ps end -let min_opt a b = - match a, b with - | Some x, Some y -> Some (if Entry.compare x y <= 0 then x else y) - | Some x, None | None, Some x -> Some x - | None, None -> None - -let rec minimum t = - let min_terminal = - match t.terminals with - | None -> None - | Some arr -> Some arr.(0) - in - let min_child = - match t.children with - | None -> None - | Some children -> minimum children.(0) - in - min_opt min_terminal min_child - -let minimum { t; _ } = - match minimum t with - | None -> assert false - | Some elt -> elt +let find_star t pattern = + let found = ref [] in + find_star t pattern (fun t -> found := t :: !found) ; + !found diff --git a/db/string_automata.mli b/db/string_automata.mli index 4b4ad60a88..7e3bce7831 100644 --- a/db/string_automata.mli +++ b/db/string_automata.mli @@ -1,10 +1,16 @@ (* A string automata, constructed from a suffix tree and optimized for fast queries and small serialization. *) +type terminals = + | Empty + | Terminals of Entry.t array + | Summary of Entry.t array + type node = { start : int ; len : int - ; terminals : Entry.Array.t + ; size : int + ; terminals : terminals ; children : node array option } @@ -13,7 +19,7 @@ type t = ; t : node } -val empty : t val find : t -> string -> t option val find_star : t -> string -> t list val minimum : t -> Entry.t +val size : t -> int diff --git a/db/type_polarity.ml b/db/type_polarity.ml index 61067bcf01..47bcec1cbd 100644 --- a/db/type_polarity.ml +++ b/db/type_polarity.ml @@ -18,9 +18,11 @@ let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] ls type t = string * int * Sign.t +let poly = "@" + let rec of_typ ~any_is_poly ~prefix ~sgn = function - | Poly _ -> [ sgn, "POLY" :: prefix ] - | Any -> if any_is_poly then [ sgn, "POLY" :: prefix ] else [ sgn, prefix ] + | Poly _ -> [ sgn, poly :: prefix ] + | Any -> if any_is_poly then [ sgn, poly :: prefix ] else [ sgn, prefix ] | Arrow (a, b) -> List.rev_append (of_typ ~any_is_poly ~prefix ~sgn:(Sign.not sgn) a) diff --git a/db/type_polarity.mli b/db/type_polarity.mli index f199d8b510..0bbcac3108 100644 --- a/db/type_polarity.mli +++ b/db/type_polarity.mli @@ -76,5 +76,6 @@ val of_typ : any_is_poly:bool -> Typexpr.t -> t Seq.t corresponding to [typ]. - If [any_is_poly] is true, the type [_] will be treated like a type variable - ['a], otherwise it will be represented solely by its sign ("+" or "-"). - *) + ['a], otherwise it will be represented solely by its sign ("+" or "-"). *) + +val poly : string diff --git a/dune-project b/dune-project index ddae2e1186..fd2418afd4 100644 --- a/dune-project +++ b/dune-project @@ -10,7 +10,7 @@ (source (github art-w/sherlodoc)) -(authors "Arthur Wendling") +(authors "Arthur Wendling" "Emile Trotignon") (maintainers "art.wendling@gmail.com") @@ -18,23 +18,24 @@ (package (name sherlodoc) - (synopsis "Fuzzy search in OCaml documentation") + (synopsis "Search engine for OCaml documentation") (depends (ocaml (>= 4.0.8)) - (cmdliner (>= 1.2.0)) + (odoc (>= 2.4.0)) + (base64 (>= 3.5.1)) (bigstringaf (>= 0.9.1)) + (js_of_ocaml (>= 5.6.0)) + (brr (>= 0.0.6)) + (cmdliner (>= 1.2.0)) (decompress (>= 1.5.3)) - (base64 (>= 3.5.1)) (fpath (>= 0.7.3)) (lwt (>= 5.7.0)) (menhir (>= 20230608)) - (odoc (>= 2.4.0)) - (tyxml (>= 4.6.0)) - (brr (>= 0.0.6)) (ppx_blob (>= 0.7.2)) - (alcotest :with-test) + (tyxml (>= 4.6.0)) (odig :with-test) - (base (and :with-test (= v0.16.3)))) + (base (and :with-test (= v0.16.3))) + (alcotest :with-test)) (depopts (dream (>= 1.0.0~alpha5)) (ancient (>= 0.9.1)))) diff --git a/dune-workspace b/dune-workspace new file mode 100644 index 0000000000..7d2408dada --- /dev/null +++ b/dune-workspace @@ -0,0 +1,3 @@ +(lang dune 3.5) + +(profile release) diff --git a/index/db_writer.ml b/index/db_writer.ml index e69c9dcb4f..e847421e35 100644 --- a/index/db_writer.ml +++ b/index/db_writer.ml @@ -1,30 +1,48 @@ open Db -type t = - { writer_names : Suffix_tree.t +type s = + { mutable load : int + ; writer_names : Suffix_tree.t ; buffer_types : Suffix_tree.Buf.t ; mutable writer_pos_types : Suffix_tree.t Occurences.t ; mutable writer_neg_types : Suffix_tree.t Occurences.t ; type_cache : Type_cache.t } -let make () = +type t = s ref + +let load t = !t.load + +let make_empty () = let buffer_names = Suffix_tree.Buf.make () in let buffer_types = Suffix_tree.Buf.make () in - { writer_names = Suffix_tree.make buffer_names + { load = 0 + ; writer_names = Suffix_tree.make buffer_names ; buffer_types ; writer_pos_types = Occurences.empty ; writer_neg_types = Occurences.empty ; type_cache = Type_cache.make () } -let export db = - { Storage.db_names = Suffix_tree.export db.writer_names - ; db_pos_types = Occurences.map Suffix_tree.export db.writer_pos_types - ; db_neg_types = Occurences.map Suffix_tree.export db.writer_neg_types - } +let make () = ref (make_empty ()) + +let export ~summarize db = + let shard = + let db = !db in + let db_names = Suffix_tree.export ~summarize db.writer_names in + let db_pos_types = + Occurences.map (Suffix_tree.export ~summarize) db.writer_pos_types + in + let db_neg_types = + Occurences.map (Suffix_tree.export ~summarize) db.writer_neg_types + in + { Storage.db_names; db_pos_types; db_neg_types } + in + db := make_empty () ; + shard let store db name elt ~count ~polarity = + db.load <- db.load + 1 ; let st = match polarity with | Type_polarity.Sign.Pos -> begin @@ -45,7 +63,14 @@ let store db name elt ~count ~polarity = Suffix_tree.add_suffixes st name elt let store_type_polarities db elt polarities = + let db = !db in Seq.iter (fun (path, count, polarity) -> store db ~count ~polarity path elt) polarities -let store_word db word elt = Suffix_tree.add_suffixes db.writer_names word elt -let type_of_odoc ~db ty = Type_cache.of_odoc ~cache:db.type_cache ty +let store_word db word elt = + let db = !db in + db.load <- db.load + 1 ; + Suffix_tree.add_suffixes db.writer_names word elt + +let type_of_odoc ~db ty = + let db = !db in + Type_cache.of_odoc ~cache:db.type_cache ty diff --git a/index/db_writer.mli b/index/db_writer.mli index f3a221ac1e..746626a5aa 100644 --- a/index/db_writer.mli +++ b/index/db_writer.mli @@ -2,11 +2,12 @@ type t (** The type that builds a database. You can use it to add things to it, but you cannot make queries on it. *) -val export : t -> Db.t +val export : summarize:bool -> t -> Db.t val make : unit -> t (** [make ()] returns an empty search database. *) +val load : t -> int val type_of_odoc : db:t -> Odoc_model.Lang.TypeExpr.t -> Db.Typexpr.t val store_type_polarities : t -> Db.Entry.t -> Db.Type_polarity.t Seq.t -> unit val store_word : t -> string -> Db.Entry.t -> unit diff --git a/index/index.ml b/index/index.ml index ecb3cfd72f..0da9a9c9a5 100644 --- a/index/index.ml +++ b/index/index.ml @@ -18,13 +18,12 @@ let index_file register filename = let main files file_list index_docstring index_name type_search db_format db_filename = let module Storage = (val Db_store.storage_module db_format) in let db = Db_writer.make () in - let pkg = Db.Entry.Package.v ~name:"" ~version:"" in - let register id () item = + let no_pkg = Db.Entry.Package.v ~name:"" ~version:"" in + let register ~pkg id () item = List.iter (Load_doc.register_entry ~db ~index_docstring ~index_name ~type_search ~pkg) (Odoc_search.Entry.entries_of_item id item) in - let h = Storage.open_out db_filename in let files = match file_list with | None -> files @@ -39,9 +38,24 @@ let main files file_list index_docstring index_name type_search db_format db_fil close_in h ; files @ other_files in - List.iter (index_file register) files ; - let t = Db_writer.export db in - Storage.save ~db:h t ; + let h = Storage.open_out db_filename in + let flush () = + let t = Db_writer.export ~summarize:(db_format = `ancient) db in + Storage.save ~db:h t + in + List.iter + (fun odoc -> + let pkg, odoc = + match String.split_on_char '\t' odoc with + | [ filename ] -> no_pkg, filename + | [ name; filename ] -> Db.Entry.Package.v ~name ~version:"", filename + | [ name; version; filename ] -> Db.Entry.Package.v ~name ~version, filename + | _ -> failwith ("invalid line: " ^ odoc) + in + index_file (register ~pkg) odoc ; + if db_format = `ancient && Db_writer.load db > 1_000_000 then flush ()) + files ; + flush () ; Storage.close_out h open Cmdliner @@ -67,7 +81,7 @@ let file_list = let odoc_files = let doc = "Path to a .odocl file" in - Arg.(non_empty & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) + Arg.(value & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) let term = Term.(const main $ odoc_files $ file_list $ index_docstring $ index_name $ type_search) diff --git a/index/load_doc.ml b/index/load_doc.ml index f00da85061..5cbb9748d0 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -18,19 +18,30 @@ let path_length str = let kind_cost = function | Entry.Kind.Constructor _ | Entry.Kind.Exception _ | Entry.Kind.Extension_constructor _ - | Entry.Kind.Field _ | Entry.Kind.Type_decl _ | Entry.Kind.Type_extension - | Entry.Kind.Val _ -> + | Entry.Kind.Field _ | Entry.Kind.Module | Entry.Kind.Type_decl _ + | Entry.Kind.Type_extension | Entry.Kind.Val _ -> 0 | _ -> 50 +let rhs_cost = function + | Some str -> String.length str + | None -> 20 + +let cost_doc = function + | Entry.Kind.Constructor _ | Entry.Kind.Exception _ | Entry.Kind.Extension_constructor _ + | Entry.Kind.Field _ | Entry.Kind.Module | Entry.Kind.Module_type + | Entry.Kind.Type_decl _ | Entry.Kind.Type_extension -> + 0 + | _ -> 100 + let cost ~name ~kind ~doc_html ~rhs ~cat = String.length name + (5 * path_length name) - + (if string_starts_with ~prefix:"Stdlib." name then 0 else 20) - + String.length (Option.value ~default:"" rhs) + + (if string_starts_with ~prefix:"Stdlib." name then 0 else 50) + + rhs_cost rhs + kind_cost kind + (if cat = `definition then 0 else 100) - + if doc_html <> "" then 0 else 100 + + if doc_html <> "" then 0 else cost_doc kind let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) @@ -125,13 +136,15 @@ let register_kind ~db elt = | None -> () | Some typ -> register_type_expr ~db elt typ -let rec categorize (id : Odoc_model.Paths.Identifier.Any.t) = +let rec categorize id = let open Odoc_model.Paths in - match id.iv with + match id.Identifier.iv with | `CoreType _ | `CoreException _ | `Root _ | `Page _ | `LeafPage _ -> `definition | `ModuleType _ -> `declaration | `Parameter _ -> `ignore (* redundant with indexed signature *) - | #Identifier.NonSrc.t_pv as x -> + | ( `InstanceVariable _ | `Method _ | `Field _ | `Result _ | `Label _ | `Type _ + | `Exception _ | `Class _ | `ClassType _ | `Value _ | `Constructor _ | `Extension _ + | `ExtensionDecl _ | `Module _ ) as x -> let parent = Identifier.label_parent { id with iv = x } in categorize (parent :> Identifier.Any.t) | `AssetFile _ | `SourceDir _ | `SourceLocationMod _ | `SourceLocation _ | `SourcePage _ diff --git a/index/suffix_tree.ml b/index/suffix_tree.ml index b6b123564e..34f455a4cb 100644 --- a/index/suffix_tree.ml +++ b/index/suffix_tree.ml @@ -63,6 +63,17 @@ end module Entry = Db.Entry +module Uid = struct + type t = int + + let gen = ref 0 + + let make () = + let u = !gen in + gen := u + 1 ; + u +end + module Terminals = struct type t = Entry.t list @@ -79,12 +90,23 @@ module Terminals = struct let rec equal xs ys = match xs, ys with | [], [] -> true - | x :: xs, y :: ys when Entry.equal x y -> equal xs ys + | x :: xs, y :: ys when x == y -> equal xs ys | _ -> false + let equal xs ys = xs == ys || equal xs ys + let mem x = function | y :: _ -> Entry.equal x y | _ -> false + + let minimum = function + | [] -> None + | x :: xs -> + Some + (List.fold_left + (fun found elt -> if Entry.compare found elt <= 0 then found else elt) + x + xs) end module Char_map = Map.Make (Char) @@ -303,64 +325,110 @@ let add_document trie doc = let add_suffixes t text elt = add_document t { Doc.text; uid = elt } -module Uid = struct - let gen = ref 0 - - let make () = - let u = !gen in - gen := u + 1 ; - u -end - module Terminals_cache = Hashtbl.Make (Terminals) +module Seen = Set.Make (Db.Entry) -let export_terminals ~cache_term ts = +let export_terminals ~cache_term ~is_summary ts = try Terminals_cache.find cache_term ts with | Not_found -> - let result = Uid.make (), Entry.Array.of_list ts in + let terminals = + if ts = [] + then Db.String_automata.Empty + else if is_summary + then Db.String_automata.Summary (Array.of_list ts) + else Db.String_automata.Terminals (Array.of_list ts) + in + let result = Uid.make (), terminals in Terminals_cache.add cache_term ts result ; result -let rec export ~cache ~cache_term node = - let terminals_uid, terminals = export_terminals ~cache_term node.terminals in +type result = + { uid : Uid.t + ; t : Db.String_automata.node + ; min : Entry.t + ; seen : Seen.t + } + +let size_of_terminals = function + | Db.String_automata.Empty -> 1 + | Summary arr | Terminals arr -> Array.length arr + +let rec export ~cache ~cache_term ~summarize ~is_root node = + let is_summary = summarize && not is_root in let children = - Char_map.bindings @@ Char_map.map (export ~cache ~cache_term) node.children + Char_map.bindings + @@ Char_map.map (export ~cache ~cache_term ~summarize ~is_root:false) node.children in let children = List.sort - (fun (a_chr, (_, _, a)) (b_chr, (_, _, b)) -> + (fun (a_chr, { min = a; _ }) (b_chr, { min = b; _ }) -> match Entry.compare a b with | 0 -> Char.compare a_chr b_chr | c -> c) children in - let min_terminal = Entry.Array.minimum terminals in + let children_seen = + List.fold_left (fun acc (_, child) -> Seen.union acc child.seen) Seen.empty children + in + let seen = List.fold_left (fun acc e -> Seen.add e acc) children_seen node.terminals in + let children_uids = List.map (fun (chr, { uid; _ }) -> chr, uid) children in + let terminals = + if is_summary + then List.of_seq (Seen.to_seq seen) + else List.filter (fun e -> not (Seen.mem e children_seen)) node.terminals + in let min_child = - match min_terminal, children with - | Some a, (_, (_, _, b)) :: _ -> if Entry.compare a b <= 0 then a else b - | Some a, [] -> a - | None, (_, (_, _, b)) :: _ -> b - | None, [] -> assert false + match children with + | [] -> None + | (_, { min = elt; _ }) :: _ -> Some elt + in + let min_terminal = Terminals.minimum terminals in + let min_child, terminals = + match min_child, min_terminal with + | None, None -> failwith "suffix_tree: empty node" + | None, Some min_terminal -> min_terminal, terminals + | Some min_child, None -> min_child, min_child :: terminals + | Some min_child, Some min_terminal -> + if Db.Entry.compare min_child min_terminal < 0 + then min_child, min_child :: terminals + else min_terminal, terminals in - let children_uids = List.map (fun (chr, (uid, _, _)) -> chr, uid) children in + assert (terminals <> []) ; + let terminals_uid, terminals = export_terminals ~cache_term ~is_summary terminals in let key = node.start, node.len, terminals_uid, children_uids in try Hashtbl.find cache key with | Not_found -> - let children = Array.of_list @@ List.map (fun (_, (_, child, _)) -> child) children in + let children = + Array.of_list @@ List.map (fun (_, { t = child; _ }) -> child) children + in + let size = size_of_terminals terminals in + let size = + if is_summary + then size + else + Array.fold_left + (fun acc child -> acc + child.Db.String_automata.size) + size + children + in let children = if Array.length children = 0 then None else Some children in let node = - { Db.String_automata.start = node.start; len = node.len; terminals; children } + { Db.String_automata.start = node.start; len = node.len; size; terminals; children } in - let result = Uid.make (), node, min_child in + let result = { uid = Uid.make (); t = node; min = min_child; seen } in Hashtbl.add cache key result ; result -let export { buffer; root = t } = - if Char_map.is_empty t.children - then Db.String_automata.empty - else ( - let str = Buf.contents buffer in +let export ~summarize { buffer; root = t } = + let str = Buf.contents buffer in + if String.length str = 0 + then + { Db.String_automata.str + ; t = { start = 0; len = 0; size = 0; children = None; terminals = Empty } + } + else begin let cache = Hashtbl.create 16 in let cache_term = Terminals_cache.create 16 in - let _, t, _ = export ~cache ~cache_term t in - { Db.String_automata.str; t }) + let { t; _ } = export ~cache ~cache_term ~summarize ~is_root:true t in + { Db.String_automata.str; t } + end diff --git a/index/suffix_tree.mli b/index/suffix_tree.mli index 986f145d66..0ff6a5a266 100644 --- a/index/suffix_tree.mli +++ b/index/suffix_tree.mli @@ -8,4 +8,4 @@ type t val make : Buf.t -> t val add_suffixes : t -> string -> Db.Entry.t -> unit -val export : t -> Db.String_automata.t +val export : summarize:bool -> t -> Db.String_automata.t diff --git a/jsoo/dune b/jsoo/dune index b9ac614a3c..eb4be501b5 100644 --- a/jsoo/dune +++ b/jsoo/dune @@ -7,11 +7,3 @@ (alias all) (action (copy main.bc.js sherlodoc.js))) - -(install - (files sherlodoc.js) - ; (section share) - ; This ought to be in share, but for now I can only make it work in bin : I did - ; not manage to fetch sherlodoc.js from share in the dune rules. - (section bin) - (package sherlodoc)) diff --git a/jsoo/main.ml b/jsoo/main.ml index ce03730009..d14fb2296e 100644 --- a/jsoo/main.ml +++ b/jsoo/main.ml @@ -29,8 +29,6 @@ let stream_of_string str = in stream -let don't_wait_for fut = Fut.await fut Fun.id - module Decompress_browser = struct (** This module contains binding to the browser string compression api. It is much faster than using an OCaml library, and does not require sending code @@ -99,7 +97,9 @@ let string_of_kind = let search message db = let query = Jv.get message "data" in let query = query |> Jv.to_jstr |> Jstr.to_string in - let results = Query.(search ~shards:db { query; packages = []; limit = 50 }) in + let results = + Query.Blocking.search ~shards:db { Query.query; packages = []; limit = 50 } + in let _ = Jv.(apply (get global "postMessage")) [| Jv.of_list @@ -112,10 +112,12 @@ let search message db = let prefix_name, name = match kind with | Db.Entry.Kind.Doc -> None, None - | _ -> - let rev_name = name |> String.split_on_char '.' |> List.rev in - ( rev_name |> List.tl |> List.rev |> String.concat "." |> Option.some - , rev_name |> List.hd |> Option.some ) + | _ -> begin + match List.rev (String.split_on_char '.' name) with + | [] -> None, None + | [ hd ] -> None, Some hd + | hd :: tl -> Some (String.concat "." (List.rev tl)), Some hd + end in let kind = string_of_kind kind in let html = @@ -134,6 +136,8 @@ let search message db = in () +let don't_wait_for fut = Fut.await fut Fun.id + let search message = don't_wait_for @@ diff --git a/query/dune b/query/dune index eec425d7db..c9f0de2ac0 100644 --- a/query/dune +++ b/query/dune @@ -1,6 +1,6 @@ (library (name query) - (libraries lwt db)) + (libraries db)) (menhir (modules type_parser) diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml index 9c19d3e89d..e3fac28a15 100644 --- a/query/dynamic_cost.ml +++ b/query/dynamic_cost.ml @@ -2,13 +2,13 @@ module Entry = Db.Entry type query = { name : string list - ; type_paths : Type_distance.Type_path.t option + ; type_paths : Type_distance.t option } let of_query { Query_parser.name; typ } = let type_paths = match typ with - | `typ t -> Some (Type_distance.Type_path.of_typ ~ignore_any:true t) + | `typ t -> Some (Type_distance.paths_of_type t) | _ -> None in { name; type_paths } @@ -27,4 +27,4 @@ let score query entry = | Some cost -> cost | None -> 0 in - 10 * (name_matches + type_cost) + 5 * (name_matches + type_cost) diff --git a/query/io.ml b/query/io.ml new file mode 100644 index 0000000000..a7bc53305c --- /dev/null +++ b/query/io.ml @@ -0,0 +1,40 @@ +module type S = sig + (* avoids a dependency on lwt for sherlodoc.js *) + + type 'a t + + val return : 'a -> 'a t + val map : 'a t -> ('a -> 'b) -> 'b t + val bind : 'a t -> ('a -> 'b t) -> 'b t +end + +module Seq (Io : S) = struct + type 'a t = unit -> 'a node Io.t + + and 'a node = + | Nil + | Cons of 'a * 'a t + + let rec of_seq s () = + match s () with + | Seq.Nil -> Io.return Nil + | Cons (x, xs) -> Io.return (Cons (x, of_seq xs)) + + let rec take n xs () = + if n = 0 + then Io.return Nil + else begin + Io.map (xs ()) + @@ function + | Nil -> Nil + | Cons (x, xs) -> Cons (x, take (n - 1) xs) + end + + let rec to_list acc s = + Io.bind (s ()) + @@ function + | Nil -> Io.return (List.rev acc) + | Cons (x, xs) -> to_list (x :: acc) xs + + let to_list s = to_list [] s +end diff --git a/query/name_cost.ml b/query/name_cost.ml index 650a12404e..3062473d74 100644 --- a/query/name_cost.ml +++ b/query/name_cost.ml @@ -4,7 +4,7 @@ let rec prefix_at ~case ~sub i s j = else if sub.[i] = s.[j] then prefix_at ~case ~sub (i + 1) s (j + 1) else if sub.[i] = Char.lowercase_ascii s.[j] - then prefix_at ~case:(case + 5) ~sub (i + 1) s (j + 1) + then prefix_at ~case:(case + 3) ~sub (i + 1) s (j + 1) else if Char.lowercase_ascii sub.[i] = s.[j] then prefix_at ~case:(case + 10) ~sub (i + 1) s (j + 1) else None @@ -41,7 +41,7 @@ let best_match ?(after = 0) ~sub str = List.fold_left (fun acc (i, case_cost) -> let left = word_boundary str (i - 1) in - let right = word_boundary str (i + String.length sub) in + let right = word_boundary str (i + String.length sub) / 3 in let is_after = if i >= after then 0 else 10 in let cost = case_cost + left + right + is_after in match acc with diff --git a/query/priority_queue.ml b/query/priority_queue.ml index 8579199e3c..6c38416a0c 100644 --- a/query/priority_queue.ml +++ b/query/priority_queue.ml @@ -9,34 +9,50 @@ type t = | All of elt * String_automata.t | Union of elt * t list +let rec size = function + | Empty -> 0 + | Array (i, arr) -> Array.length arr - i + | All (_, s) -> String_automata.size s + | Union (_, xs) -> List.fold_left (fun acc x -> acc + size x) 0 xs + let minimum = function | Empty -> None | Array (i, arr) -> Some arr.(i) | All (elt, _) | Union (elt, _) -> Some elt -let of_sorted_array = function - | None -> Empty - | Some arr -> Array (0, arr) +let of_sorted_array arr = Array (0, arr) let of_automata s = let elt = String_automata.minimum s in All (elt, s) +let of_list lst = + let lst = List.filter (( <> ) Empty) lst in + let min x = + match minimum x with + | None -> assert false + | Some elt -> elt + in + let compare a b = Entry.compare (min a) (min b) in + match List.sort compare lst with + | [] -> Empty + | hd :: _ as lst -> Union (min hd, lst) + let insert_sort x lst = match minimum x with | None -> lst | Some min_elt -> - let rec go lst = + let rec insert lst = match lst with | [] -> [ x ] | y :: ys -> begin match minimum y with - | None -> go ys + | None -> insert ys | Some min_y when Entry.compare min_elt min_y <= 0 -> x :: lst - | _ -> y :: go ys + | _ -> y :: insert ys end in - go lst + insert lst let union_with ~min_elt lst = match List.filter (( <> ) Empty) lst with @@ -54,6 +70,23 @@ let rec union_sorted lst = | Some min_elt -> Union (min_elt, lst) end +let expand_automata ~min_elt ({ String_automata.t; _ } as automata) = + match t.terminals with + | String_automata.Summary arr -> Array (0, arr) + | terminals -> + let terminals = + match terminals with + | String_automata.Empty -> Empty + | Terminals terminals -> Array (0, terminals) + | _ -> assert false + in + let lift child = of_automata { automata with String_automata.t = child } in + let children = + Array.to_list @@ Array.map lift @@ Option.value ~default:[||] t.children + in + let all = insert_sort terminals children in + union_with ~min_elt all + let rec pop_until cond = function | Empty -> Empty | Array (i, arr) as t -> @@ -63,7 +96,7 @@ let rec pop_until cond = function let m = (i + j) / 2 in if i = m then Array (j, arr) else if cond arr.(m) then search i m else search m j in - let rec go j step = + let rec search_from j step = if j >= Array.length arr then begin let last = Array.length arr - 1 in @@ -72,29 +105,31 @@ let rec pop_until cond = function end else if cond arr.(j) then if i = j then t else search (j - (step / 2)) j - else go (j + step) (step * 2) + else search_from (j + step) (step * 2) in - go i 1 + search_from i 1 | All (min_elt, _) as t when cond min_elt -> t - | All (min_elt, ({ String_automata.t; _ } as automata)) -> - let terminals = of_sorted_array t.terminals in - let children = - Array.to_list - @@ Array.map (fun child -> of_automata { automata with t = child }) - @@ Option.value ~default:[||] t.children - in - let all = insert_sort terminals children in - pop_until cond (union_with ~min_elt all) + | All (min_elt, automata) -> pop_until cond (expand_automata ~min_elt automata) | Union (min_elt, _) as t when cond min_elt -> t | Union (_, lst) -> - let rec go = function + let rec pop_union i = function | [] -> [] | x :: xs -> let x' = pop_until cond x in - if x == x' then x :: xs else insert_sort x' (go xs) + if x == x' + then begin + assert (i > 0) ; + x :: xs + end + else insert_sort x' (pop_union (i + 1) xs) in - let lst = go lst in + let lst = pop_union 0 lst in union_sorted lst -let pop_lt elt t = pop_until (fun x -> Entry.compare x elt >= 0) t -let pop_lte elt t = pop_until (fun x -> Entry.compare x elt > 0) t +let pop_lt elt t = + let cmp_lt x = Entry.compare x elt >= 0 in + pop_until cmp_lt t + +let pop_lte elt t = + let cmp_lte x = Entry.compare x elt > 0 in + pop_until cmp_lte t diff --git a/query/priority_queue.mli b/query/priority_queue.mli index 40134bc653..24f42d41bb 100644 --- a/query/priority_queue.mli +++ b/query/priority_queue.mli @@ -3,6 +3,8 @@ type t val minimum : t -> elt option val of_automata : Db.String_automata.t -> t -val of_sorted_array : elt array option -> t +val of_sorted_array : elt array -> t +val of_list : t list -> t val pop_lt : elt -> t -> t val pop_lte : elt -> t -> t +val size : t -> int diff --git a/query/query.ml b/query/query.ml index 134b6be1cb..e683071127 100644 --- a/query/query.ml +++ b/query/query.ml @@ -29,15 +29,14 @@ let find_types ~shard typ = | Db.Type_polarity.Sign.Pos -> shard.Db.db_pos_types | Neg -> shard.Db.db_neg_types in - Succ.union_of_list + Succ.of_automatas @@ Db.Occurences.fold (fun occurrences st acc -> if occurrences < count then acc else begin let ts = Tree.find_star st name in - let ss = List.map Succ.of_automata ts in - List.rev_append ss acc + List.rev_append ts acc end) st_occ []) @@ -75,6 +74,8 @@ type t = ; limit : int } +let pretty params = Parser.(to_string @@ of_string params.query) + let match_packages ~packages { Db.Entry.pkg; _ } = List.exists (String.equal pkg.name) packages @@ -83,26 +84,33 @@ let match_packages ~packages results = | [] -> results | _ -> Seq.filter (match_packages ~packages) results -let rec seq_take n xs () = - if n = 0 - then Seq.Nil - else begin - match xs () with - | Seq.Nil -> Seq.Nil - | Seq.Cons (x, xs) -> Seq.Cons (x, seq_take (n - 1) xs) - end - -let search ~shards ?(dynamic_sort = true) params = - let limit = params.limit in +let search ~shards params = let query = Parser.of_string params.query in let results = search ~shards query in let results = Succ.to_seq results in - let results = match_packages ~packages:params.packages results in - if dynamic_sort - then begin - let query = Dynamic_cost.of_query query in - List.of_seq @@ Top_results.of_seq ~query ~limit results - end - else List.of_seq @@ seq_take params.limit results + query, match_packages ~packages:params.packages results -let pretty params = Parser.(to_string @@ of_string params.query) +module type IO = Io.S + +module Make (Io : IO) = struct + module Tr = Top_results.Make (Io) + + let search ~shards ?(dynamic_sort = true) params = + let limit = params.limit in + let query, results = search ~shards params in + let results = Tr.Seq.of_seq results in + if dynamic_sort + then begin + let query = Dynamic_cost.of_query query in + Tr.of_seq ~query ~limit results + end + else Tr.Seq.to_list @@ Tr.Seq.take limit results +end + +module Blocking = Make (struct + type 'a t = 'a + + let return x = x + let map x f = f x + let bind x f = f x + end) diff --git a/query/query.mli b/query/query.mli index 7f9442410b..f7f7d78ada 100644 --- a/query/query.mli +++ b/query/query.mli @@ -4,33 +4,43 @@ type t = ; limit : int } -val search : shards:Db.t list -> ?dynamic_sort:bool -> t -> Db.Entry.t list -(** [search ~shard ~dynamic_sort {query; packages; limit}] returns [(pretty_query, +val pretty : t -> string + +module type IO = Io.S + +module Make (Io : IO) : sig + val search : shards:Db.t list -> ?dynamic_sort:bool -> t -> Db.Entry.t list Io.t + (** [search ~shard ~dynamic_sort {query; packages; limit}] returns [(pretty_query, results)] where [pretty_query] is a re-printed version of [query] and - [results] is the list of results corresponding to the query and the - various parameters. + [results] is the list of results corresponding to the query and the + various parameters. - - [shards] is a list of databases. [results] is the union of the results of - each database of the list [shards]. If [shards] is a very long list, [api] - might be slow to return, but in some cases you do not have a choice. - Currently, [index] generates only one shard, but it used to generate many - to be able to handle the sheer size of the opam repository. + - [shards] is a list of databases. [results] is the union of the results of + each database of the list [shards]. If [shards] is a very long list, [api] + might be slow to return, but in some cases you do not have a choice. + Currently, [index] generates only one shard, but it used to generate many + to be able to handle the sheer size of the opam repository. - - [~dynamic_sort] changes the order of [results]. It is [true] by default, - and is only set to [false] for debugging purposes. + - [~dynamic_sort] changes the order of [results]. It is [true] by default, + and is only set to [false] for debugging purposes. - - [query] is the query string whose shape is a list of space-separated - words, followed by an optionnal [: ...] type annotation that filters the - results by type. The type annotation accepts [_] as a wildcard : [: string + - [query] is the query string whose shape is a list of space-separated + words, followed by an optionnal [: ...] type annotation that filters the + results by type. The type annotation accepts [_] as a wildcard : [: string -> _] will return entries that take a [string] as argument, but returns - anything. + anything. - - [limit] is the maximum length of [results]. Having a very large number - might be an issue. + - [limit] is the maximum length of [results]. Having a very large number + might be an issue. - - [packages] is not function, use [[]] for this argument. *) + - [packages] is not function, use [[]] for this argument. *) +end -val pretty : t -> string +module Blocking : sig + val search : shards:Db.t list -> ?dynamic_sort:bool -> t -> Db.Entry.t list +end + +(* val search_lwt : shards:Db.t list -> ?dynamic_sort:bool -> t -> Db.Entry.t list Lwt.t *) (** For testing *) module Private : sig diff --git a/query/query_parser.ml b/query/query_parser.ml index 46d6b63cbc..0283842dac 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -15,8 +15,8 @@ let balance_parens str = let type_of_string str = let str = balance_parens str in let lexbuf = Lexing.from_string str in - try Ok (Type_parser.main Type_lexer.token lexbuf) with - | Type_parser.Error -> Error "parse error" + try `typ (Type_parser.main Type_lexer.token lexbuf) with + | _ -> `parse_error let naive_of_string str = List.filter (fun s -> String.length s > 0) (String.split_on_char ' ' str) @@ -30,11 +30,6 @@ type t = ; typ : [ `typ of Db.Typexpr.t | `no_typ | `parse_error ] } -let type_of_string str_typ = - match type_of_string str_typ with - | Ok typ -> `typ typ - | Error _ -> `parse_error - let of_string str = let query_name, typ = match String.index_opt str ':' with diff --git a/query/succ.ml b/query/succ.ml index 084e7ad822..d258e0450c 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,102 +1,134 @@ module Entry = Db.Entry -type t = +type elt = Entry.t + +type s = | Empty + | All | Pq of Priority_queue.t - | Inter of t * t - | Union of t * t + | Inter of s * s + | Union of s * s -let empty = Empty -let of_automata t = Pq (Priority_queue.of_automata t) -let of_array arr = Pq (Priority_queue.of_sorted_array (Some arr)) +type t = + { s : s + ; size : int + } + +let all = { s = All; size = 0 } +let empty = { s = Empty; size = 0 } +let make_pq t = { s = Pq t; size = Priority_queue.size t } +let of_automata t = make_pq (Priority_queue.of_automata t) +let of_automatas ts = make_pq Priority_queue.(of_list (List.map of_automata ts)) +let of_array arr = make_pq (Priority_queue.of_sorted_array arr) let inter a b = - match a, b with + match a.s, b.s with | Empty, _ | _, Empty -> empty + | _, All -> a + | All, _ -> b | x, y when x == y -> a - | x, y -> Inter (x, y) + | x, y -> + let s = if a.size <= b.size then Inter (x, y) else Inter (y, x) in + { s; size = min a.size b.size } let union a b = - match a, b with - | Empty, _ -> b + match a.s, b.s with + | All, _ | _, All -> all | _, Empty -> a + | Empty, _ -> b | x, y when x == y -> a - | x, y -> Union (x, y) + | x, y -> + let s = if a.size >= b.size then Union (x, y) else Union (y, x) in + { s; size = a.size + b.size } let rec join_with fn = function | [] -> [] | [ x ] -> [ x ] | a :: b :: xs -> fn a b :: join_with fn xs -let rec perfect fn = function - | [] -> Empty +let rec perfect ~default fn = function + | [] -> default | [ x ] -> x - | xs -> perfect fn (join_with fn xs) + | xs -> perfect ~default fn (join_with fn xs) -let inter_of_list xs = perfect inter xs -let union_of_list xs = perfect union xs -let best x y = if Entry.compare x y <= 0 then x else y +let inter_of_list xs = + let xs = List.sort (fun a b -> Int.compare a.size b.size) xs in + perfect ~default:all inter xs -let best_opt old_cand new_cand = - match old_cand, new_cand with - | None, None -> None - | None, Some z | Some z, None -> Some z - | Some x, Some y -> Some (best x y) +let union_of_list xs = + let xs = List.sort (fun a b -> Int.compare b.size a.size) xs in + perfect ~default:empty union xs type strictness = - | Gt - | Ge + | First + | Ge of elt + | Gt of elt + +type result = + | Is_empty + | Is_all + | Found_eq of s + | Found_gt of elt * s -let rec succ ~strictness t elt = +let rec succ ~strictness t = match t with - | Empty -> None, t - | Pq pqueue -> - let pqueue = + | Empty -> Is_empty + | All -> begin + match strictness with + | First -> Is_all + | Gt _ -> Is_all + | Ge _ -> Found_eq All + end + | Pq pqueue -> begin + let pqueue' = match strictness with - | Gt -> Priority_queue.pop_lte elt pqueue - | Ge -> Priority_queue.pop_lt elt pqueue + | First -> pqueue + | Ge elt -> Priority_queue.pop_lt elt pqueue + | Gt elt -> Priority_queue.pop_lte elt pqueue in - begin - match Priority_queue.minimum pqueue with - | None -> () - | Some e -> assert (Entry.compare elt e <= 0) - end ; - Priority_queue.minimum pqueue, Pq pqueue - | Union (l, r) -> begin - match succ ~strictness l elt with - | None, _ -> succ ~strictness r elt - | Some elt_l, l when strictness = Ge && Entry.equal elt elt_l -> Some elt, Union (l, r) - | elt_l, l -> - let elt_r, r = succ ~strictness r elt in - best_opt elt_l elt_r, Union (l, r) + match strictness, Priority_queue.minimum pqueue' with + | _, None -> Is_empty + | Ge elt, Some e when Db.Entry.equal e elt -> Found_eq (Pq pqueue') + | _, Some e -> Found_gt (e, Pq pqueue') end - | Inter (l, r) -> - let rec loop elt l r = - match succ ~strictness:Ge l elt with - | None, _ -> None, Empty - | Some elt', l -> - assert (Entry.compare elt elt' <= 0) ; - if Entry.equal elt elt' then Some elt, Inter (l, r) else loop elt' r l - in - begin - match succ ~strictness l elt with - | None, _ -> None, Empty - | Some elt_l, l -> loop elt_l r l + | Union (l, r) -> begin + match succ ~strictness l with + | Is_empty -> succ ~strictness r + | Is_all -> failwith "union all" + | Found_eq l -> Found_eq (Union (l, r)) + | Found_gt (elt_l, l') -> begin + match succ ~strictness r with + | Is_empty -> Found_gt (elt_l, l') + | Is_all -> failwith "union all" + | Found_eq r' -> Found_eq (Union (l', r')) + | Found_gt (elt_r, r') when Db.Entry.compare elt_l elt_r <= 0 -> + Found_gt (elt_l, Union (l', r')) + | Found_gt (elt_r, r') -> Found_gt (elt_r, Union (l', r')) end - -let rec first t = - match t with - | Empty -> None, Empty - | Pq pqueue -> Priority_queue.minimum pqueue, t + end | Inter (l, r) -> begin - match first l with - | None, _ -> None, Empty - | Some elt, l -> succ ~strictness:Ge (Inter (l, r)) elt + match succ ~strictness l with + | Is_empty -> Is_empty + | Is_all -> failwith "inter all" + | Found_eq l' -> begin + match succ ~strictness r with + | Is_empty -> Is_empty + | Is_all -> failwith "inter all" + | Found_eq r' -> Found_eq (Inter (l', r')) + | Found_gt (elt, r') -> Found_gt (elt, Inter (l', r')) + end + | Found_gt (elt, l') -> Found_gt (elt, Inter (l', r)) end - | Union (l, r) -> - let elt_l, l = first l in - let elt_r, r = first r in - best_opt elt_l elt_r, Union (l, r) + +let rec succ_loop ?(count = 0) ~strictness t = + match strictness, succ ~strictness t with + | _, Is_empty -> None + | _, Is_all -> None + | Ge elt, Found_eq t -> Some (elt, t) + | _, Found_gt (elt, t) -> succ_loop ~count:(count + 1) ~strictness:(Ge elt) t + | _ -> assert false + +let first t = succ_loop ~strictness:First t let seq_of_dispenser fn = let rec go () = @@ -106,18 +138,18 @@ let seq_of_dispenser fn = in go -let to_seq t = +let to_seq { s = t; _ } = let state = ref None in let loop () = - let elt, t = + let result = match !state with | None -> first t - | Some (previous_elt, t) -> succ ~strictness:Gt t previous_elt + | Some (previous_elt, t) -> succ_loop ~strictness:(Gt previous_elt) t in - match elt with + match result with | None -> None - | Some elt -> - state := Some (elt, t) ; + | Some (elt, _) -> + state := result ; Some elt in seq_of_dispenser loop diff --git a/query/succ.mli b/query/succ.mli index c0041cd658..cfd9df7008 100644 --- a/query/succ.mli +++ b/query/succ.mli @@ -6,6 +6,7 @@ type t val to_seq : t -> Db.Entry.t Seq.t val empty : t val of_automata : Db.String_automata.t -> t +val of_automatas : Db.String_automata.t list -> t val inter : t -> t -> t val union : t -> t -> t val inter_of_list : t list -> t diff --git a/query/top_results.ml b/query/top_results.ml index deac4a968e..60287b357f 100644 --- a/query/top_results.ml +++ b/query/top_results.ml @@ -33,21 +33,25 @@ let add ~query ~limit elt t = end end -let max_seek = 500 +let max_seek = 10 -let of_seq ~query ~limit seq = - let rec go total_seen t seq = - if total_seen >= limit + max_seek - then t - else begin - match seq () with - | Seq.Nil -> t - | Cons (x, xs) -> begin - match add ~query ~limit x t with - | Stop t -> t - | Continue t -> go (total_seen + 1) t xs +module Make (IO : Io.S) = struct + module Seq = Io.Seq (IO) + + let of_seq ~query ~limit seq = + let rec go total_seen t seq = + if total_seen >= limit + max_seek + then IO.return t + else begin + IO.bind (seq ()) + @@ function + | Seq.Nil -> IO.return t + | Cons (x, xs) -> begin + match add ~query ~limit x t with + | Stop t -> IO.return t + | Continue t -> go (total_seen + 1) t xs + end end - end - in - let t = go 0 empty seq in - Bests.to_seq t.bests + in + IO.map (go 0 empty seq) @@ fun t -> List.of_seq @@ Bests.to_seq t.bests +end diff --git a/query/top_results.mli b/query/top_results.mli index c8c33d0ea1..a1533763a8 100644 --- a/query/top_results.mli +++ b/query/top_results.mli @@ -1 +1,9 @@ -val of_seq : query:Dynamic_cost.query -> limit:int -> Db.Entry.t Seq.t -> Db.Entry.t Seq.t +module Make (IO : Io.S) : sig + module Seq : module type of Io.Seq (IO) + + val of_seq + : query:Dynamic_cost.query + -> limit:int + -> Db.Entry.t Seq.t + -> Db.Entry.t list IO.t +end diff --git a/query/type_distance.ml b/query/type_distance.ml index a8f32164ff..72e414e7fd 100644 --- a/query/type_distance.ml +++ b/query/type_distance.ml @@ -1,125 +1,107 @@ -module Type_path : sig - (** This module contains the transformation that make it possible to compute the - distance between types.. +type step = + | Type of string + | Poly + | Any + | Arrow_left + | Arrow_right + | Product of + { pos : int + ; length : int + } + | Argument of + { pos : int + ; length : int + } - A type can viewed as a tree. [a -> b -> c * d] is the following tree : - {[ - -> - |- a - |- -> - |- b - |- * - |- c - |- d - ]} - We consider the list of paths from root to leaf in the tree of the type. +module Sign = Db.Type_polarity.Sign - Here the paths would be : [ [[-> a]; [-> -> b]; [-> -> * c ]; [-> -> * d]] ] +type t = step list list - We encode slightly more information than that. In the above, it not possible by - looking at a type path to know the child position relative to its parent : In - the path [[-> a]]; [a] is the first child of [->], and in [[-> -> b]]; [[-> b]] - is the second child of [->]. This information is not possible to recover without - the whole tree, so we add it in the list, ass a number after the arrow. +let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst - This makes the type path of the example type look like this : - - {[ - [[-> 1 a]; [-> 2 -> 1 b]; [-> 2 -> 2 * 1 c ]; [-> 2 -> 2 * 2 d]] - ]} *) - - type t = string list list - - val of_typ : ignore_any:bool -> Db.Typexpr.t -> t - (* [of_typ ~ignore_any typ] is the list of type path associated to [typ]. - If [ignore_any] is true, [Any] constructors in [typ] will be ignored, - if it is false, they will be treated like a polymorphic variable. *) -end = struct - module Sign = Db.Type_polarity.Sign - - type t = string list list - - let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst +let rec paths_of_type ~prefix t = + match t with + | Db.Typexpr.Poly _ -> [ Poly :: prefix ] + | Any -> [ Any :: prefix ] + | Arrow (a, b) -> + let prefix_left = Arrow_left :: prefix in + let prefix_right = Arrow_right :: prefix in + List.rev_append + (paths_of_type ~prefix:prefix_left a) + (paths_of_type ~prefix:prefix_right b) + | Constr (name, args) -> + let prefix = Type name :: prefix in + begin + match args with + | [] -> [ prefix ] + | _ -> + let length = List.length args in + rev_concat + @@ List.mapi + (fun i arg -> + let prefix = Argument { pos = i; length } :: prefix in + paths_of_type ~prefix arg) + args + end + | Tuple args -> + let length = List.length args in + rev_concat + @@ List.mapi (fun i arg -> + let prefix = Product { pos = i; length } :: prefix in + paths_of_type ~prefix arg) + @@ args + | Unhandled -> [] - let rec of_typ ~ignore_any ~prefix t = - match t with - | Db.Typexpr.Poly _ -> - let poly = "POLY" in - [ poly :: prefix ] - | Any -> - if ignore_any - then [ "_" :: prefix ] - else ( - let poly = "POLY" in - [ poly :: prefix ]) - | Arrow (a, b) -> - let prefix_left = "->0" :: prefix in - let prefix_right = "->1" :: prefix in - List.rev_append - (of_typ ~ignore_any ~prefix:prefix_left a) - (of_typ ~ignore_any ~prefix:prefix_right b) - | Constr (name, args) -> - let prefix = name :: prefix in - begin - match args with - | [] -> [ prefix ] - | _ -> - rev_concat - @@ List.mapi - (fun i arg -> - let prefix = string_of_int i :: prefix in - of_typ ~ignore_any ~prefix arg) - args - end - | Tuple args -> - rev_concat - @@ List.mapi (fun i arg -> - let prefix = (string_of_int i ^ "*") :: prefix in - of_typ ~ignore_any ~prefix arg) - @@ args - | Unhandled -> [] +let paths_of_type t = List.map List.rev @@ paths_of_type ~prefix:[] t - let of_typ ~ignore_any t = List.map List.rev @@ of_typ ~ignore_any ~prefix:[] t -end +(* *) -let skip_query x = 10 * String.length x -let skip_entry _ = 15 +let skip_entry _ = 10 let distance xs ys = let len_xs = List.length xs in let len_ys = List.length ys in let cache = Array.make_matrix (1 + len_xs) (1 + len_ys) (-1) in - let rec memo i j xs ys = + let inv = Db.Type_polarity.Sign.not in + let rec memo ~xsgn ~ysgn i j xs ys = let r = cache.(i).(j) in if r >= 0 then r else begin - let r = go i j xs ys in + let r = go ~xsgn ~ysgn i j xs ys in cache.(i).(j) <- r ; r end - and go i j xs ys = + and go ~xsgn ~ysgn i j xs ys = match xs, ys with | [], [] -> 0 | [], _ -> 0 - | [ "_" ], _ -> 0 - | x :: xs, y :: ys when x = y -> memo (i + 1) (j + 1) xs ys - | _, "->1" :: ys -> memo i (j + 1) xs ys - | "->1" :: xs, _ -> 1 + memo (i + 1) j xs ys - | xs, [] -> List.fold_left (fun acc x -> acc + skip_query x) 0 xs - | x :: xs', y :: ys' -> - let skip_x = skip_query x in + | [ Any ], _ when xsgn = ysgn -> 0 + | [ Poly ], [ (Any | Poly) ] when xsgn = ysgn -> 0 + | Arrow_left :: xs, Arrow_left :: ys -> + memo ~xsgn:(inv xsgn) ~ysgn:(inv ysgn) (i + 1) (j + 1) xs ys + | x :: xs, y :: ys when x = y && xsgn = ysgn -> memo ~xsgn ~ysgn (i + 1) (j + 1) xs ys + | _, Arrow_left :: ys -> 1 + memo ~xsgn ~ysgn:(inv ysgn) i (j + 1) xs ys + | Arrow_left :: xs, _ -> 1 + memo ~xsgn:(inv xsgn) ~ysgn (i + 1) j xs ys + | _, Arrow_right :: ys -> memo ~xsgn ~ysgn i (j + 1) xs ys + | Arrow_right :: xs, _ -> memo ~xsgn ~ysgn (i + 1) j xs ys + | _, [] -> 10_000 + | Product _ :: xs, Product _ :: ys -> 1 + memo ~xsgn ~ysgn (i + 1) (j + 1) xs ys + | Argument _ :: xs, Argument _ :: ys -> 1 + memo ~xsgn ~ysgn (i + 1) (j + 1) xs ys + | Product _ :: xs, ys -> 1 + memo ~xsgn ~ysgn (i + 1) j xs ys + | xs, Product _ :: ys -> 1 + memo ~xsgn ~ysgn i (j + 1) xs ys + | Type x :: xs', Type y :: ys' when xsgn = ysgn -> begin let skip_y = skip_entry y in - let cost = - match Name_cost.best_match ~sub:x y with - | None -> skip_x + skip_y - | Some (_, cost) -> cost - in - min - (cost + memo (i + 1) (j + 1) xs' ys') - (min (skip_x + memo (i + 1) j xs' ys) (skip_y + memo i (j + 1) xs ys')) + match Name_cost.best_match ~sub:x y with + | None -> skip_y + memo ~xsgn ~ysgn i (j + 1) xs ys' + | Some (_, cost) -> (cost / 3) + memo ~xsgn ~ysgn (i + 1) (j + 1) xs' ys' + end + | xs, Type y :: ys' -> skip_entry y + memo ~xsgn ~ysgn i (j + 1) xs ys' + | xs, Argument _ :: ys' -> memo ~xsgn ~ysgn i (j + 1) xs ys' + | _, (Any | Poly) :: _ -> 10_000 in - go 0 0 xs ys + let pos = Db.Type_polarity.Sign.Pos in + go ~xsgn:pos ~ysgn:pos 0 0 xs ys let minimize = function | [] -> 0 @@ -127,7 +109,7 @@ let minimize = function let used = Array.make (List.length (List.hd arr)) false in let arr = Array.map (fun lst -> - let lst = (1, None) :: List.mapi (fun i x -> x, Some i) lst in + let lst = List.mapi (fun i x -> x, i) lst in List.sort Stdlib.compare lst) @@ Array.of_list arr in @@ -145,48 +127,46 @@ let minimize = function then false else if rem <= 0 then begin - let score = acc + (1 * (Array.length arr - i)) in + (* entry type is smaller than query type *) + let score = acc + (1000 * (Array.length arr - i)) in best := min score !best ; true end else if i >= Array.length arr then begin - best := min !best (acc + (100 * rem)) ; + (* query type is smaller than entry type *) + let score = acc + (5 * rem) in + best := min score !best ; true end else if acc + heuristics.(i) >= !best then true - else ( + else begin let rec find = function | [] -> true | (cost, j) :: rest -> - let ok = - match j with - | None -> - go rem (acc + cost + if rem > Array.length arr - i then 100 else 0) (i + 1) - | Some j -> - if used.(j) - then true - else begin - used.(j) <- true ; - let ok = go (rem - 1) (acc + cost) (i + 1) in - used.(j) <- false ; - ok - end + let continue = + if used.(j) + then true + else begin + used.(j) <- true ; + let continue = go (rem - 1) (acc + cost) (i + 1) in + used.(j) <- false ; + continue + end in - if ok then find rest else false + if continue then find rest else false in - find arr.(i)) + find arr.(i) + end in let _ = go (Array.length used) 0 0 in !best let v ~query_paths ~entry = - let entry_paths = Type_path.of_typ ~ignore_any:false entry in + let entry_paths = paths_of_type entry in match entry_paths, query_paths with | _, [] | [], _ -> 0 | _ -> - let arr = - List.map (fun p -> List.map (fun q -> distance q p) query_paths) entry_paths - in + let arr = List.map (fun p -> List.map (distance p) entry_paths) query_paths in minimize arr diff --git a/query/type_distance.mli b/query/type_distance.mli index 3d73b7eafe..ab97edef37 100644 --- a/query/type_distance.mli +++ b/query/type_distance.mli @@ -1,10 +1,8 @@ -module Type_path : sig - type t +type t - val of_typ : ignore_any:bool -> Db.Typexpr.t -> t -end +val paths_of_type : Db.Typexpr.t -> t -val v : query_paths:Type_path.t -> entry:Db.Typexpr.t -> int +val v : query_paths:t -> entry:Db.Typexpr.t -> int (** [Type_distance.v ~query_paths ~entry] is an integer representing a notion of distance between two types. [query_paths] is a type from a query, and [entry] is the type of a possible candidate for this query. *) diff --git a/sherlodoc.opam b/sherlodoc.opam index 27831cef24..6bd90ee2a6 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -1,28 +1,29 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -synopsis: "Fuzzy search in OCaml documentation" +synopsis: "Search engine for OCaml documentation" maintainer: ["art.wendling@gmail.com"] -authors: ["Arthur Wendling"] +authors: ["Arthur Wendling" "Emile Trotignon"] license: "MIT" homepage: "https://github.com/art-w/sherlodoc" bug-reports: "https://github.com/art-w/sherlodoc/issues" depends: [ "dune" {>= "3.5"} "ocaml" {>= "4.0.8"} - "cmdliner" {>= "1.2.0"} + "odoc" {>= "2.4.0"} + "base64" {>= "3.5.1"} "bigstringaf" {>= "0.9.1"} + "js_of_ocaml" {>= "5.6.0"} + "brr" {>= "0.0.6"} + "cmdliner" {>= "1.2.0"} "decompress" {>= "1.5.3"} - "base64" {>= "3.5.1"} "fpath" {>= "0.7.3"} "lwt" {>= "5.7.0"} "menhir" {>= "20230608"} - "odoc" {>= "2.4.0"} - "tyxml" {>= "4.6.0"} - "brr" {>= "0.0.6"} "ppx_blob" {>= "0.7.2"} - "alcotest" {with-test} + "tyxml" {>= "4.6.0"} "odig" {with-test} "base" {with-test & = "v0.16.3"} + "alcotest" {with-test} ] depopts: [ "dream" {>= "1.0.0~alpha5"} diff --git a/store/db_store.default.ml b/store/db_store.default.ml index 2183d094c6..36fb89cb73 100644 --- a/store/db_store.default.ml +++ b/store/db_store.default.ml @@ -1,5 +1,6 @@ type db_format = - [ `marshal + [ `ancient + | `marshal | `js ] @@ -8,3 +9,4 @@ let available_backends = [ "marshal", `marshal; "js", `js ] let storage_module = function | `marshal -> (module Storage_marshal : Db.Storage.S) | `js -> (module Storage_js : Db.Storage.S) + | `ancient -> failwith "ancient is unsupported" diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 8d289a6529..4553a624ed 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -150,140 +150,140 @@ dependencies so we do not display error (one was encountered with yojson) $ export SHERLODOC_FORMAT=ancient $ sherlodoc index --index-docstring=false $(find ./docs/odoc/base/ -name "*.odocl") > /dev/null $ sherlodoc search --print-cost --limit 100 "S_poly" - 195 val Base.Set.S_poly.mem : 'a t -> 'a -> bool - 202 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list - 206 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list - 212 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t - 212 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b - 213 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b - 215 sig Base.Map.S_poly - 215 sig Base.Set.S_poly - 215 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option - 218 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option - 218 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list - 219 sig Base.Hashtbl.S_poly - 221 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t - 222 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit - 222 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit - 224 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit - 224 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list - 226 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option - 235 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit - 235 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit - 235 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t - 236 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit - 236 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit - 237 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool - 238 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit - 239 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b - 240 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] - 241 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t - 242 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit - 242 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b - 244 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b - 245 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t - 246 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit - 254 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b - 255 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t - 258 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc - 259 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t - 259 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option - 265 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t - 272 type ('a, 'b) Base.Map.S_poly.t - 272 type 'elt Base.Set.S_poly.t - 274 type ('a, 'cmp) Base.Set.S_poly.set - 275 type ('a, 'b) Base.Map.S_poly.tree - 275 type 'elt Base.Set.S_poly.tree - 276 type ('a, 'b) Base.Hashtbl.S_poly.t - 279 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> + 150 sig Base.Map.S_poly + 150 sig Base.Set.S_poly + 154 sig Base.Hashtbl.S_poly + 198 type 'a Base.Hashtbl.S_poly.key = 'a + 207 type ('a, 'b) Base.Map.S_poly.t + 207 type 'elt Base.Set.S_poly.t + 209 type ('a, 'cmp) Base.Set.S_poly.set + 210 val Base.Set.S_poly.mem : 'a t -> 'a -> bool + 210 type ('a, 'b) Base.Map.S_poly.tree + 210 type 'elt Base.Set.S_poly.tree + 211 type ('a, 'b) Base.Hashtbl.S_poly.t + 211 mod Base.Set.S_poly.Named + 217 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list + 221 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + 224 type Base.Map.S_poly.comparator_witness + 224 type Base.Set.S_poly.comparator_witness + 227 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t + 227 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b + 228 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b + 230 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option + 233 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option + 233 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list + 233 mod Base.Map.S_poly.Make_applicative_traversals + 236 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t + 237 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit + 237 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit + 239 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit + 239 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 241 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option + 250 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit + 250 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit + 250 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t + 251 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit + 251 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit + 252 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool + 253 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit + 254 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b + 255 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] + 256 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t + 257 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit + 257 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b + 259 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b + 260 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t + 261 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit + 269 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b + 270 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t + 273 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc + 274 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t + 274 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option + 280 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t + 294 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> 'a key -> if_found:('b -> 'c) -> if_not_found:('a key -> 'c) -> 'c - 283 val Base.Set.S_poly.empty : 'a t - 283 type 'a Base.Hashtbl.S_poly.key = 'a - 283 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> + 298 val Base.Set.S_poly.empty : 'a t + 298 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t - 288 val Base.Map.S_poly.empty : ('k, _) t - 289 type Base.Map.S_poly.comparator_witness - 289 type Base.Set.S_poly.comparator_witness - 290 val Base.Set.S_poly.length : _ t -> int - 293 val Base.Set.S_poly.is_empty : _ t -> bool - 293 val Base.Set.S_poly.singleton : 'a -> 'a t - 294 val Base.Set.S_poly.choose_exn : 'a t -> 'a - 295 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t - 295 val Base.Map.S_poly.length : (_, _) t -> int - 295 val Base.Set.S_poly.max_elt_exn : 'a t -> 'a - 295 val Base.Set.S_poly.min_elt_exn : 'a t -> 'a - 296 val Base.Set.S_poly.of_list : 'a list -> 'a t - 296 val Base.Set.S_poly.of_tree : 'a tree -> 'a t - 296 val Base.Set.S_poly.to_list : 'a t -> 'a list - 296 val Base.Set.S_poly.to_tree : 'a t -> 'a tree - 296 val Base.Set.S_poly.invariants : 'a t -> bool - 297 val Base.Set.S_poly.choose : 'a t -> 'a option - 297 val Base.Set.S_poly.elements : 'a t -> 'a list - 297 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> + 303 val Base.Map.S_poly.empty : ('k, _) t + 305 val Base.Set.S_poly.length : _ t -> int + 308 val Base.Set.S_poly.is_empty : _ t -> bool + 308 val Base.Set.S_poly.singleton : 'a -> 'a t + 309 val Base.Set.S_poly.choose_exn : 'a t -> 'a + 310 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t + 310 val Base.Map.S_poly.length : (_, _) t -> int + 310 val Base.Set.S_poly.max_elt_exn : 'a t -> 'a + 310 val Base.Set.S_poly.min_elt_exn : 'a t -> 'a + 311 val Base.Set.S_poly.of_list : 'a list -> 'a t + 311 val Base.Set.S_poly.of_tree : 'a tree -> 'a t + 311 val Base.Set.S_poly.to_list : 'a t -> 'a list + 311 val Base.Set.S_poly.to_tree : 'a t -> 'a tree + 311 val Base.Set.S_poly.invariants : 'a t -> bool + 312 val Base.Set.S_poly.choose : 'a t -> 'a option + 312 val Base.Set.S_poly.elements : 'a t -> 'a list + 312 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> dst:('k, 'b) t -> f:(key:'k key -> 'a -> 'b option -> 'b Merge_into_action.t) -> unit - 298 val Base.Map.S_poly.data : (_, 'v) t -> 'v list - 298 val Base.Map.S_poly.keys : ('k, _) t -> 'k list - 298 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t - 298 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t - 298 val Base.Set.S_poly.max_elt : 'a t -> 'a option - 298 val Base.Set.S_poly.min_elt : 'a t -> 'a option - 298 val Base.Map.S_poly.is_empty : (_, _) t -> bool - 298 val Base.Set.S_poly.of_array : 'a array -> 'a t - 298 val Base.Set.S_poly.to_array : 'a t -> 'a array - 299 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool - 299 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t - 299 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t - 299 val Base.Hashtbl.S_poly.clear : (_, _) t -> unit - 299 val Base.Hashtbl.S_poly.length : (_, _) t -> int - 299 val Base.Hashtbl.S_poly.hashable : 'a Hashable.t - 300 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool - 301 val Base.Set.S_poly.nth : 'a t -> int -> 'a option - 301 val Base.Set.S_poly.union_list : 'a t list -> 'a t - 302 val Base.Map.S_poly.invariants : ('k, 'v) t -> bool - 302 val Base.Hashtbl.S_poly.is_empty : (_, _) t -> bool - 302 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> + 313 val Base.Map.S_poly.data : (_, 'v) t -> 'v list + 313 val Base.Map.S_poly.keys : ('k, _) t -> 'k list + 313 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t + 313 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t + 313 val Base.Set.S_poly.max_elt : 'a t -> 'a option + 313 val Base.Set.S_poly.min_elt : 'a t -> 'a option + 313 val Base.Map.S_poly.is_empty : (_, _) t -> bool + 313 val Base.Set.S_poly.of_array : 'a array -> 'a t + 313 val Base.Set.S_poly.to_array : 'a t -> 'a array + 314 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool + 314 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t + 314 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t + 314 val Base.Hashtbl.S_poly.clear : (_, _) t -> unit + 314 val Base.Hashtbl.S_poly.length : (_, _) t -> int + 314 val Base.Hashtbl.S_poly.hashable : 'a Hashable.t + 315 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool + 316 val Base.Set.S_poly.nth : 'a t -> int -> 'a option + 316 val Base.Set.S_poly.union_list : 'a t list -> 'a t + 317 val Base.Map.S_poly.invariants : ('k, 'v) t -> bool + 317 val Base.Hashtbl.S_poly.is_empty : (_, _) t -> bool + 317 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> 'a key -> a:'d -> if_found:('b -> 'd -> 'c) -> if_not_found:('a key -> 'd -> 'c) -> 'c - 304 val Base.Map.S_poly.find_exn : ('k, 'v) t -> 'k -> 'v - 305 val Base.Map.S_poly.singleton : 'k -> 'v -> ('k, 'v) t - 305 val Base.Set.S_poly.remove_index : 'a t -> int -> 'a t - 306 val Base.Hashtbl.S_poly.copy : ('a, 'b) t -> ('a, 'b) t - 306 val Base.Map.S_poly.max_elt_exn : ('k, 'v) t -> 'k * 'v - 306 val Base.Map.S_poly.min_elt_exn : ('k, 'v) t -> 'k * 'v - 306 val Base.Set.S_poly.of_sequence : 'a Sequence.t -> 'a t - 306 val Base.Set.S_poly.are_disjoint : 'a t -> 'a t -> bool - 307 val Base.Map.S_poly.find : ('k, 'v) t -> 'k -> 'v option - 307 val Base.Map.S_poly.rank : ('k, _) t -> 'k -> int option - 307 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int + 319 val Base.Map.S_poly.find_exn : ('k, 'v) t -> 'k -> 'v + 320 val Base.Map.S_poly.singleton : 'k -> 'v -> ('k, 'v) t + 320 val Base.Set.S_poly.remove_index : 'a t -> int -> 'a t + 321 val Base.Hashtbl.S_poly.copy : ('a, 'b) t -> ('a, 'b) t + 321 val Base.Map.S_poly.max_elt_exn : ('k, 'v) t -> 'k * 'v + 321 val Base.Map.S_poly.min_elt_exn : ('k, 'v) t -> 'k * 'v + 321 val Base.Set.S_poly.of_sequence : 'a Sequence.t -> 'a t + 321 val Base.Set.S_poly.are_disjoint : 'a t -> 'a t -> bool + 322 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int $ sherlodoc search --print-cost --no-rhs "group b" - 281 val Base.Set.group_by - 360 val Base.List.group - 367 val Base.Sequence.group - 375 val Base.Set.Poly.group_by - 390 val Base.List.Assoc.group - 390 val Base.List.sort_and_group - 403 val Base.Set.Using_comparator.group_by - 413 val Base.Set.Using_comparator.Tree.group_by - 420 val Base.List.Assoc.sort_and_group - 458 val Base.List.groupi - 477 val Base.Set.S_poly.group_by - 478 val Base.Hashtbl.group - 512 val Base.Set.Accessors_generic.group_by - 525 val Base.Set.Creators_and_accessors_generic.group_by - 578 val Base.Hashtbl.Poly.group - 585 val Base.Hashtbl.Creators.group - 592 val Base.Hashtbl.Creators.group - 604 val Base.Hashtbl.S_without_submodules.group - 680 val Base.Hashtbl.S_poly.group + 181 val Base.Set.group_by + 205 val Base.List.group + 212 val Base.Sequence.group + 225 val Base.List.sort_and_group + 228 val Base.List.groupi + 235 val Base.List.Assoc.group + 255 val Base.List.Assoc.sort_and_group + 275 val Base.Set.Poly.group_by + 303 val Base.Set.Using_comparator.group_by + 313 val Base.Set.Using_comparator.Tree.group_by + 323 val Base.Hashtbl.group + 377 val Base.Set.S_poly.group_by + 412 val Base.Set.Accessors_generic.group_by + 423 val Base.Hashtbl.Poly.group + 425 val Base.Set.Creators_and_accessors_generic.group_by + 430 val Base.Hashtbl.Creators.group + 437 val Base.Hashtbl.Creators.group + 449 val Base.Hashtbl.S_without_submodules.group + 525 val Base.Hashtbl.S_poly.group $ sherlodoc search --no-rhs "group by" val Base.Set.group_by val Base.Set.Poly.group_by @@ -293,151 +293,151 @@ dependencies so we do not display error (one was encountered with yojson) val Base.Set.Accessors_generic.group_by val Base.Set.Creators_and_accessors_generic.group_by $ sherlodoc search --print-cost "map2" + 127 mod Base.Applicative.Make_using_map2 + 128 mod Base.Applicative.Make2_using_map2 + 128 mod Base.Applicative.Make3_using_map2 + 138 mod Base.Applicative.Make_using_map2_local + 139 mod Base.Applicative.Make2_using_map2_local + 139 mod Base.Applicative.Make3_using_map2_local 142 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 150 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 157 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 173 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 176 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 199 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 211 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 213 val Base.Or_error.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 226 val Base.Applicative.Pair.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 229 val Base.Applicative.Compose.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 229 val Base.Applicative.S2_to_S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 229 val Base.Applicative.S3_to_S.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 229 val Base.Applicative.Make_using_map2.return : 'a -> 'a X.t - 230 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 232 val Base.Applicative.Make.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t - 232 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 233 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 234 val Base.Array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 235 val Base.Applicative.Make2_using_map2.return : 'a -> ('a, _) X.t - 236 val Base.Applicative.Of_monad.map2 : 'a M.t -> 'b M.t -> f:('a -> 'b -> 'c) -> 'c M.t - 238 val Base.Applicative.Make3_using_map2.return : 'a -> ('a, _, _) X.t - 240 val Base.Either.First.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t - 240 val Base.Applicative.Make_using_map2.all : 'a X.t list -> 'a list X.t - 241 val Base.Either.Second.map2 : ('a, 'e) t -> ('b, 'e) t -> f:('a -> 'b -> 'c) -> ('c, 'e) t - 243 val Base.Applicative.Make_using_map2.map2 : 'a X.t -> 'b X.t -> f:('a -> 'b -> 'c) -> 'c X.t + 147 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 150 mod Base.Applicative.Make_using_map2.Applicative_infix + 151 mod Base.Applicative.Make2_using_map2.Applicative_infix + 151 mod Base.Applicative.Make3_using_map2.Applicative_infix + 155 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 161 mod Base.Applicative.Make_using_map2_local.Applicative_infix + 162 mod Base.Applicative.Make2_using_map2_local.Applicative_infix + 162 mod Base.Applicative.Make3_using_map2_local.Applicative_infix + 166 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 178 sig Base.Applicative.Basic_using_map2 + 178 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 179 sig Base.Applicative.Basic2_using_map2 + 179 sig Base.Applicative.Basic3_using_map2 + 189 sig Base.Applicative.Basic_using_map2_local + 189 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 190 sig Base.Applicative.Basic2_using_map2_local + 190 sig Base.Applicative.Basic3_using_map2_local + 226 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc search --print-cost --static-sort "List map2" - 97 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 193 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 210 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 212 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 214 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 127 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 223 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 240 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 242 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 244 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t $ sherlodoc search --print-cost "List map2" - 177 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 152 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 238 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 250 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t 252 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 253 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 274 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 264 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t $ sherlodoc search --no-rhs "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group $ sherlodoc search --print-cost "list" - 105 val Base.Bytes.to_list : t -> char list - 106 val Base.Queue.of_list : 'a list -> 'a t - 106 val Base.Stack.of_list : 'a list -> 'a t - 109 val Base.Set.to_list : ('a, _) t -> 'a list - 110 val Base.Bytes.of_char_list : char list -> t - 113 val Base.Linked_queue.of_list : 'a list -> 'a t - 121 val Base.Info.of_list : ?trunc_after:int -> t list -> t - 122 val Base.Error.of_list : ?trunc_after:int -> t list -> t - 128 val Base.List.rev : 'a t -> 'a t - 129 val Base.List.hd_exn : 'a t -> 'a - 129 val Base.List.return : 'a -> 'a t - 130 val Base.Array.of_list_rev : 'a list -> 'a t - 130 val Base.String.to_list_rev : t -> char list - 131 val Base.List.join : 'a t t -> 'a t - 131 val Base.List.tl_exn : 'a t -> 'a t - 131 val Base.Sequence.shift_right_with_list : 'a t -> 'a list -> 'a t - 133 val Base.List.concat : 'a t t -> 'a t - 133 val Base.Sequence.to_list_rev : 'a t -> 'a list - 134 val Base.List.last : 'a t -> 'a option - 135 val Base.List.ignore_m : 'a t -> unit t - 136 val Base.List.drop : 'a t -> int -> 'a t - 136 val Base.List.take : 'a t -> int -> 'a t - 136 val Base.Sequence.cycle_list_exn : 'a list -> 'a t - 137 val Base.List.nth_exn : 'a t -> int -> 'a - 139 val Base.List.append : 'a t -> 'a t -> 'a t + 81 type 'a Base.list = 'a List.t + 93 type 'a Base.Export.list = 'a List.t + 101 type 'a Base.List.t = 'a list + 104 mod Base.List + 104 mod Caml.List + 108 val Base.List.rev : 'a t -> 'a t + 109 val Base.List.hd_exn : 'a t -> 'a + 109 val Base.List.return : 'a -> 'a t + 110 val Base.Bytes.to_list : t -> char list + 111 val Base.List.join : 'a t t -> 'a t + 111 val Base.List.tl_exn : 'a t -> 'a t + 111 val Base.Queue.of_list : 'a list -> 'a t + 111 val Base.Stack.of_list : 'a list -> 'a t + 113 val Base.List.concat : 'a t t -> 'a t + 113 mod Shadow_stdlib.List + 114 val Base.List.last : 'a t -> 'a option + 114 val Base.Set.to_list : ('a, _) t -> 'a list + 115 mod Base.List.Assoc + 115 mod Base.List.Infix + 115 cons Base.Sexp.t.List : t list -> t + 115 val Base.List.ignore_m : 'a t -> unit t + 115 val Base.Bytes.of_char_list : char list -> t + 116 val Base.List.drop : 'a t -> int -> 'a t + 116 val Base.List.take : 'a t -> int -> 'a t + 117 val Base.List.nth_exn : 'a t -> int -> 'a $ sherlodoc search --print-cost ": list" - 95 val Base.Bytes.to_list : t -> char list - 97 val Base.String.split_lines : t -> t list - 100 val Base.String.to_list_rev : t -> char list - 103 val Base.Sequence.to_list_rev : 'a t -> 'a list - 105 val Caml.(@) : 'a list -> 'a list -> 'a list - 105 val Base.Pretty_printer.all : unit -> string list - 109 val Base.Set.to_list : ('a, _) t -> 'a list - 110 val Base.Hashtbl.data : (_, 'b) t -> 'b list - 110 val Base.Set.elements : ('a, _) t -> 'a list - 112 val Base.String.split : t -> on:char -> t list - 114 val Base.Hashtbl.keys : ('a, _) t -> 'a key list - 119 val Base.Map.data : (_, 'v, _) t -> 'v list - 119 val Base.Map.keys : ('k, _, _) t -> 'k list - 120 val Base.Hashtbl.Poly.data : (_, 'b) t -> 'b list - 124 val Base.Hashtbl.Poly.keys : ('a, _) t -> 'a key list - 126 val Base.String.split_on_chars : t -> on:char list -> t list - 136 val Base.Hashtbl.to_alist : ('a, 'b) t -> ('a key * 'b) list - 138 val Base.List.rev : 'a t -> 'a t - 139 val Base.List.return : 'a -> 'a t - 139 val Base.String.Search_pattern.split_on : t -> string -> string list - 141 val Base.List.join : 'a t t -> 'a t - 141 val Base.List.tl_exn : 'a t -> 'a t - 142 val Base.Hashtbl.find_multi : ('a, 'b list) t -> 'a key -> 'b list - 143 val Base.List.concat : 'a t t -> 'a t - 145 val Base.List.ignore_m : 'a t -> unit t + 118 val Base.List.rev : 'a t -> 'a t + 119 val Base.List.return : 'a -> 'a t + 120 val Base.Bytes.to_list : t -> char list + 121 val Base.List.join : 'a t t -> 'a t + 121 val Base.List.tl_exn : 'a t -> 'a t + 122 val Base.String.split_lines : t -> t list + 123 val Base.List.concat : 'a t t -> 'a t + 125 val Base.List.ignore_m : 'a t -> unit t + 125 val Base.String.to_list_rev : t -> char list + 128 val Base.Sequence.to_list_rev : 'a t -> 'a list + 130 val Base.Pretty_printer.all : unit -> string list + 132 val Base.List.all_unit : unit t list -> unit t + 132 val Base.List.filter_opt : 'a option t -> 'a t + 132 val Base.List.transpose_exn : 'a t t -> 'a t t + 132 val Base.List.concat_no_order : 'a t t -> 'a t + 145 val Caml.(@) : 'a list -> 'a list -> 'a list + 149 val Base.Set.to_list : ('a, _) t -> 'a list + 150 val Base.Hashtbl.data : (_, 'b) t -> 'b list + 150 val Base.Set.elements : ('a, _) t -> 'a list + 151 val Base.List.drop : 'a t -> int -> 'a t + 151 val Base.List.take : 'a t -> int -> 'a t + 152 val Base.String.split : t -> on:char -> t list + 154 val Base.List.append : 'a t -> 'a t -> 'a t + 154 val Base.Hashtbl.keys : ('a, _) t -> 'a key list + 158 val Base.List.rev_append : 'a t -> 'a t -> 'a t Partial name search: $ sherlodoc search --print-cost "strin" - 169 val Caml.string_of_int : int -> string - 171 val Caml.string_of_bool : bool -> string - 173 val Caml.string_of_float : float -> string - 186 val Base.Sexp.of_string : unit - 189 val Caml.prerr_string : string -> unit - 189 val Caml.print_string : string -> unit - 189 val Caml.int_of_string : string -> int - 191 val Caml.bool_of_string : string -> bool - 192 val Base.Exn.to_string : t -> string - 192 val Base.Sys.max_string_length : int - 193 val Caml.float_of_string : string -> float - 194 val Base.Float.to_string : t -> string - 197 val Base.Exn.to_string_mach : t -> string - 197 val Base.Info.to_string_hum : t -> string - 197 val Base.Sign.to_string_hum : t -> string - 198 val Base.Error.to_string_hum : t -> string - 198 val Base.Info.to_string_mach : t -> string - 199 val Base.Error.to_string_mach : t -> string - 200 val Caml.int_of_string_opt : string -> int option - 201 val Caml.string_of_format : ('a, 'b, 'c, 'd, 'e, 'f) format6 -> string - 202 val Caml.bool_of_string_opt : string -> bool option - 202 val Base.Or_error.error_string : string -> _ t - 204 val Base.Buffer.add_string : t -> string -> unit - 204 val Caml.float_of_string_opt : string -> float option - 204 val Base.Sign_or_nan.to_string_hum : t -> string + 97 type Base.string = String.t + 109 type Base.Export.string = String.t + 109 val Caml.string_of_int : int -> string + 111 val Caml.string_of_bool : bool -> string + 113 val Caml.string_of_float : float -> string + 116 val Base.Sexp.of_string : unit + 117 type Base.String.t = string + 117 type Base.String.elt = char + 119 val Base.String.rev : t -> t + 119 val Caml.prerr_string : string -> unit + 119 val Caml.print_string : string -> unit + 119 val Caml.int_of_string : string -> int + 121 mod Base.String + 121 mod Caml.String + 121 val Caml.bool_of_string : string -> bool + 122 val Base.String.hash : t -> int + 122 val Base.Exn.to_string : t -> string + 122 val Base.Sys.max_string_length : int + 123 val Base.String.escaped : t -> t + 123 val Caml.float_of_string : string -> float + 123 val Base.String.max_length : int + 124 val Base.String.(^) : t -> t -> t + 124 val Base.Float.to_string : t -> string + 125 mod Base.Stringable + 125 val Base.String.uppercase : t -> t $ sherlodoc search --print-cost "tring" - 164 val Base.String.rev : t -> t - 166 val Base.Sexp.of_string : unit - 167 val Base.String.hash : t -> int - 168 val Base.String.escaped : t -> t - 168 val Base.String.max_length : int - 169 val Base.String.(^) : t -> t -> t - 169 val Caml.prerr_string : string -> unit - 169 val Caml.print_string : string -> unit - 169 val Caml.int_of_string : string -> int - 170 val Base.String.uppercase : t -> t - 171 val Caml.bool_of_string : string -> bool - 171 val Base.String.capitalize : t -> t - 172 val Base.Exn.to_string : t -> string - 172 val Base.String.append : t -> t -> t - 173 val Caml.float_of_string : string -> float - 174 val Base.String.equal : t -> t -> bool - 174 val Base.String.prefix : t -> int -> t - 174 val Base.String.suffix : t -> int -> t - 174 val Base.Float.to_string : t -> string - 175 val Base.String.compare : t -> t -> int - 177 val Base.String.ascending : t -> t -> int - 177 val Base.String.split_lines : t -> t list - 179 val Base.String.drop_prefix : t -> int -> t - 179 val Base.String.drop_suffix : t -> int -> t - 179 val Base.String.common_suffix : t list -> t + 127 type Base.string = String.t + 132 type Base.String.t = string + 132 type Base.String.elt = char + 134 val Base.String.rev : t -> t + 136 mod Base.String + 136 mod Caml.String + 136 val Base.Sexp.of_string : unit + 137 val Base.String.hash : t -> int + 138 val Base.String.escaped : t -> t + 138 val Base.String.max_length : int + 139 val Base.String.(^) : t -> t -> t + 139 val Caml.prerr_string : string -> unit + 139 val Caml.print_string : string -> unit + 139 type Base.Export.string = String.t + 139 val Caml.int_of_string : string -> int + 140 val Base.String.uppercase : t -> t + 141 val Caml.bool_of_string : string -> bool + 141 type Base.String.Caseless.t = t + 141 val Base.String.capitalize : t -> t + 142 val Base.Exn.to_string : t -> string + 142 val Base.String.append : t -> t -> t + 143 val Caml.float_of_string : string -> float + 144 val Base.String.equal : t -> t -> bool + 144 val Base.String.prefix : t -> int -> t + 144 val Base.Float.to_string : t -> string diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 5a70e1ef24..932ab2d50b 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -159,9 +159,9 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2284 db.js - 1724 db.js.gz - 1776 megaodocl.gz + 2088 db.js + 1580 db.js.gz + 1772 megaodocl.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f @@ -172,7 +172,7 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 96K html/sherlodoc.js + 100K html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index d1ea3a6bab..30d114faed 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -16,31 +16,31 @@ val Main.multiple_hit_2 : foo val Main.multiple_hit_3 : foo $ sherlodoc search --print-cost "name_conflict" - 169 val Main.name_conflict : foo - 169 type Main.name_conflict = foo + 84 type Main.name_conflict = foo + 184 val Main.name_conflict : foo $ sherlodoc search "nesting_priority" val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo $ sherlodoc search "list" type 'a Main.list - val Main.Map.to_list : foo type 'a Main.List.t = 'a list - val Main.List.map : ('a -> 'b) -> 'a t -> 'b t mod Main.List + val Main.Map.to_list : foo + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo $ sherlodoc search "map" - val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - val Main.Map.to_list : foo mod Main.Map + val Main.Map.to_list : foo + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo $ sherlodoc search "list map" val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - val Main.Map.to_list : foo val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.Map.to_list : foo val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.foo : foo $ sherlodoc search "map2" @@ -55,33 +55,33 @@ val Main.produce_2' : unit -> unit -> moo val Main.value : moo $ sherlodoc search ":moo -> _" - val Main.consume : moo -> unit cons Main.MyExtension : moo -> extensible_type + val Main.consume : moo -> unit val Main.consume_2 : moo -> moo -> unit val Main.consume_2_other : moo -> t -> unit $ sherlodoc search "modtype" sig Main.Modtype val Main.Modtype.v_modtype : foo $ sherlodoc search "S" - sig Main.S mod Main.S_to_S1 - type 'a Main.list - type Main.MyExtension + sig Main.S type Main.extensible_type = .. type 'a Main.List.t = 'a list + 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 val Main.nesting_priority : foo val Main.consume_2 : moo -> moo -> unit val Main.Nest.nesting_priority : foo val Main.consume_2_other : moo -> t -> unit - cons Main.MyExtension : moo -> extensible_type val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - mod Main.List - mod Main.Nest + val Main.foo : foo val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - val Main.foo : foo $ sherlodoc search "qwertyuiopasdfghjklzxcvbnm" [No results] $ sherlodoc search "hidden" @@ -91,21 +91,21 @@ val Main.produce : unit -> moo val Main.produce_2' : unit -> unit -> moo $ sherlodoc search ":'a" + val Main.poly_param : 'a boo val Main.poly_1 : 'a -> 'b -> 'c - val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - val Main.poly_param : 'a boo $ sherlodoc search ": 'a -> 'b -> 'c " val Main.poly_1 : 'a -> 'b -> 'c val Main.poly_2 : 'a -> 'b -> 'c -> 'a -> 'b -> 'c - val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc search ": ('a -> 'b) -> 'a t -> 'b t" val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t val Main.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + val Main.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc search ": 'a bo" val Main.poly_param : 'a boo $ sherlodoc search ":extensible_type" diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 95daa0756a..b8545e0ed3 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -8,10 +8,10 @@ $ export SHERLODOC_FORMAT=ancient $ sherlodoc index $(find . -name '*.odocl') $ sherlodoc search --print-cost "list" - 154 type 'a Main.list - 221 type 'a Main.List.t = 'a list - 229 val Main.List.empty : 'a t * 'b t - 242 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t - 254 mod Main.List + 89 type 'a Main.list + 101 type 'a Main.List.t = 'a list + 104 mod Main.List + 209 val Main.List.empty : 'a t * 'b t + 222 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t $ sherlodoc search ": (int, 'a) result" val Main.ok_zero : (int, 'a) result diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t index 9c499626d4..d9b72e95f0 100644 --- a/test/cram/module_type_cost.t/run.t +++ b/test/cram/module_type_cost.t/run.t @@ -10,10 +10,10 @@ Here we expect to have the `my_function` from the module be above the one from the module type. $ sherlodoc search --print-cost --no-rhs "my_function" - 181 val Main.M.my_function - 184 val Main.Make.my_function - 281 val Main.S.my_function + 196 val Main.M.my_function + 199 val Main.Make.my_function + 296 val Main.S.my_function Here we expect both the module type and the module to be ranked the same $ sherlodoc search --print-cost "module" - 281 mod Main.Module_nype - 281 sig Main.Module_type + 116 mod Main.Module_nype + 166 sig Main.Module_type diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 0f1733bbe5..ce7480a783 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 96K sherlodoc.js + 100K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html diff --git a/www/dune b/www/dune index 4d6d725378..b8ea93c04f 100644 --- a/www/dune +++ b/www/dune @@ -1,6 +1,7 @@ (library (name www) - (libraries cmdliner dream tyxml db db_store query) + (optional) + (libraries lwt cmdliner dream tyxml db db_store query) (preprocess (pps ppx_blob)) (preprocessor_deps diff --git a/www/static/style.css b/www/static/style.css index 56c11b1dea..98e5bca588 100644 --- a/www/static/style.css +++ b/www/static/style.css @@ -8,6 +8,7 @@ body { margin-bottom: 1em; min-height: 100%; background: url("/bg.jpg") no-repeat bottom right; + font-family: system-ui, sans-serif; } form { @@ -54,14 +55,22 @@ a { text-decoration: none; } -pre { - margin: 0.5em; +.comment p { + line-height: 1.3em; +} + +.comment pre { + margin: 0 2em; font-size: 1.1rem; - white-space: normal; + white-space: pre; } -pre { + +.found > li > pre { + margin: 0.5em; padding-left: 6em; text-indent: -6em; + font-size: 1.1rem; + white-space: normal; } pre em { @@ -74,7 +83,7 @@ ul { padding: 0; } -.found li { +.found > li { list-style: none; margin: 0; padding: 0; @@ -83,39 +92,45 @@ ul { margin-left: 0.95em; } -.found li em { +.found > li > pre em { margin: 0 -3px; padding: 3px; color: black; } -.found li:hover em { +.found > li:hover > pre em { background: #FADFB1; } -.found li a:hover em { +.found > li > pre a:hover em { background: #EABB60; border-bottom: 2px solid #553515; } -h1, ul.doc, p { +h1, ul.doc, .comment { margin: 0; padding: 0; margin-left: 3.4rem; } +.comment a, .comment a:visited { color: black } +.comment .at-tag { font-style: italic } +.comment li { list-style: square } + h1 { margin-bottom: 1em; font-size: 3em; + font-family: serif; } p.doc { margin-bottom: 1em; + margin-left: 2.3em; font-size: 1.5em; } -ul.doc li { +ul.doc > li { margin-bottom: 0.5em; } @@ -170,11 +185,15 @@ code { .ad { padding: 3rem 0; - font-family: monospace; + margin-left: 2.3em; font-style: italic; font-size: 1rem; } +pre, code, .ad, .packages a, input#q { + font-family: ui-monospace, 'Fira Code', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; +} + .ad svg { vertical-align: middle; margin-right: 0.5rem } .categories { @@ -206,7 +225,6 @@ code { display: inline-block; white-space: nowrap; margin-right: 1.5em; - font-family: monospace; } .packages a:hover { background: #eee; diff --git a/www/ui.ml b/www/ui.ml index 1556c1f066..c237e37966 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -10,16 +10,17 @@ let string_of_kind = let open Db.Entry.Kind in function | Doc -> "doc" - | Type_decl _ -> "type" - | Module -> "mod" - | Exception _ -> "exn" + | Type_decl None -> "type" + | Type_decl (Some str) -> "type " ^ str + | Module -> "module" + | Exception _ -> "exception" | Class_type -> "class" - | Method -> "meth" + | Method -> "method" | Class -> "class" | Type_extension -> "type" - | Extension_constructor _ -> "cons" - | Module_type -> "sig" - | Constructor _ -> "cons" + | Extension_constructor _ -> "constructor" + | Module_type -> "module type" + | Constructor _ -> "constructor" | Field _ -> "field" | Val _ -> "val" @@ -33,7 +34,12 @@ let render_elt elt = | None -> [] in let kind = string_of_kind elt.kind ^ " " in - [ txt kind; a ~a:link [ em [ txt elt.name ] ] ] @ rhs + let doc = + if elt.doc_html = "" + then [] + else [ div ~a:[ a_class [ "comment" ] ] [ Unsafe.data elt.doc_html ] ] + in + pre (txt kind :: a ~a:link [ em [ txt elt.name ] ] :: rhs) :: doc let render_pkg elt = let open Db.Entry in @@ -47,9 +53,7 @@ let render_pkg elt = ] ] -let render_result elt = - let open Db.Entry in - render_pkg elt @ [ pre (render_elt elt); Unsafe.data elt.doc_html ] +let render_result elt = render_pkg elt @ render_elt elt let render ~pretty results = match results with diff --git a/www/www.ml b/www/www.ml index c1f74feb21..91032d6be4 100644 --- a/www/www.ml +++ b/www/www.ml @@ -1,18 +1,25 @@ module Storage = Db.Storage module H = Tyxml.Html +open Lwt.Syntax + +module Query_lwt = Query.Make (struct + type 'a t = 'a Lwt.t + + let return = Lwt.return + let map x f = Lwt.map f x + let bind x f = Lwt.bind x f + end) let api ~shards params = - let results = Query.search ~shards params in + let+ results = Query_lwt.search ~shards params in let pretty = Query.pretty params in - Lwt.return (Ui.render ~pretty results) + Ui.render ~pretty results let api ~shards params = if String.trim params.Query.query = "" then Lwt.return (Ui.explain ()) else api ~shards params -open Lwt.Syntax - let get_query params = Option.value ~default:"" (Dream.query params "q") let get_packages params = From 8b915354451528f835d70204804a4ea767f68bbe Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 30 Jan 2024 16:29:58 +0100 Subject: [PATCH 253/285] fix missing sort on suffix tree terminals --- index/suffix_tree.ml | 22 ++++++++++------------ test/cram/base_web.t | 8 ++++---- test/cram/simple.t/run.t | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/index/suffix_tree.ml b/index/suffix_tree.ml index 34f455a4cb..a3ddd1ad5c 100644 --- a/index/suffix_tree.ml +++ b/index/suffix_tree.ml @@ -98,15 +98,6 @@ module Terminals = struct let mem x = function | y :: _ -> Entry.equal x y | _ -> false - - let minimum = function - | [] -> None - | x :: xs -> - Some - (List.fold_left - (fun found elt -> if Entry.compare found elt <= 0 then found else elt) - x - xs) end module Char_map = Map.Make (Char) @@ -371,18 +362,23 @@ let rec export ~cache ~cache_term ~summarize ~is_root node = List.fold_left (fun acc (_, child) -> Seen.union acc child.seen) Seen.empty children in let seen = List.fold_left (fun acc e -> Seen.add e acc) children_seen node.terminals in - let children_uids = List.map (fun (chr, { uid; _ }) -> chr, uid) children in let terminals = if is_summary then List.of_seq (Seen.to_seq seen) - else List.filter (fun e -> not (Seen.mem e children_seen)) node.terminals + else + List.sort Entry.compare + @@ List.filter (fun e -> not (Seen.mem e children_seen)) node.terminals in let min_child = match children with | [] -> None | (_, { min = elt; _ }) :: _ -> Some elt in - let min_terminal = Terminals.minimum terminals in + let min_terminal = + match terminals with + | [] -> None + | hd :: _ -> Some hd + in let min_child, terminals = match min_child, min_terminal with | None, None -> failwith "suffix_tree: empty node" @@ -393,8 +389,10 @@ let rec export ~cache ~cache_term ~summarize ~is_root node = then min_child, min_child :: terminals else min_terminal, terminals in + assert (min_child == Seen.min_elt seen) ; assert (terminals <> []) ; let terminals_uid, terminals = export_terminals ~cache_term ~is_summary terminals in + let children_uids = List.map (fun (chr, { uid; _ }) -> chr, uid) children in let key = node.start, node.len, terminals_uid, children_uids in try Hashtbl.find cache key with | Not_found -> diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 932ab2d50b..1dcb34d62c 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -159,9 +159,9 @@ in queryable way, so a size increase is expected. It should just be reasonable. $ gzip -k megaodocl $ du -s *.js *.gz - 2088 db.js - 1580 db.js.gz - 1772 megaodocl.gz + 2108 db.js + 1592 db.js.gz + 1776 megaodocl.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f @@ -172,7 +172,7 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js $ du -sh html/sherlodoc.js - 100K html/sherlodoc.js + 92K html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index ce7480a783..bcf7e7598c 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 100K sherlodoc.js + 92K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html From cba8adeefb0f7ec22c01c7bb2cfbc590fbf9626a Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 30 Jan 2024 18:34:16 +0100 Subject: [PATCH 254/285] fix ancient segfault on empty suffix tree --- db/string_automata.ml | 6 ++++++ db/string_automata.mli | 1 + index/suffix_tree.ml | 5 +---- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/db/string_automata.ml b/db/string_automata.ml index 5866aed57b..9714acf78a 100644 --- a/db/string_automata.ml +++ b/db/string_automata.ml @@ -16,6 +16,12 @@ type t = ; t : node } +let empty = { start = 0; len = 0; size = 0; children = None; terminals = Empty } + +let empty () = + (* avoid ancient segfaulting on statically allocated values *) + Obj.obj @@ Obj.dup @@ Obj.repr empty + let size t = t.t.size let minimum { t; _ } = diff --git a/db/string_automata.mli b/db/string_automata.mli index 7e3bce7831..9d02e06ebc 100644 --- a/db/string_automata.mli +++ b/db/string_automata.mli @@ -19,6 +19,7 @@ type t = ; t : node } +val empty : unit -> node val find : t -> string -> t option val find_star : t -> string -> t list val minimum : t -> Entry.t diff --git a/index/suffix_tree.ml b/index/suffix_tree.ml index a3ddd1ad5c..7e96c8d671 100644 --- a/index/suffix_tree.ml +++ b/index/suffix_tree.ml @@ -420,10 +420,7 @@ let rec export ~cache ~cache_term ~summarize ~is_root node = let export ~summarize { buffer; root = t } = let str = Buf.contents buffer in if String.length str = 0 - then - { Db.String_automata.str - ; t = { start = 0; len = 0; size = 0; children = None; terminals = Empty } - } + then { Db.String_automata.str; t = Db.String_automata.empty () } else begin let cache = Hashtbl.create 16 in let cache_term = Terminals_cache.create 16 in From 1b39bd2274d2106f1329b5d883a6f50892c1f5ac Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 30 Jan 2024 18:49:38 +0100 Subject: [PATCH 255/285] test ancient on empty databases --- test/cram/simple.t/run.t | 2 +- test/cram_ancient/dune | 3 +++ test/cram_ancient/empty.t | 7 +++++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 test/cram_ancient/dune create mode 100644 test/cram_ancient/empty.t diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index bcf7e7598c..ce7480a783 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -11,7 +11,7 @@ Here cat is used to remove weird permissions on executable built by dune $ cat ../../../jsoo/main.bc.js > sherlodoc.js $ du -sh sherlodoc.js - 92K sherlodoc.js + 100K sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html diff --git a/test/cram_ancient/dune b/test/cram_ancient/dune new file mode 100644 index 0000000000..9e980dd522 --- /dev/null +++ b/test/cram_ancient/dune @@ -0,0 +1,3 @@ +(cram +(enabled_if %{lib-available:ancient} ) + (deps %{bin:odoc} %{bin:sherlodoc})) diff --git a/test/cram_ancient/empty.t b/test/cram_ancient/empty.t new file mode 100644 index 0000000000..443a468af0 --- /dev/null +++ b/test/cram_ancient/empty.t @@ -0,0 +1,7 @@ + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=ancient + $ sherlodoc index + $ sherlodoc search "query" + [No results] + $ sherlodoc search ": type_query" + [No results] From 5193f8adda721d168503a2c26e3b48e02e6abf0d Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 30 Jan 2024 18:52:58 +0100 Subject: [PATCH 256/285] test dont fail when ancient is absent --- test/cram/base_cli.t | 2 +- test/cram/cli.t/run.t | 2 +- test/cram/cli_poly.t/run.t | 2 +- test/cram/cli_small.t/run.t | 2 +- test/cram/module_type_cost.t/run.t | 2 +- test/cram_ancient/cli_small.t/main.mli | 18 ++++++++++++++++++ test/cram_ancient/cli_small.t/run.t | 17 +++++++++++++++++ 7 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 test/cram_ancient/cli_small.t/main.mli create mode 100644 test/cram_ancient/cli_small.t/run.t diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 4553a624ed..17a3aa5e53 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -147,7 +147,7 @@ dependencies so we do not display error (one was encountered with yojson) ./docs/odoc/base/page-index.odocl ./docs/odoc/base/shadow_stdlib/shadow_stdlib.odocl $ export SHERLODOC_DB=db.bin - $ export SHERLODOC_FORMAT=ancient + $ export SHERLODOC_FORMAT=marshal $ sherlodoc index --index-docstring=false $(find ./docs/odoc/base/ -name "*.odocl") > /dev/null $ sherlodoc search --print-cost --limit 100 "S_poly" 150 sig Base.Map.S_poly diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 30d114faed..bae3d9cb60 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -7,7 +7,7 @@ $ du -sh megaodocl 8.0K megaodocl $ export SHERLODOC_DB=db.bin - $ export SHERLODOC_FORMAT=ancient + $ export SHERLODOC_FORMAT=marshal $ sherlodoc index $(find . -name '*.odocl') $ sherlodoc search "unique_name" val Main.unique_name : foo diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index b799a74098..4b840d9330 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -7,7 +7,7 @@ $ du -sh megaodocl 4.0K megaodocl $ export SHERLODOC_DB=db.bin - $ export SHERLODOC_FORMAT=ancient + $ export SHERLODOC_FORMAT=marshal $ sherlodoc index $(find . -name '*.odocl') TODO : get a result for the query bellow $ sherlodoc search ":'a" diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index b8545e0ed3..515b28e453 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,7 +5,7 @@ $ du -sh megaodocl 4.0K megaodocl $ export SHERLODOC_DB=db.bin - $ export SHERLODOC_FORMAT=ancient + $ export SHERLODOC_FORMAT=marshal $ sherlodoc index $(find . -name '*.odocl') $ sherlodoc search --print-cost "list" 89 type 'a Main.list diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t index d9b72e95f0..a91585251a 100644 --- a/test/cram/module_type_cost.t/run.t +++ b/test/cram/module_type_cost.t/run.t @@ -5,7 +5,7 @@ $ du -sh megaodocl 4.0K megaodocl $ export SHERLODOC_DB=db.bin - $ export SHERLODOC_FORMAT=ancient + $ export SHERLODOC_FORMAT=marshal $ sherlodoc index $(find . -name '*.odocl') Here we expect to have the `my_function` from the module be above the one from the module type. diff --git a/test/cram_ancient/cli_small.t/main.mli b/test/cram_ancient/cli_small.t/main.mli new file mode 100644 index 0000000000..9e1d7609a7 --- /dev/null +++ b/test/cram_ancient/cli_small.t/main.mli @@ -0,0 +1,18 @@ + +type 'a list + +module List : sig + type 'a t = 'a list + + val map : ('a -> 'b) -> 'a t -> 'b t + + val empty : 'a t * 'b t + + +end + +type ('a, 'b) result + +val ok: 'a -> ('a, 'b) result + +val ok_zero : (int, 'a) result \ No newline at end of file diff --git a/test/cram_ancient/cli_small.t/run.t b/test/cram_ancient/cli_small.t/run.t new file mode 100644 index 0000000000..b8545e0ed3 --- /dev/null +++ b/test/cram_ancient/cli_small.t/run.t @@ -0,0 +1,17 @@ + $ ocamlc -c main.mli -bin-annot -I . + $ odoc compile -I . main.cmti + $ odoc link -I . main.odoc + $ cat $(find . -name '*.odocl') > megaodocl + $ du -sh megaodocl + 4.0K megaodocl + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=ancient + $ sherlodoc index $(find . -name '*.odocl') + $ sherlodoc search --print-cost "list" + 89 type 'a Main.list + 101 type 'a Main.List.t = 'a list + 104 mod Main.List + 209 val Main.List.empty : 'a t * 'b t + 222 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + $ sherlodoc search ": (int, 'a) result" + val Main.ok_zero : (int, 'a) result From 20c479faeab249a817a236292f22369b0ed43c74 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 31 Jan 2024 14:07:40 +0100 Subject: [PATCH 257/285] attempt at testing sherlodoc.js size in ci compatible way --- test/cram/base_web.t | 2 -- test/cram/simple.t/run.t | 4 +--- test/cram/size_bound.t | 12 ++++++++++++ test/cram_static/dune | 5 +++++ test/cram_static/js_static_size.t | 3 +++ 5 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 test/cram/size_bound.t create mode 100644 test/cram_static/dune create mode 100644 test/cram_static/js_static_size.t diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 1dcb34d62c..6fe002c9a5 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -171,8 +171,6 @@ in queryable way, so a size increase is expected. It should just be reasonable. The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js - $ du -sh html/sherlodoc.js - 92K html/sherlodoc.js $ ls html base db.js diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index ce7480a783..1d43a552b9 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -9,9 +9,7 @@ $ sherlodoc index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null Here cat is used to remove weird permissions on executable built by dune - $ cat ../../../jsoo/main.bc.js > sherlodoc.js - $ du -sh sherlodoc.js - 100K sherlodoc.js + $ sherlodoc js sherlodoc.js $ mkdir html $ cp sherlodoc.js html $ cp db.js html diff --git a/test/cram/size_bound.t b/test/cram/size_bound.t new file mode 100644 index 0000000000..0b97dbdaf3 --- /dev/null +++ b/test/cram/size_bound.t @@ -0,0 +1,12 @@ +This tests the sherlodoc.js is not bigger than 120000 bytes. We test a threshold +of the size because the precise size depends on specific ocaml and dependencies +versions. This test should pass on every version. If it fails, we can either +update the threshold to be a larg enough or forbid certain dependency versions +in the opam file. + $ sherlodoc js sherlodoc.js + $ if [ "$(stat --printf="%s" sherlodoc.js)" -gt 120000 ]; then + > stat --printf="%s" sherlodoc.js + > else + > echo "All good! "; + > fi + All good! diff --git a/test/cram_static/dune b/test/cram_static/dune new file mode 100644 index 0000000000..a0af1ab3c0 --- /dev/null +++ b/test/cram_static/dune @@ -0,0 +1,5 @@ +(cram + (enabled_if + (and + (= %{version:brr} 0.0.6) (= %{ocaml_version} 4.14.1))) + (deps %{bin:odoc} %{bin:sherlodoc})) diff --git a/test/cram_static/js_static_size.t b/test/cram_static/js_static_size.t new file mode 100644 index 0000000000..900e52c3d2 --- /dev/null +++ b/test/cram_static/js_static_size.t @@ -0,0 +1,3 @@ + $ sherlodoc js sherlodoc.js + $ du -sh sherlodoc.js + 100K sherlodoc.js From 3a35e1ae721c2d931a361f66078d0051d09e4201 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 31 Jan 2024 14:18:17 +0100 Subject: [PATCH 258/285] tighten static test enabling --- test/cram_static/dune | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/cram_static/dune b/test/cram_static/dune index a0af1ab3c0..78ce40bca1 100644 --- a/test/cram_static/dune +++ b/test/cram_static/dune @@ -1,5 +1,7 @@ (cram (enabled_if (and - (= %{version:brr} 0.0.6) (= %{ocaml_version} 4.14.1))) + (= %{version:brr} 0.0.6) + (= %{version:menhirLib} 20230608) + (= %{ocaml_version} 4.14.1))) (deps %{bin:odoc} %{bin:sherlodoc})) From 957f20d64862c24f7345c02ad66d5dd725d0da14 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 31 Jan 2024 14:51:54 +0100 Subject: [PATCH 259/285] remove unreliable test --- test/cram/base_web.t | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 6fe002c9a5..a37b953295 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -153,15 +153,9 @@ dependencies so we do not display error (one was encountered with yojson) $ gzip -k db.js -We want to compare the compressed size with the size of the odocl. The search -database contains information than the odocl, but the information is organised -in queryable way, so a size increase is expected. It should just be reasonable. - $ gzip -k megaodocl - $ du -s *.js *.gz 2108 db.js 1592 db.js.gz - 1776 megaodocl.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f From 65d37611133fe66b06444f3ae0f10524ff84fa1c Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 31 Jan 2024 15:21:07 +0100 Subject: [PATCH 260/285] fix jsoo version in static size test --- test/cram_static/dune | 1 + test/cram_static/js_static_size.t | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/cram_static/dune b/test/cram_static/dune index 78ce40bca1..be6047703b 100644 --- a/test/cram_static/dune +++ b/test/cram_static/dune @@ -3,5 +3,6 @@ (and (= %{version:brr} 0.0.6) (= %{version:menhirLib} 20230608) + (= %{version:js_of_ocaml} 5.6.0) (= %{ocaml_version} 4.14.1))) (deps %{bin:odoc} %{bin:sherlodoc})) diff --git a/test/cram_static/js_static_size.t b/test/cram_static/js_static_size.t index 900e52c3d2..966d3f18fe 100644 --- a/test/cram_static/js_static_size.t +++ b/test/cram_static/js_static_size.t @@ -1,3 +1,3 @@ $ sherlodoc js sherlodoc.js $ du -sh sherlodoc.js - 100K sherlodoc.js + 92K sherlodoc.js From 3570369819e6527434a22446b3299feea17ad511 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 31 Jan 2024 15:37:56 +0100 Subject: [PATCH 261/285] base web test is now static --- test/cram/base_web.t | 182 ------------------------------------ test/cram_static/base_web.t | 39 ++++++++ 2 files changed, 39 insertions(+), 182 deletions(-) delete mode 100644 test/cram/base_web.t create mode 100644 test/cram_static/base_web.t diff --git a/test/cram/base_web.t b/test/cram/base_web.t deleted file mode 100644 index a37b953295..0000000000 --- a/test/cram/base_web.t +++ /dev/null @@ -1,182 +0,0 @@ - $ mkdir docs -Generating odocls for base with odig. This might give an error on some -dependencies so we do not display error (one was encountered with yojson) - $ odig odoc --cache-dir=docs base 2> /dev/null - Updating documentation, this may take some time... - $ find ./docs/odoc/base/ -name '*.odocl' | sort - ./docs/odoc/base/base.odocl - ./docs/odoc/base/base__.odocl - ./docs/odoc/base/base__Applicative.odocl - ./docs/odoc/base/base__Applicative_intf.odocl - ./docs/odoc/base/base__Array.odocl - ./docs/odoc/base/base__Array0.odocl - ./docs/odoc/base/base__Array_permute.odocl - ./docs/odoc/base/base__Avltree.odocl - ./docs/odoc/base/base__Backtrace.odocl - ./docs/odoc/base/base__Binary_search.odocl - ./docs/odoc/base/base__Binary_searchable.odocl - ./docs/odoc/base/base__Binary_searchable_intf.odocl - ./docs/odoc/base/base__Blit.odocl - ./docs/odoc/base/base__Blit_intf.odocl - ./docs/odoc/base/base__Bool.odocl - ./docs/odoc/base/base__Bool0.odocl - ./docs/odoc/base/base__Buffer.odocl - ./docs/odoc/base/base__Buffer_intf.odocl - ./docs/odoc/base/base__Bytes.odocl - ./docs/odoc/base/base__Bytes0.odocl - ./docs/odoc/base/base__Bytes_tr.odocl - ./docs/odoc/base/base__Char.odocl - ./docs/odoc/base/base__Char0.odocl - ./docs/odoc/base/base__Comparable.odocl - ./docs/odoc/base/base__Comparable_intf.odocl - ./docs/odoc/base/base__Comparator.odocl - ./docs/odoc/base/base__Comparisons.odocl - ./docs/odoc/base/base__Container.odocl - ./docs/odoc/base/base__Container_intf.odocl - ./docs/odoc/base/base__Either.odocl - ./docs/odoc/base/base__Either0.odocl - ./docs/odoc/base/base__Either_intf.odocl - ./docs/odoc/base/base__Equal.odocl - ./docs/odoc/base/base__Error.odocl - ./docs/odoc/base/base__Exn.odocl - ./docs/odoc/base/base__Field.odocl - ./docs/odoc/base/base__Fieldslib.odocl - ./docs/odoc/base/base__Float.odocl - ./docs/odoc/base/base__Float0.odocl - ./docs/odoc/base/base__Floatable.odocl - ./docs/odoc/base/base__Fn.odocl - ./docs/odoc/base/base__Formatter.odocl - ./docs/odoc/base/base__Globalize.odocl - ./docs/odoc/base/base__Hash.odocl - ./docs/odoc/base/base__Hash_intf.odocl - ./docs/odoc/base/base__Hash_set.odocl - ./docs/odoc/base/base__Hash_set_intf.odocl - ./docs/odoc/base/base__Hashable.odocl - ./docs/odoc/base/base__Hashable_intf.odocl - ./docs/odoc/base/base__Hasher.odocl - ./docs/odoc/base/base__Hashtbl.odocl - ./docs/odoc/base/base__Hashtbl_intf.odocl - ./docs/odoc/base/base__Hex_lexer.odocl - ./docs/odoc/base/base__Identifiable.odocl - ./docs/odoc/base/base__Identifiable_intf.odocl - ./docs/odoc/base/base__Import.odocl - ./docs/odoc/base/base__Import0.odocl - ./docs/odoc/base/base__Indexed_container.odocl - ./docs/odoc/base/base__Indexed_container_intf.odocl - ./docs/odoc/base/base__Info.odocl - ./docs/odoc/base/base__Info_intf.odocl - ./docs/odoc/base/base__Int.odocl - ./docs/odoc/base/base__Int0.odocl - ./docs/odoc/base/base__Int32.odocl - ./docs/odoc/base/base__Int63.odocl - ./docs/odoc/base/base__Int63_emul.odocl - ./docs/odoc/base/base__Int64.odocl - ./docs/odoc/base/base__Int_conversions.odocl - ./docs/odoc/base/base__Int_intf.odocl - ./docs/odoc/base/base__Int_math.odocl - ./docs/odoc/base/base__Intable.odocl - ./docs/odoc/base/base__Invariant.odocl - ./docs/odoc/base/base__Invariant_intf.odocl - ./docs/odoc/base/base__Lazy.odocl - ./docs/odoc/base/base__Linked_queue.odocl - ./docs/odoc/base/base__Linked_queue0.odocl - ./docs/odoc/base/base__List.odocl - ./docs/odoc/base/base__List0.odocl - ./docs/odoc/base/base__List1.odocl - ./docs/odoc/base/base__Map.odocl - ./docs/odoc/base/base__Map_intf.odocl - ./docs/odoc/base/base__Maybe_bound.odocl - ./docs/odoc/base/base__Monad.odocl - ./docs/odoc/base/base__Monad_intf.odocl - ./docs/odoc/base/base__Nativeint.odocl - ./docs/odoc/base/base__Nothing.odocl - ./docs/odoc/base/base__Obj_array.odocl - ./docs/odoc/base/base__Obj_local.odocl - ./docs/odoc/base/base__Option.odocl - ./docs/odoc/base/base__Option_array.odocl - ./docs/odoc/base/base__Or_error.odocl - ./docs/odoc/base/base__Ordered_collection_common.odocl - ./docs/odoc/base/base__Ordered_collection_common0.odocl - ./docs/odoc/base/base__Ordering.odocl - ./docs/odoc/base/base__Poly0.odocl - ./docs/odoc/base/base__Popcount.odocl - ./docs/odoc/base/base__Pow_overflow_bounds.odocl - ./docs/odoc/base/base__Ppx_compare_lib.odocl - ./docs/odoc/base/base__Ppx_enumerate_lib.odocl - ./docs/odoc/base/base__Ppx_hash_lib.odocl - ./docs/odoc/base/base__Pretty_printer.odocl - ./docs/odoc/base/base__Printf.odocl - ./docs/odoc/base/base__Queue.odocl - ./docs/odoc/base/base__Queue_intf.odocl - ./docs/odoc/base/base__Random.odocl - ./docs/odoc/base/base__Random_repr.odocl - ./docs/odoc/base/base__Ref.odocl - ./docs/odoc/base/base__Result.odocl - ./docs/odoc/base/base__Sequence.odocl - ./docs/odoc/base/base__Set.odocl - ./docs/odoc/base/base__Set_intf.odocl - ./docs/odoc/base/base__Sexp.odocl - ./docs/odoc/base/base__Sexp_with_comparable.odocl - ./docs/odoc/base/base__Sexpable.odocl - ./docs/odoc/base/base__Sign.odocl - ./docs/odoc/base/base__Sign0.odocl - ./docs/odoc/base/base__Sign_or_nan.odocl - ./docs/odoc/base/base__Source_code_position.odocl - ./docs/odoc/base/base__Source_code_position0.odocl - ./docs/odoc/base/base__Stack.odocl - ./docs/odoc/base/base__Stack_intf.odocl - ./docs/odoc/base/base__Staged.odocl - ./docs/odoc/base/base__String.odocl - ./docs/odoc/base/base__String0.odocl - ./docs/odoc/base/base__Stringable.odocl - ./docs/odoc/base/base__Sys.odocl - ./docs/odoc/base/base__Sys0.odocl - ./docs/odoc/base/base__T.odocl - ./docs/odoc/base/base__Type_equal.odocl - ./docs/odoc/base/base__Uchar.odocl - ./docs/odoc/base/base__Uchar0.odocl - ./docs/odoc/base/base__Uniform_array.odocl - ./docs/odoc/base/base__Unit.odocl - ./docs/odoc/base/base__Variant.odocl - ./docs/odoc/base/base__Variantslib.odocl - ./docs/odoc/base/base__With_return.odocl - ./docs/odoc/base/base__Word_size.odocl - ./docs/odoc/base/base_internalhash_types/base_internalhash_types.odocl - ./docs/odoc/base/caml/caml.odocl - ./docs/odoc/base/md5/md5_lib.odocl - ./docs/odoc/base/page-index.odocl - ./docs/odoc/base/shadow_stdlib/shadow_stdlib.odocl - $ cat $(find ./docs/odoc/base/ -name '*.odocl') > megaodocl - $ du -sh megaodocl - 6.2M megaodocl - $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $(find ./docs/odoc/base/ -name '*.odocl') > /dev/null - - $ gzip -k db.js - - $ du -s *.js *.gz - 2108 db.js - 1592 db.js.gz - - $ for f in $(find . -name '*.odocl'); do - > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f - > done - $ odoc support-files -o html - $ cp db.js html/ -The --no-preserve flag is here so that copying to /tmp will not fail because of -a previous run. .js files built by dune are read only. - $ cp --no-preserve=mode,ownership ../../jsoo/main.bc.js html/sherlodoc.js - $ ls html - base - db.js - fonts - highlight.pack.js - katex.min.css - katex.min.js - ocaml - odoc.css - odoc_search.js - sexplib0 - sherlodoc.js -indent to see results -$ cp -r html /tmp -$ firefox /tmp/html/base/index.html diff --git a/test/cram_static/base_web.t b/test/cram_static/base_web.t new file mode 100644 index 0000000000..dc3c1dcbe3 --- /dev/null +++ b/test/cram_static/base_web.t @@ -0,0 +1,39 @@ + $ mkdir docs +Generating odocls for base with odig. This might give an error on some +dependencies so we do not display error (one was encountered with yojson) + $ odig odoc --cache-dir=docs base 2> /dev/null + Updating documentation, this may take some time... + $ cat $(find ./docs/odoc/base/ -name '*.odocl') > megaodocl + $ du -sh megaodocl + 6.2M megaodocl + $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $(find ./docs/odoc/base/ -name '*.odocl') > /dev/null + + $ gzip -k db.js + + $ du -s *.js *.gz + 2108 db.js + 1592 db.js.gz + + $ for f in $(find . -name '*.odocl'); do + > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f + > done + $ odoc support-files -o html + $ cp db.js html/ +The --no-preserve flag is here so that copying to /tmp will not fail because of +a previous run. .js files built by dune are read only. + $ sherlodoc js html/sherlodoc.js + $ ls html + base + db.js + fonts + highlight.pack.js + katex.min.css + katex.min.js + ocaml + odoc.css + odoc_search.js + sexplib0 + sherlodoc.js +indent to see results +$ cp -r html /tmp +$ firefox /tmp/html/base/index.html From 46b2ab0a435f01d3142ae8a7965a80ae377008e6 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 31 Jan 2024 15:52:15 +0100 Subject: [PATCH 262/285] sort ls output in cram test --- test/cram/simple.t/run.t | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 1d43a552b9..22c3459a1d 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -14,15 +14,15 @@ Here cat is used to remove weird permissions on executable built by dune $ cp sherlodoc.js html $ cp db.js html $ odoc support-files -o html - $ for f in $(find . -name '*.odocl'); do + $ for f in $(find . -name '*.odocl' | sort); do > echo $f ; > cd html ; > odoc html-generate --search-uri db.js --search-uri sherlodoc.js --output-dir . ../$f ; > cd .. > done - ./page-page.odocl ./main.odocl - $ ls + ./page-page.odocl + $ ls | sort db.js html main.cmi @@ -36,7 +36,7 @@ Here cat is used to remove weird permissions on executable built by dune page-page.odocl page.mld sherlodoc.js - $ ls html + $ ls html | sort db.js fonts highlight.pack.js @@ -46,7 +46,7 @@ Here cat is used to remove weird permissions on executable built by dune odoc_search.js page sherlodoc.js - $ ls html/page + $ ls html/page | sort Main index.html $ find . -name "*.html" -type f | sort From 17fb1077bc8fcb7dbf188ca786f8120dd8a08b38 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 31 Jan 2024 16:16:01 +0100 Subject: [PATCH 263/285] remove odocl size from cli tests --- test/cram/cli.t/run.t | 3 --- test/cram/cli_small.t/run.t | 3 --- 2 files changed, 6 deletions(-) diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index bae3d9cb60..da3c8707df 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -3,9 +3,6 @@ $ odoc compile -I . page.mld $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc - $ cat $(find . -name '*.odocl') > megaodocl - $ du -sh megaodocl - 8.0K megaodocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal $ sherlodoc index $(find . -name '*.odocl') diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 515b28e453..22a28216c8 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -1,9 +1,6 @@ $ ocamlc -c main.mli -bin-annot -I . $ odoc compile -I . main.cmti $ odoc link -I . main.odoc - $ cat $(find . -name '*.odocl') > megaodocl - $ du -sh megaodocl - 4.0K megaodocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal $ sherlodoc index $(find . -name '*.odocl') From aef5b5c4256fc2df7eda14b734f93654874b0694 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 31 Jan 2024 17:24:34 +0100 Subject: [PATCH 264/285] Fast tests on base (#7) * make test on base faster by making the slowest part cachable by dune * do not call odig inside cram tests : this is important because odig can have issues --------- Co-authored-by: Emile Trotignon --- dune-project | 2 + test/cram/base_benchmark.t | 159 ---------------- test/cram/base_cli.t | 151 +-------------- test/cram/base_odocls.t | 151 +++++++++++++++ test/cram/dune | 6 +- test/cram/multi_package.t | 369 ++++++++++++++++++++++++++++++++++++ test/cram_static/base_web.t | 17 +- test/cram_static/dune | 2 +- test/dune | 7 + 9 files changed, 540 insertions(+), 324 deletions(-) delete mode 100644 test/cram/base_benchmark.t create mode 100644 test/cram/base_odocls.t create mode 100644 test/cram/multi_package.t create mode 100644 test/dune diff --git a/dune-project b/dune-project index fd2418afd4..5acfe35684 100644 --- a/dune-project +++ b/dune-project @@ -16,6 +16,8 @@ (license MIT) +(using directory-targets 0.1) + (package (name sherlodoc) (synopsis "Search engine for OCaml documentation") diff --git a/test/cram/base_benchmark.t b/test/cram/base_benchmark.t deleted file mode 100644 index a8639b2496..0000000000 --- a/test/cram/base_benchmark.t +++ /dev/null @@ -1,159 +0,0 @@ -This test will fail, it is not deterministic. Please just check that the values -are not crazy and discard the changes - $ mkdir docs -Generating odocls for base with odig. This might give an error on some -dependencies so we do not display error (one was encountered with yojson) - $ odig odoc --cache-dir=docs base 2> /dev/null - Updating documentation, this may take some time... - $ find ./docs/odoc/base/ -name '*.odocl' | sort - ./docs/odoc/base/base.odocl - ./docs/odoc/base/base__.odocl - ./docs/odoc/base/base__Applicative.odocl - ./docs/odoc/base/base__Applicative_intf.odocl - ./docs/odoc/base/base__Array.odocl - ./docs/odoc/base/base__Array0.odocl - ./docs/odoc/base/base__Array_permute.odocl - ./docs/odoc/base/base__Avltree.odocl - ./docs/odoc/base/base__Backtrace.odocl - ./docs/odoc/base/base__Binary_search.odocl - ./docs/odoc/base/base__Binary_searchable.odocl - ./docs/odoc/base/base__Binary_searchable_intf.odocl - ./docs/odoc/base/base__Blit.odocl - ./docs/odoc/base/base__Blit_intf.odocl - ./docs/odoc/base/base__Bool.odocl - ./docs/odoc/base/base__Bool0.odocl - ./docs/odoc/base/base__Buffer.odocl - ./docs/odoc/base/base__Buffer_intf.odocl - ./docs/odoc/base/base__Bytes.odocl - ./docs/odoc/base/base__Bytes0.odocl - ./docs/odoc/base/base__Bytes_tr.odocl - ./docs/odoc/base/base__Char.odocl - ./docs/odoc/base/base__Char0.odocl - ./docs/odoc/base/base__Comparable.odocl - ./docs/odoc/base/base__Comparable_intf.odocl - ./docs/odoc/base/base__Comparator.odocl - ./docs/odoc/base/base__Comparisons.odocl - ./docs/odoc/base/base__Container.odocl - ./docs/odoc/base/base__Container_intf.odocl - ./docs/odoc/base/base__Either.odocl - ./docs/odoc/base/base__Either0.odocl - ./docs/odoc/base/base__Either_intf.odocl - ./docs/odoc/base/base__Equal.odocl - ./docs/odoc/base/base__Error.odocl - ./docs/odoc/base/base__Exn.odocl - ./docs/odoc/base/base__Field.odocl - ./docs/odoc/base/base__Fieldslib.odocl - ./docs/odoc/base/base__Float.odocl - ./docs/odoc/base/base__Float0.odocl - ./docs/odoc/base/base__Floatable.odocl - ./docs/odoc/base/base__Fn.odocl - ./docs/odoc/base/base__Formatter.odocl - ./docs/odoc/base/base__Globalize.odocl - ./docs/odoc/base/base__Hash.odocl - ./docs/odoc/base/base__Hash_intf.odocl - ./docs/odoc/base/base__Hash_set.odocl - ./docs/odoc/base/base__Hash_set_intf.odocl - ./docs/odoc/base/base__Hashable.odocl - ./docs/odoc/base/base__Hashable_intf.odocl - ./docs/odoc/base/base__Hasher.odocl - ./docs/odoc/base/base__Hashtbl.odocl - ./docs/odoc/base/base__Hashtbl_intf.odocl - ./docs/odoc/base/base__Hex_lexer.odocl - ./docs/odoc/base/base__Identifiable.odocl - ./docs/odoc/base/base__Identifiable_intf.odocl - ./docs/odoc/base/base__Import.odocl - ./docs/odoc/base/base__Import0.odocl - ./docs/odoc/base/base__Indexed_container.odocl - ./docs/odoc/base/base__Indexed_container_intf.odocl - ./docs/odoc/base/base__Info.odocl - ./docs/odoc/base/base__Info_intf.odocl - ./docs/odoc/base/base__Int.odocl - ./docs/odoc/base/base__Int0.odocl - ./docs/odoc/base/base__Int32.odocl - ./docs/odoc/base/base__Int63.odocl - ./docs/odoc/base/base__Int63_emul.odocl - ./docs/odoc/base/base__Int64.odocl - ./docs/odoc/base/base__Int_conversions.odocl - ./docs/odoc/base/base__Int_intf.odocl - ./docs/odoc/base/base__Int_math.odocl - ./docs/odoc/base/base__Intable.odocl - ./docs/odoc/base/base__Invariant.odocl - ./docs/odoc/base/base__Invariant_intf.odocl - ./docs/odoc/base/base__Lazy.odocl - ./docs/odoc/base/base__Linked_queue.odocl - ./docs/odoc/base/base__Linked_queue0.odocl - ./docs/odoc/base/base__List.odocl - ./docs/odoc/base/base__List0.odocl - ./docs/odoc/base/base__List1.odocl - ./docs/odoc/base/base__Map.odocl - ./docs/odoc/base/base__Map_intf.odocl - ./docs/odoc/base/base__Maybe_bound.odocl - ./docs/odoc/base/base__Monad.odocl - ./docs/odoc/base/base__Monad_intf.odocl - ./docs/odoc/base/base__Nativeint.odocl - ./docs/odoc/base/base__Nothing.odocl - ./docs/odoc/base/base__Obj_array.odocl - ./docs/odoc/base/base__Obj_local.odocl - ./docs/odoc/base/base__Option.odocl - ./docs/odoc/base/base__Option_array.odocl - ./docs/odoc/base/base__Or_error.odocl - ./docs/odoc/base/base__Ordered_collection_common.odocl - ./docs/odoc/base/base__Ordered_collection_common0.odocl - ./docs/odoc/base/base__Ordering.odocl - ./docs/odoc/base/base__Poly0.odocl - ./docs/odoc/base/base__Popcount.odocl - ./docs/odoc/base/base__Pow_overflow_bounds.odocl - ./docs/odoc/base/base__Ppx_compare_lib.odocl - ./docs/odoc/base/base__Ppx_enumerate_lib.odocl - ./docs/odoc/base/base__Ppx_hash_lib.odocl - ./docs/odoc/base/base__Pretty_printer.odocl - ./docs/odoc/base/base__Printf.odocl - ./docs/odoc/base/base__Queue.odocl - ./docs/odoc/base/base__Queue_intf.odocl - ./docs/odoc/base/base__Random.odocl - ./docs/odoc/base/base__Random_repr.odocl - ./docs/odoc/base/base__Ref.odocl - ./docs/odoc/base/base__Result.odocl - ./docs/odoc/base/base__Sequence.odocl - ./docs/odoc/base/base__Set.odocl - ./docs/odoc/base/base__Set_intf.odocl - ./docs/odoc/base/base__Sexp.odocl - ./docs/odoc/base/base__Sexp_with_comparable.odocl - ./docs/odoc/base/base__Sexpable.odocl - ./docs/odoc/base/base__Sign.odocl - ./docs/odoc/base/base__Sign0.odocl - ./docs/odoc/base/base__Sign_or_nan.odocl - ./docs/odoc/base/base__Source_code_position.odocl - ./docs/odoc/base/base__Source_code_position0.odocl - ./docs/odoc/base/base__Stack.odocl - ./docs/odoc/base/base__Stack_intf.odocl - ./docs/odoc/base/base__Staged.odocl - ./docs/odoc/base/base__String.odocl - ./docs/odoc/base/base__String0.odocl - ./docs/odoc/base/base__Stringable.odocl - ./docs/odoc/base/base__Sys.odocl - ./docs/odoc/base/base__Sys0.odocl - ./docs/odoc/base/base__T.odocl - ./docs/odoc/base/base__Type_equal.odocl - ./docs/odoc/base/base__Uchar.odocl - ./docs/odoc/base/base__Uchar0.odocl - ./docs/odoc/base/base__Uniform_array.odocl - ./docs/odoc/base/base__Unit.odocl - ./docs/odoc/base/base__Variant.odocl - ./docs/odoc/base/base__Variantslib.odocl - ./docs/odoc/base/base__With_return.odocl - ./docs/odoc/base/base__Word_size.odocl - ./docs/odoc/base/base_internalhash_types/base_internalhash_types.odocl - ./docs/odoc/base/caml/caml.odocl - ./docs/odoc/base/md5/md5_lib.odocl - ./docs/odoc/base/page-index.odocl - ./docs/odoc/base/shadow_stdlib/shadow_stdlib.odocl - $ sherlodoc index --format=js --db=db.js $(find ./docs/odoc/base/ -name '*.odocl') > /dev/null - - - - - - - - diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 17a3aa5e53..43340a6979 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -1,154 +1,7 @@ - $ mkdir docs -Generating odocls for base with odig. This might give an error on some -dependencies so we do not display error (one was encountered with yojson) - $ odig odoc --cache-dir=docs base 2> /dev/null - Updating documentation, this may take some time... - $ find ./docs/odoc/base/ -name '*.odocl' | sort - ./docs/odoc/base/base.odocl - ./docs/odoc/base/base__.odocl - ./docs/odoc/base/base__Applicative.odocl - ./docs/odoc/base/base__Applicative_intf.odocl - ./docs/odoc/base/base__Array.odocl - ./docs/odoc/base/base__Array0.odocl - ./docs/odoc/base/base__Array_permute.odocl - ./docs/odoc/base/base__Avltree.odocl - ./docs/odoc/base/base__Backtrace.odocl - ./docs/odoc/base/base__Binary_search.odocl - ./docs/odoc/base/base__Binary_searchable.odocl - ./docs/odoc/base/base__Binary_searchable_intf.odocl - ./docs/odoc/base/base__Blit.odocl - ./docs/odoc/base/base__Blit_intf.odocl - ./docs/odoc/base/base__Bool.odocl - ./docs/odoc/base/base__Bool0.odocl - ./docs/odoc/base/base__Buffer.odocl - ./docs/odoc/base/base__Buffer_intf.odocl - ./docs/odoc/base/base__Bytes.odocl - ./docs/odoc/base/base__Bytes0.odocl - ./docs/odoc/base/base__Bytes_tr.odocl - ./docs/odoc/base/base__Char.odocl - ./docs/odoc/base/base__Char0.odocl - ./docs/odoc/base/base__Comparable.odocl - ./docs/odoc/base/base__Comparable_intf.odocl - ./docs/odoc/base/base__Comparator.odocl - ./docs/odoc/base/base__Comparisons.odocl - ./docs/odoc/base/base__Container.odocl - ./docs/odoc/base/base__Container_intf.odocl - ./docs/odoc/base/base__Either.odocl - ./docs/odoc/base/base__Either0.odocl - ./docs/odoc/base/base__Either_intf.odocl - ./docs/odoc/base/base__Equal.odocl - ./docs/odoc/base/base__Error.odocl - ./docs/odoc/base/base__Exn.odocl - ./docs/odoc/base/base__Field.odocl - ./docs/odoc/base/base__Fieldslib.odocl - ./docs/odoc/base/base__Float.odocl - ./docs/odoc/base/base__Float0.odocl - ./docs/odoc/base/base__Floatable.odocl - ./docs/odoc/base/base__Fn.odocl - ./docs/odoc/base/base__Formatter.odocl - ./docs/odoc/base/base__Globalize.odocl - ./docs/odoc/base/base__Hash.odocl - ./docs/odoc/base/base__Hash_intf.odocl - ./docs/odoc/base/base__Hash_set.odocl - ./docs/odoc/base/base__Hash_set_intf.odocl - ./docs/odoc/base/base__Hashable.odocl - ./docs/odoc/base/base__Hashable_intf.odocl - ./docs/odoc/base/base__Hasher.odocl - ./docs/odoc/base/base__Hashtbl.odocl - ./docs/odoc/base/base__Hashtbl_intf.odocl - ./docs/odoc/base/base__Hex_lexer.odocl - ./docs/odoc/base/base__Identifiable.odocl - ./docs/odoc/base/base__Identifiable_intf.odocl - ./docs/odoc/base/base__Import.odocl - ./docs/odoc/base/base__Import0.odocl - ./docs/odoc/base/base__Indexed_container.odocl - ./docs/odoc/base/base__Indexed_container_intf.odocl - ./docs/odoc/base/base__Info.odocl - ./docs/odoc/base/base__Info_intf.odocl - ./docs/odoc/base/base__Int.odocl - ./docs/odoc/base/base__Int0.odocl - ./docs/odoc/base/base__Int32.odocl - ./docs/odoc/base/base__Int63.odocl - ./docs/odoc/base/base__Int63_emul.odocl - ./docs/odoc/base/base__Int64.odocl - ./docs/odoc/base/base__Int_conversions.odocl - ./docs/odoc/base/base__Int_intf.odocl - ./docs/odoc/base/base__Int_math.odocl - ./docs/odoc/base/base__Intable.odocl - ./docs/odoc/base/base__Invariant.odocl - ./docs/odoc/base/base__Invariant_intf.odocl - ./docs/odoc/base/base__Lazy.odocl - ./docs/odoc/base/base__Linked_queue.odocl - ./docs/odoc/base/base__Linked_queue0.odocl - ./docs/odoc/base/base__List.odocl - ./docs/odoc/base/base__List0.odocl - ./docs/odoc/base/base__List1.odocl - ./docs/odoc/base/base__Map.odocl - ./docs/odoc/base/base__Map_intf.odocl - ./docs/odoc/base/base__Maybe_bound.odocl - ./docs/odoc/base/base__Monad.odocl - ./docs/odoc/base/base__Monad_intf.odocl - ./docs/odoc/base/base__Nativeint.odocl - ./docs/odoc/base/base__Nothing.odocl - ./docs/odoc/base/base__Obj_array.odocl - ./docs/odoc/base/base__Obj_local.odocl - ./docs/odoc/base/base__Option.odocl - ./docs/odoc/base/base__Option_array.odocl - ./docs/odoc/base/base__Or_error.odocl - ./docs/odoc/base/base__Ordered_collection_common.odocl - ./docs/odoc/base/base__Ordered_collection_common0.odocl - ./docs/odoc/base/base__Ordering.odocl - ./docs/odoc/base/base__Poly0.odocl - ./docs/odoc/base/base__Popcount.odocl - ./docs/odoc/base/base__Pow_overflow_bounds.odocl - ./docs/odoc/base/base__Ppx_compare_lib.odocl - ./docs/odoc/base/base__Ppx_enumerate_lib.odocl - ./docs/odoc/base/base__Ppx_hash_lib.odocl - ./docs/odoc/base/base__Pretty_printer.odocl - ./docs/odoc/base/base__Printf.odocl - ./docs/odoc/base/base__Queue.odocl - ./docs/odoc/base/base__Queue_intf.odocl - ./docs/odoc/base/base__Random.odocl - ./docs/odoc/base/base__Random_repr.odocl - ./docs/odoc/base/base__Ref.odocl - ./docs/odoc/base/base__Result.odocl - ./docs/odoc/base/base__Sequence.odocl - ./docs/odoc/base/base__Set.odocl - ./docs/odoc/base/base__Set_intf.odocl - ./docs/odoc/base/base__Sexp.odocl - ./docs/odoc/base/base__Sexp_with_comparable.odocl - ./docs/odoc/base/base__Sexpable.odocl - ./docs/odoc/base/base__Sign.odocl - ./docs/odoc/base/base__Sign0.odocl - ./docs/odoc/base/base__Sign_or_nan.odocl - ./docs/odoc/base/base__Source_code_position.odocl - ./docs/odoc/base/base__Source_code_position0.odocl - ./docs/odoc/base/base__Stack.odocl - ./docs/odoc/base/base__Stack_intf.odocl - ./docs/odoc/base/base__Staged.odocl - ./docs/odoc/base/base__String.odocl - ./docs/odoc/base/base__String0.odocl - ./docs/odoc/base/base__Stringable.odocl - ./docs/odoc/base/base__Sys.odocl - ./docs/odoc/base/base__Sys0.odocl - ./docs/odoc/base/base__T.odocl - ./docs/odoc/base/base__Type_equal.odocl - ./docs/odoc/base/base__Uchar.odocl - ./docs/odoc/base/base__Uchar0.odocl - ./docs/odoc/base/base__Uniform_array.odocl - ./docs/odoc/base/base__Unit.odocl - ./docs/odoc/base/base__Variant.odocl - ./docs/odoc/base/base__Variantslib.odocl - ./docs/odoc/base/base__With_return.odocl - ./docs/odoc/base/base__Word_size.odocl - ./docs/odoc/base/base_internalhash_types/base_internalhash_types.odocl - ./docs/odoc/base/caml/caml.odocl - ./docs/odoc/base/md5/md5_lib.odocl - ./docs/odoc/base/page-index.odocl - ./docs/odoc/base/shadow_stdlib/shadow_stdlib.odocl + $ export ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal - $ sherlodoc index --index-docstring=false $(find ./docs/odoc/base/ -name "*.odocl") > /dev/null + $ sherlodoc index --index-docstring=false $ODOCLS > /dev/null $ sherlodoc search --print-cost --limit 100 "S_poly" 150 sig Base.Map.S_poly 150 sig Base.Set.S_poly diff --git a/test/cram/base_odocls.t b/test/cram/base_odocls.t new file mode 100644 index 0000000000..ac85358c90 --- /dev/null +++ b/test/cram/base_odocls.t @@ -0,0 +1,151 @@ + $ find ../docs/odoc/base/ -name '*.odocl' | sort + ../docs/odoc/base/base.odocl + ../docs/odoc/base/base__.odocl + ../docs/odoc/base/base__Applicative.odocl + ../docs/odoc/base/base__Applicative_intf.odocl + ../docs/odoc/base/base__Array.odocl + ../docs/odoc/base/base__Array0.odocl + ../docs/odoc/base/base__Array_permute.odocl + ../docs/odoc/base/base__Avltree.odocl + ../docs/odoc/base/base__Backtrace.odocl + ../docs/odoc/base/base__Binary_search.odocl + ../docs/odoc/base/base__Binary_searchable.odocl + ../docs/odoc/base/base__Binary_searchable_intf.odocl + ../docs/odoc/base/base__Blit.odocl + ../docs/odoc/base/base__Blit_intf.odocl + ../docs/odoc/base/base__Bool.odocl + ../docs/odoc/base/base__Bool0.odocl + ../docs/odoc/base/base__Buffer.odocl + ../docs/odoc/base/base__Buffer_intf.odocl + ../docs/odoc/base/base__Bytes.odocl + ../docs/odoc/base/base__Bytes0.odocl + ../docs/odoc/base/base__Bytes_tr.odocl + ../docs/odoc/base/base__Char.odocl + ../docs/odoc/base/base__Char0.odocl + ../docs/odoc/base/base__Comparable.odocl + ../docs/odoc/base/base__Comparable_intf.odocl + ../docs/odoc/base/base__Comparator.odocl + ../docs/odoc/base/base__Comparisons.odocl + ../docs/odoc/base/base__Container.odocl + ../docs/odoc/base/base__Container_intf.odocl + ../docs/odoc/base/base__Either.odocl + ../docs/odoc/base/base__Either0.odocl + ../docs/odoc/base/base__Either_intf.odocl + ../docs/odoc/base/base__Equal.odocl + ../docs/odoc/base/base__Error.odocl + ../docs/odoc/base/base__Exn.odocl + ../docs/odoc/base/base__Field.odocl + ../docs/odoc/base/base__Fieldslib.odocl + ../docs/odoc/base/base__Float.odocl + ../docs/odoc/base/base__Float0.odocl + ../docs/odoc/base/base__Floatable.odocl + ../docs/odoc/base/base__Fn.odocl + ../docs/odoc/base/base__Formatter.odocl + ../docs/odoc/base/base__Globalize.odocl + ../docs/odoc/base/base__Hash.odocl + ../docs/odoc/base/base__Hash_intf.odocl + ../docs/odoc/base/base__Hash_set.odocl + ../docs/odoc/base/base__Hash_set_intf.odocl + ../docs/odoc/base/base__Hashable.odocl + ../docs/odoc/base/base__Hashable_intf.odocl + ../docs/odoc/base/base__Hasher.odocl + ../docs/odoc/base/base__Hashtbl.odocl + ../docs/odoc/base/base__Hashtbl_intf.odocl + ../docs/odoc/base/base__Hex_lexer.odocl + ../docs/odoc/base/base__Identifiable.odocl + ../docs/odoc/base/base__Identifiable_intf.odocl + ../docs/odoc/base/base__Import.odocl + ../docs/odoc/base/base__Import0.odocl + ../docs/odoc/base/base__Indexed_container.odocl + ../docs/odoc/base/base__Indexed_container_intf.odocl + ../docs/odoc/base/base__Info.odocl + ../docs/odoc/base/base__Info_intf.odocl + ../docs/odoc/base/base__Int.odocl + ../docs/odoc/base/base__Int0.odocl + ../docs/odoc/base/base__Int32.odocl + ../docs/odoc/base/base__Int63.odocl + ../docs/odoc/base/base__Int63_emul.odocl + ../docs/odoc/base/base__Int64.odocl + ../docs/odoc/base/base__Int_conversions.odocl + ../docs/odoc/base/base__Int_intf.odocl + ../docs/odoc/base/base__Int_math.odocl + ../docs/odoc/base/base__Intable.odocl + ../docs/odoc/base/base__Invariant.odocl + ../docs/odoc/base/base__Invariant_intf.odocl + ../docs/odoc/base/base__Lazy.odocl + ../docs/odoc/base/base__Linked_queue.odocl + ../docs/odoc/base/base__Linked_queue0.odocl + ../docs/odoc/base/base__List.odocl + ../docs/odoc/base/base__List0.odocl + ../docs/odoc/base/base__List1.odocl + ../docs/odoc/base/base__Map.odocl + ../docs/odoc/base/base__Map_intf.odocl + ../docs/odoc/base/base__Maybe_bound.odocl + ../docs/odoc/base/base__Monad.odocl + ../docs/odoc/base/base__Monad_intf.odocl + ../docs/odoc/base/base__Nativeint.odocl + ../docs/odoc/base/base__Nothing.odocl + ../docs/odoc/base/base__Obj_array.odocl + ../docs/odoc/base/base__Obj_local.odocl + ../docs/odoc/base/base__Option.odocl + ../docs/odoc/base/base__Option_array.odocl + ../docs/odoc/base/base__Or_error.odocl + ../docs/odoc/base/base__Ordered_collection_common.odocl + ../docs/odoc/base/base__Ordered_collection_common0.odocl + ../docs/odoc/base/base__Ordering.odocl + ../docs/odoc/base/base__Poly0.odocl + ../docs/odoc/base/base__Popcount.odocl + ../docs/odoc/base/base__Pow_overflow_bounds.odocl + ../docs/odoc/base/base__Ppx_compare_lib.odocl + ../docs/odoc/base/base__Ppx_enumerate_lib.odocl + ../docs/odoc/base/base__Ppx_hash_lib.odocl + ../docs/odoc/base/base__Pretty_printer.odocl + ../docs/odoc/base/base__Printf.odocl + ../docs/odoc/base/base__Queue.odocl + ../docs/odoc/base/base__Queue_intf.odocl + ../docs/odoc/base/base__Random.odocl + ../docs/odoc/base/base__Random_repr.odocl + ../docs/odoc/base/base__Ref.odocl + ../docs/odoc/base/base__Result.odocl + ../docs/odoc/base/base__Sequence.odocl + ../docs/odoc/base/base__Set.odocl + ../docs/odoc/base/base__Set_intf.odocl + ../docs/odoc/base/base__Sexp.odocl + ../docs/odoc/base/base__Sexp_with_comparable.odocl + ../docs/odoc/base/base__Sexpable.odocl + ../docs/odoc/base/base__Sign.odocl + ../docs/odoc/base/base__Sign0.odocl + ../docs/odoc/base/base__Sign_or_nan.odocl + ../docs/odoc/base/base__Source_code_position.odocl + ../docs/odoc/base/base__Source_code_position0.odocl + ../docs/odoc/base/base__Stack.odocl + ../docs/odoc/base/base__Stack_intf.odocl + ../docs/odoc/base/base__Staged.odocl + ../docs/odoc/base/base__String.odocl + ../docs/odoc/base/base__String0.odocl + ../docs/odoc/base/base__Stringable.odocl + ../docs/odoc/base/base__Sys.odocl + ../docs/odoc/base/base__Sys0.odocl + ../docs/odoc/base/base__T.odocl + ../docs/odoc/base/base__Type_equal.odocl + ../docs/odoc/base/base__Uchar.odocl + ../docs/odoc/base/base__Uchar0.odocl + ../docs/odoc/base/base__Uniform_array.odocl + ../docs/odoc/base/base__Unit.odocl + ../docs/odoc/base/base__Variant.odocl + ../docs/odoc/base/base__Variantslib.odocl + ../docs/odoc/base/base__With_return.odocl + ../docs/odoc/base/base__Word_size.odocl + ../docs/odoc/base/base_internalhash_types/base_internalhash_types.odocl + ../docs/odoc/base/caml/caml.odocl + ../docs/odoc/base/md5/md5_lib.odocl + ../docs/odoc/base/page-index.odocl + ../docs/odoc/base/shadow_stdlib/shadow_stdlib.odocl + + + + + + + + diff --git a/test/cram/dune b/test/cram/dune index af6aba9786..958bfaa70a 100644 --- a/test/cram/dune +++ b/test/cram/dune @@ -1,6 +1,2 @@ (cram - (deps - (source_tree base_odocls) - %{bin:odoc} - %{bin:sherlodoc} - ../../jsoo/main.bc.js)) + (deps ../docs %{bin:odoc} %{bin:sherlodoc})) diff --git a/test/cram/multi_package.t b/test/cram/multi_package.t new file mode 100644 index 0000000000..4e99ec53d3 --- /dev/null +++ b/test/cram/multi_package.t @@ -0,0 +1,369 @@ + $ export ODOCLS=$(find ../docs/odoc/ -name '*.odocl' | sort) + $ echo $ODOCLS | wc -w + 557 + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=marshal + $ sherlodoc index --index-docstring=false $ODOCLS > /dev/null + $ sherlodoc search --print-cost --limit 100 "S_poly" + 150 sig Base.Map.S_poly + 150 sig Base.Set.S_poly + 154 sig Base.Hashtbl.S_poly + 198 type 'a Base.Hashtbl.S_poly.key = 'a + 207 type ('a, 'b) Base.Map.S_poly.t + 207 type 'elt Base.Set.S_poly.t + 209 type ('a, 'cmp) Base.Set.S_poly.set + 210 val Base.Set.S_poly.mem : 'a t -> 'a -> bool + 210 type ('a, 'b) Base.Map.S_poly.tree + 210 type 'elt Base.Set.S_poly.tree + 211 type ('a, 'b) Base.Hashtbl.S_poly.t + 211 mod Base.Set.S_poly.Named + 217 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list + 221 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + 224 type Base.Map.S_poly.comparator_witness + 224 type Base.Set.S_poly.comparator_witness + 227 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t + 227 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b + 228 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b + 230 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option + 233 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option + 233 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list + 233 mod Base.Map.S_poly.Make_applicative_traversals + 236 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t + 237 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit + 237 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit + 239 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit + 239 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 241 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option + 250 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit + 250 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit + 250 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t + 251 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit + 251 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit + 252 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool + 253 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit + 254 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b + 255 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] + 256 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t + 257 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit + 257 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b + 259 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b + 260 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t + 261 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit + 269 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b + 270 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t + 273 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc + 274 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t + 274 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option + 280 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t + 294 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> + 'a key -> + if_found:('b -> 'c) -> + if_not_found:('a key -> 'c) -> + 'c + 298 val Base.Set.S_poly.empty : 'a t + 298 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> + f:(key:'a key -> data:'b -> ('c, 'd) Either.t) -> + ('a, 'c) t * ('a, 'd) t + 303 val Base.Map.S_poly.empty : ('k, _) t + 305 val Base.Set.S_poly.length : _ t -> int + 308 val Base.Set.S_poly.is_empty : _ t -> bool + 308 val Base.Set.S_poly.singleton : 'a -> 'a t + 309 val Base.Set.S_poly.choose_exn : 'a t -> 'a + 310 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t + 310 val Base.Map.S_poly.length : (_, _) t -> int + 310 val Base.Set.S_poly.max_elt_exn : 'a t -> 'a + 310 val Base.Set.S_poly.min_elt_exn : 'a t -> 'a + 311 val Base.Set.S_poly.of_list : 'a list -> 'a t + 311 val Base.Set.S_poly.of_tree : 'a tree -> 'a t + 311 val Base.Set.S_poly.to_list : 'a t -> 'a list + 311 val Base.Set.S_poly.to_tree : 'a t -> 'a tree + 311 val Base.Set.S_poly.invariants : 'a t -> bool + 312 val Base.Set.S_poly.choose : 'a t -> 'a option + 312 val Base.Set.S_poly.elements : 'a t -> 'a list + 312 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> + dst:('k, 'b) t -> + f:(key:'k key -> 'a -> 'b option -> 'b Merge_into_action.t) -> + unit + 313 val Base.Map.S_poly.data : (_, 'v) t -> 'v list + 313 val Base.Map.S_poly.keys : ('k, _) t -> 'k list + 313 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t + 313 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t + 313 val Base.Set.S_poly.max_elt : 'a t -> 'a option + 313 val Base.Set.S_poly.min_elt : 'a t -> 'a option + 313 val Base.Map.S_poly.is_empty : (_, _) t -> bool + 313 val Base.Set.S_poly.of_array : 'a array -> 'a t + 313 val Base.Set.S_poly.to_array : 'a t -> 'a array + 314 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool + 314 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t + 314 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t + 314 val Base.Hashtbl.S_poly.clear : (_, _) t -> unit + 314 val Base.Hashtbl.S_poly.length : (_, _) t -> int + 314 val Base.Hashtbl.S_poly.hashable : 'a Hashable.t + 315 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool + 316 val Base.Set.S_poly.nth : 'a t -> int -> 'a option + 316 val Base.Set.S_poly.union_list : 'a t list -> 'a t + 317 val Base.Map.S_poly.invariants : ('k, 'v) t -> bool + 317 val Base.Hashtbl.S_poly.is_empty : (_, _) t -> bool + 317 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> + 'a key -> + a:'d -> + if_found:('b -> 'd -> 'c) -> + if_not_found:('a key -> 'd -> 'c) -> + 'c + 319 val Base.Map.S_poly.find_exn : ('k, 'v) t -> 'k -> 'v + 320 val Base.Map.S_poly.singleton : 'k -> 'v -> ('k, 'v) t + 320 val Base.Set.S_poly.remove_index : 'a t -> int -> 'a t + 321 val Base.Hashtbl.S_poly.copy : ('a, 'b) t -> ('a, 'b) t + 321 val Base.Map.S_poly.max_elt_exn : ('k, 'v) t -> 'k * 'v + 321 val Base.Map.S_poly.min_elt_exn : ('k, 'v) t -> 'k * 'v + 321 val Base.Set.S_poly.of_sequence : 'a Sequence.t -> 'a t + 321 val Base.Set.S_poly.are_disjoint : 'a t -> 'a t -> bool + 322 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int + $ sherlodoc search --print-cost --no-rhs "group b" + 127 val Str.group_beginning + 170 val Stdlib.Seq.group + 176 field Signature_group.in_place_patch.replace_by + 181 val Base.Set.group_by + 205 val Base.List.group + 212 val Base.Sequence.group + 220 field UnixLabels.group_entry.gr_gid + 224 field UnixLabels.group_entry.gr_name + 225 val Base.List.sort_and_group + 226 field UnixLabels.group_entry.gr_passwd + 228 val Base.List.groupi + 229 field UnixLabels.group_entry.gr_mem + 235 val Base.List.Assoc.group + 255 val Base.List.Assoc.sort_and_group + 275 val UnixLabels.getgroups + 275 val UnixLabels.setgroups + 275 val Base.Set.Poly.group_by + 280 val UnixLabels.initgroups + 297 type UnixLabels.group_entry + 303 val Base.Set.Using_comparator.group_by + 313 val Base.Set.Using_comparator.Tree.group_by + 323 val Base.Hashtbl.group + 377 val Base.Set.S_poly.group_by + 412 val Base.Set.Accessors_generic.group_by + 423 val Base.Hashtbl.Poly.group + $ sherlodoc search --no-rhs "group by" + field Signature_group.in_place_patch.replace_by + val Base.Set.group_by + val Base.Set.Poly.group_by + val Base.Set.Using_comparator.group_by + val Base.Set.Using_comparator.Tree.group_by + val Base.Set.S_poly.group_by + val Base.Set.Accessors_generic.group_by + val Base.Set.Creators_and_accessors_generic.group_by + $ sherlodoc search --print-cost "map2" + 73 val Stdlib.Seq.map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t + 83 val Stdlib.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 86 val Stdlib.Float.Array.map2 : (float -> float -> float) -> t -> t -> t + 87 val Stdlib.Array.map2 : ('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array + 91 val Stdlib.ListLabels.map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 94 val Stdlib.Float.ArrayLabels.map2 : f:(float -> float -> float) -> t -> t -> t + 95 val Stdlib.ArrayLabels.map2 : f:('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array + 97 val Stdlib.List.rev_map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 105 val Stdlib.ListLabels.rev_map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 127 mod Base.Applicative.Make_using_map2 + 128 mod Base.Applicative.Make2_using_map2 + 128 mod Base.Applicative.Make3_using_map2 + 138 mod Base.Applicative.Make_using_map2_local + 139 mod Base.Applicative.Make2_using_map2_local + 139 mod Base.Applicative.Make3_using_map2_local + 142 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 147 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 150 mod Base.Applicative.Make_using_map2.Applicative_infix + 151 mod Base.Applicative.Make2_using_map2.Applicative_infix + 151 mod Base.Applicative.Make3_using_map2.Applicative_infix + 153 val Misc.Stdlib.List.map2_prefix : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t * 'b t + 155 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 161 mod Base.Applicative.Make_using_map2_local.Applicative_infix + 162 mod Base.Applicative.Make2_using_map2_local.Applicative_infix + 162 mod Base.Applicative.Make3_using_map2_local.Applicative_infix + + $ sherlodoc search --print-cost --static-sort "List map2" + 78 val Stdlib.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 82 val Stdlib.List.rev_map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 86 val Stdlib.ListLabels.map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 90 val Stdlib.ListLabels.rev_map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 127 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 143 val Misc.Stdlib.List.map2_prefix : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t * 'b t + 223 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 240 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 242 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 244 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + + $ sherlodoc search --print-cost "List map2" + 88 val Stdlib.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 102 val Stdlib.List.rev_map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 111 val Stdlib.ListLabels.map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 125 val Stdlib.ListLabels.rev_map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list + 152 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 158 val Misc.Stdlib.List.map2_prefix : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t * 'b t + 238 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 250 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 252 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 264 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + + $ sherlodoc search --no-rhs "Base.Hashtbl.S_without_submodules.group" + val Base.Hashtbl.S_without_submodules.group + $ sherlodoc search --print-cost "list" + 56 mod Stdlib.List + 58 cons Stdlib.List.t.[] : 'a t + 60 val Stdlib.List.hd : 'a list -> 'a + 64 val Stdlib.Stream.of_list : 'a list -> 'a t + 65 val Stdlib.List.tl : 'a list -> 'a list + 65 val Stdlib.List.length : 'a list -> int + 66 val Stdlib.List.rev : 'a list -> 'a list + 67 val Stdlib.Array.of_list : 'a list -> 'a array + 67 val Stdlib.Array.to_list : 'a array -> 'a list + 68 val Stdlib.List.nth : 'a list -> int -> 'a + 69 val Stdlib.List.mem : 'a -> 'a list -> bool + 69 val Stdlib.Option.to_list : 'a option -> 'a list + 69 val Stdlib.Set.Make.of_list : elt list -> t + 70 val Stdlib.List.memq : 'a -> 'a list -> bool + 70 val Stdlib.List.of_seq : 'a Seq.t -> 'a list + 70 val Stdlib.List.to_seq : 'a list -> 'a Seq.t + 71 mod Stdlib.StdLabels.List + 73 val Stdlib.List.cons : 'a -> 'a list -> 'a list + 73 val Stdlib.ArrayLabels.of_list : 'a list -> 'a array + 74 cons Stdlib.List.t.:: : 'a * 'a list -> 'a t + 74 val Stdlib.List.concat : 'a list list -> 'a list + 75 val Stdlib.List.assq : 'a -> ('a * 'b) list -> 'b + 75 val Stdlib.List.flatten : 'a list list -> 'a list + 76 val Stdlib.List.assoc : 'a -> ('a * 'b) list -> 'b + 77 mod Stdlib.ListLabels + $ sherlodoc search --print-cost ": list" + 43 cons Stdlib.List.t.[] : 'a t + 54 cons Stdlib.ListLabels.t.[] : 'a t + 70 val Stdlib.List.tl : 'a list -> 'a list + 71 val Stdlib.List.rev : 'a list -> 'a list + 75 val Stdlib.List.of_seq : 'a Seq.t -> 'a list + 76 val Stdlib.ListLabels.tl : 'a list -> 'a list + 77 val Stdlib.Array.to_list : 'a array -> 'a list + 77 val Stdlib.ListLabels.rev : 'a list -> 'a list + 79 val Stdlib.List.concat : 'a list list -> 'a list + 79 val Stdlib.Option.to_list : 'a option -> 'a list + 80 val Stdlib.List.flatten : 'a list list -> 'a list + 80 val Stdlib.Set.Make.elements : t -> elt list + 81 val Stdlib.ListLabels.of_seq : 'a Seq.t -> 'a list + 83 val Stdlib.ArrayLabels.to_list : 'a array -> 'a list + 84 val Stdlib.Float.Array.to_list : t -> float list + 85 val Stdlib.ListLabels.concat : 'a list list -> 'a list + 86 val Stdlib.ListLabels.flatten : 'a list list -> 'a list + 90 val Stdlib.Float.ArrayLabels.to_list : t -> float list + 97 val Stdlib.(@) : 'a list -> 'a list -> 'a list + 103 val Stdlib.List.cons : 'a -> 'a list -> 'a list + 104 val Stdlib.Stream.npeek : int -> 'a t -> 'a list + 109 cons Stdlib.List.t.:: : 'a * 'a list -> 'a t + 109 val Stdlib.ListLabels.cons : 'a -> 'a list -> 'a list + 110 val Stdlib.List.append : 'a list -> 'a list -> 'a list + 110 val Stdlib.Result.to_list : ('a, 'e) result -> 'a list + +Partial name search: + $ sherlodoc search --print-cost "strin" + 61 val Stdlib.string_of_int : int -> string + 63 val Stdlib.string_of_bool : bool -> string + 64 val Stdlib.Digest.string : string -> t + 65 val Stdlib.string_of_float : float -> string + 69 type Stdlib.String.t = string + 71 val Stdlib.prerr_string : string -> unit + 71 val Stdlib.print_string : string -> unit + 71 val Stdlib.int_of_string : string -> int + 73 mod Stdlib.String + 73 val Stdlib.String.empty : string + 73 val Stdlib.bool_of_string : string -> bool + 74 val Stdlib.Sys.max_string_length : int + 75 type Stdlib.StringLabels.t = string + 75 val Stdlib.Unit.to_string : t -> string + 75 val Stdlib.float_of_string : string -> float + 76 val Stdlib.Int.to_string : int -> string + 78 val Stdlib.Bool.to_string : bool -> string + 79 mod Stdlib.StringLabels + 79 val Stdlib.StringLabels.empty : string + 80 val Stdlib.String.create : int -> bytes + 80 val Stdlib.Bytes.of_string : string -> bytes + 80 val Stdlib.Bytes.to_string : bytes -> string + 80 val Stdlib.Float.of_string : string -> float + 80 val Stdlib.Float.to_string : float -> string + 80 val Stdlib.Int32.to_string : int32 -> string + $ sherlodoc search --print-cost "base strin" + 112 type Base.string = String.t + 124 type Base.Export.string = String.t + 131 val Base.Sexp.of_string : unit + 132 type Base.String.t = string + 132 type Base.String.elt = char + 134 val Base.String.rev : t -> t + 136 mod Base.String + 137 val Base.String.hash : t -> int + 137 val Base.Exn.to_string : t -> string + 137 val Base.Sys.max_string_length : int + 138 val Base.String.escaped : t -> t + 138 val Base.String.max_length : int + 139 val Base.String.(^) : t -> t -> t + 139 val Base.Float.to_string : t -> string + 140 mod Base.Stringable + 140 val Base.String.uppercase : t -> t + 141 type Base.String.Caseless.t = t + 141 val Base.String.capitalize : t -> t + 142 mod Base.StringLabels + 142 val Base.String.append : t -> t -> t + 142 val Base.Exn.to_string_mach : t -> string + 142 val Base.Info.to_string_hum : t -> string + 142 val Base.Sign.to_string_hum : t -> string + 143 val Base.Error.to_string_hum : t -> string + 143 val Base.Info.to_string_mach : t -> string + + $ sherlodoc search --print-cost "tring" + 84 type Stdlib.String.t = string + 88 mod Stdlib.String + 88 val Stdlib.String.empty : string + 91 val Stdlib.prerr_string : string -> unit + 91 val Stdlib.print_string : string -> unit + 91 val Stdlib.int_of_string : string -> int + 93 val Stdlib.bool_of_string : string -> bool + 94 val Stdlib.Digest.string : string -> t + 95 val Stdlib.String.create : int -> bytes + 95 val Stdlib.Unit.to_string : t -> string + 95 val Stdlib.float_of_string : string -> float + 96 val Stdlib.String.equal : t -> t -> bool + 96 val Stdlib.Int.to_string : int -> string + 96 val Stdlib.String.length : string -> int + 96 val Stdlib.string_of_int : int -> string + 97 val Stdlib.String.copy : string -> string + 97 val Stdlib.String.trim : string -> string + 97 val Stdlib.String.compare : t -> t -> int + 98 val Stdlib.String.of_seq : char Seq.t -> t + 98 val Stdlib.String.to_seq : t -> char Seq.t + 98 val Stdlib.Bool.to_string : bool -> string + 98 val Stdlib.string_of_bool : bool -> string + 99 val Stdlib.Sys.max_string_length : int + 100 val Stdlib.String.escaped : string -> string + 100 val Stdlib.Int32.to_string : int32 -> string + $ sherlodoc search --print-cost "base tring" + 142 type Base.string = String.t + 147 type Base.String.t = string + 147 type Base.String.elt = char + 149 val Base.String.rev : t -> t + 151 mod Base.String + 151 val Base.Sexp.of_string : unit + 152 val Base.String.hash : t -> int + 153 val Base.String.escaped : t -> t + 153 val Base.String.max_length : int + 154 val Base.String.(^) : t -> t -> t + 154 type Base.Export.string = String.t + 155 val Base.String.uppercase : t -> t + 156 type Base.String.Caseless.t = t + 156 val Base.String.capitalize : t -> t + 157 val Base.Exn.to_string : t -> string + 157 val Base.String.append : t -> t -> t + 159 val Base.String.equal : t -> t -> bool + 159 val Base.String.prefix : t -> int -> t + 159 val Base.String.suffix : t -> int -> t + 159 val Base.Float.to_string : t -> string + 160 val Base.String.compare : t -> t -> int + 162 val Base.String.ascending : t -> t -> int + 162 val Base.String.split_lines : t -> t list + 162 val Base.Sys.max_string_length : int + 164 val Base.String.common_prefix : t list -> t + diff --git a/test/cram_static/base_web.t b/test/cram_static/base_web.t index dc3c1dcbe3..742ac60d82 100644 --- a/test/cram_static/base_web.t +++ b/test/cram_static/base_web.t @@ -1,15 +1,15 @@ - $ mkdir docs -Generating odocls for base with odig. This might give an error on some -dependencies so we do not display error (one was encountered with yojson) - $ odig odoc --cache-dir=docs base 2> /dev/null - Updating documentation, this may take some time... - $ cat $(find ./docs/odoc/base/ -name '*.odocl') > megaodocl + $ export ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') + $ cat $ODOCLS > megaodocl $ du -sh megaodocl 6.2M megaodocl - $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $(find ./docs/odoc/base/ -name '*.odocl') > /dev/null + $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $ODOCLS > /dev/null $ gzip -k db.js +We want to compare the compressed size with the size of the odocl. The search +database contains information than the odocl, but the information is organised +in queryable way, so a size increase is expected. It should just be reasonable. + $ du -s *.js *.gz 2108 db.js 1592 db.js.gz @@ -23,16 +23,13 @@ The --no-preserve flag is here so that copying to /tmp will not fail because of a previous run. .js files built by dune are read only. $ sherlodoc js html/sherlodoc.js $ ls html - base db.js fonts highlight.pack.js katex.min.css katex.min.js - ocaml odoc.css odoc_search.js - sexplib0 sherlodoc.js indent to see results $ cp -r html /tmp diff --git a/test/cram_static/dune b/test/cram_static/dune index be6047703b..0913ad956b 100644 --- a/test/cram_static/dune +++ b/test/cram_static/dune @@ -5,4 +5,4 @@ (= %{version:menhirLib} 20230608) (= %{version:js_of_ocaml} 5.6.0) (= %{ocaml_version} 4.14.1))) - (deps %{bin:odoc} %{bin:sherlodoc})) + (deps ../docs %{bin:odoc} %{bin:sherlodoc})) diff --git a/test/dune b/test/dune new file mode 100644 index 0000000000..0df55bf40f --- /dev/null +++ b/test/dune @@ -0,0 +1,7 @@ +(rule + (target (dir docs)) + (deps (package base)) + (action + (progn + (run mkdir -p docs) + (run odig odoc --cache-dir=docs base)))) From 38b494b6fe572ace26c9c10ded8119395cb3a965 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Wed, 31 Jan 2024 18:51:45 +0100 Subject: [PATCH 265/285] remove deps from odig docs build --- test/cram/base_cli.t | 28 ++-- test/cram/multi_package.t | 249 +++++++++++++++++------------------- test/cram_static/base_web.t | 6 +- test/dune | 2 +- 4 files changed, 134 insertions(+), 151 deletions(-) diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 43340a6979..eab14102c8 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -230,7 +230,6 @@ 132 val Base.List.filter_opt : 'a option t -> 'a t 132 val Base.List.transpose_exn : 'a t t -> 'a t t 132 val Base.List.concat_no_order : 'a t t -> 'a t - 145 val Caml.(@) : 'a list -> 'a list -> 'a list 149 val Base.Set.to_list : ('a, _) t -> 'a list 150 val Base.Hashtbl.data : (_, 'b) t -> 'b list 150 val Base.Set.elements : ('a, _) t -> 'a list @@ -240,34 +239,35 @@ 154 val Base.List.append : 'a t -> 'a t -> 'a t 154 val Base.Hashtbl.keys : ('a, _) t -> 'a key list 158 val Base.List.rev_append : 'a t -> 'a t -> 'a t + 161 val Base.List.intersperse : 'a t -> sep:'a -> 'a t Partial name search: $ sherlodoc search --print-cost "strin" 97 type Base.string = String.t 109 type Base.Export.string = String.t - 109 val Caml.string_of_int : int -> string - 111 val Caml.string_of_bool : bool -> string - 113 val Caml.string_of_float : float -> string 116 val Base.Sexp.of_string : unit 117 type Base.String.t = string 117 type Base.String.elt = char 119 val Base.String.rev : t -> t - 119 val Caml.prerr_string : string -> unit - 119 val Caml.print_string : string -> unit - 119 val Caml.int_of_string : string -> int 121 mod Base.String 121 mod Caml.String - 121 val Caml.bool_of_string : string -> bool 122 val Base.String.hash : t -> int 122 val Base.Exn.to_string : t -> string 122 val Base.Sys.max_string_length : int 123 val Base.String.escaped : t -> t - 123 val Caml.float_of_string : string -> float 123 val Base.String.max_length : int 124 val Base.String.(^) : t -> t -> t 124 val Base.Float.to_string : t -> string 125 mod Base.Stringable 125 val Base.String.uppercase : t -> t + 126 type Base.String.Caseless.t = t + 126 val Base.String.capitalize : t -> t + 127 mod Base.StringLabels + 127 mod Caml.StringLabels + 127 val Base.String.append : t -> t -> t + 127 val Base.Exn.to_string_mach : t -> string + 127 val Base.Info.to_string_hum : t -> string + 127 val Base.Sign.to_string_hum : t -> string $ sherlodoc search --print-cost "tring" 127 type Base.string = String.t 132 type Base.String.t = string @@ -280,17 +280,17 @@ Partial name search: 138 val Base.String.escaped : t -> t 138 val Base.String.max_length : int 139 val Base.String.(^) : t -> t -> t - 139 val Caml.prerr_string : string -> unit - 139 val Caml.print_string : string -> unit 139 type Base.Export.string = String.t - 139 val Caml.int_of_string : string -> int 140 val Base.String.uppercase : t -> t - 141 val Caml.bool_of_string : string -> bool 141 type Base.String.Caseless.t = t 141 val Base.String.capitalize : t -> t 142 val Base.Exn.to_string : t -> string 142 val Base.String.append : t -> t -> t - 143 val Caml.float_of_string : string -> float 144 val Base.String.equal : t -> t -> bool 144 val Base.String.prefix : t -> int -> t + 144 val Base.String.suffix : t -> int -> t 144 val Base.Float.to_string : t -> string + 145 val Base.String.compare : t -> t -> int + 145 mod Shadow_stdlib.String + 147 val Base.String.ascending : t -> t -> int + 147 val Base.String.split_lines : t -> t list diff --git a/test/cram/multi_package.t b/test/cram/multi_package.t index 4e99ec53d3..1f44eb2c58 100644 --- a/test/cram/multi_package.t +++ b/test/cram/multi_package.t @@ -1,6 +1,6 @@ $ export ODOCLS=$(find ../docs/odoc/ -name '*.odocl' | sort) $ echo $ODOCLS | wc -w - 557 + 142 $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal $ sherlodoc index --index-docstring=false $ODOCLS > /dev/null @@ -120,33 +120,26 @@ 321 val Base.Set.S_poly.are_disjoint : 'a t -> 'a t -> bool 322 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int $ sherlodoc search --print-cost --no-rhs "group b" - 127 val Str.group_beginning - 170 val Stdlib.Seq.group - 176 field Signature_group.in_place_patch.replace_by 181 val Base.Set.group_by 205 val Base.List.group 212 val Base.Sequence.group - 220 field UnixLabels.group_entry.gr_gid - 224 field UnixLabels.group_entry.gr_name 225 val Base.List.sort_and_group - 226 field UnixLabels.group_entry.gr_passwd 228 val Base.List.groupi - 229 field UnixLabels.group_entry.gr_mem 235 val Base.List.Assoc.group 255 val Base.List.Assoc.sort_and_group - 275 val UnixLabels.getgroups - 275 val UnixLabels.setgroups 275 val Base.Set.Poly.group_by - 280 val UnixLabels.initgroups - 297 type UnixLabels.group_entry 303 val Base.Set.Using_comparator.group_by 313 val Base.Set.Using_comparator.Tree.group_by 323 val Base.Hashtbl.group 377 val Base.Set.S_poly.group_by 412 val Base.Set.Accessors_generic.group_by 423 val Base.Hashtbl.Poly.group + 425 val Base.Set.Creators_and_accessors_generic.group_by + 430 val Base.Hashtbl.Creators.group + 437 val Base.Hashtbl.Creators.group + 449 val Base.Hashtbl.S_without_submodules.group + 525 val Base.Hashtbl.S_poly.group $ sherlodoc search --no-rhs "group by" - field Signature_group.in_place_patch.replace_by val Base.Set.group_by val Base.Set.Poly.group_by val Base.Set.Using_comparator.group_by @@ -155,15 +148,6 @@ val Base.Set.Accessors_generic.group_by val Base.Set.Creators_and_accessors_generic.group_by $ sherlodoc search --print-cost "map2" - 73 val Stdlib.Seq.map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t - 83 val Stdlib.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 86 val Stdlib.Float.Array.map2 : (float -> float -> float) -> t -> t -> t - 87 val Stdlib.Array.map2 : ('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array - 91 val Stdlib.ListLabels.map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 94 val Stdlib.Float.ArrayLabels.map2 : f:(float -> float -> float) -> t -> t -> t - 95 val Stdlib.ArrayLabels.map2 : f:('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array - 97 val Stdlib.List.rev_map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 105 val Stdlib.ListLabels.rev_map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list 127 mod Base.Applicative.Make_using_map2 128 mod Base.Applicative.Make2_using_map2 128 mod Base.Applicative.Make3_using_map2 @@ -175,31 +159,30 @@ 150 mod Base.Applicative.Make_using_map2.Applicative_infix 151 mod Base.Applicative.Make2_using_map2.Applicative_infix 151 mod Base.Applicative.Make3_using_map2.Applicative_infix - 153 val Misc.Stdlib.List.map2_prefix : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t * 'b t 155 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t 161 mod Base.Applicative.Make_using_map2_local.Applicative_infix 162 mod Base.Applicative.Make2_using_map2_local.Applicative_infix 162 mod Base.Applicative.Make3_using_map2_local.Applicative_infix + 166 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 178 sig Base.Applicative.Basic_using_map2 + 178 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 179 sig Base.Applicative.Basic2_using_map2 + 179 sig Base.Applicative.Basic3_using_map2 + 189 sig Base.Applicative.Basic_using_map2_local + 189 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 190 sig Base.Applicative.Basic2_using_map2_local + 190 sig Base.Applicative.Basic3_using_map2_local + 226 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc search --print-cost --static-sort "List map2" - 78 val Stdlib.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 82 val Stdlib.List.rev_map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 86 val Stdlib.ListLabels.map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 90 val Stdlib.ListLabels.rev_map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list 127 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 143 val Misc.Stdlib.List.map2_prefix : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t * 'b t 223 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 240 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t 242 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 244 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t $ sherlodoc search --print-cost "List map2" - 88 val Stdlib.List.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 102 val Stdlib.List.rev_map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 111 val Stdlib.ListLabels.map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - 125 val Stdlib.ListLabels.rev_map2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list 152 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 158 val Misc.Stdlib.List.map2_prefix : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t * 'b t 238 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t 250 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t 252 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t @@ -208,85 +191,85 @@ $ sherlodoc search --no-rhs "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group $ sherlodoc search --print-cost "list" - 56 mod Stdlib.List - 58 cons Stdlib.List.t.[] : 'a t - 60 val Stdlib.List.hd : 'a list -> 'a - 64 val Stdlib.Stream.of_list : 'a list -> 'a t - 65 val Stdlib.List.tl : 'a list -> 'a list - 65 val Stdlib.List.length : 'a list -> int - 66 val Stdlib.List.rev : 'a list -> 'a list - 67 val Stdlib.Array.of_list : 'a list -> 'a array - 67 val Stdlib.Array.to_list : 'a array -> 'a list - 68 val Stdlib.List.nth : 'a list -> int -> 'a - 69 val Stdlib.List.mem : 'a -> 'a list -> bool - 69 val Stdlib.Option.to_list : 'a option -> 'a list - 69 val Stdlib.Set.Make.of_list : elt list -> t - 70 val Stdlib.List.memq : 'a -> 'a list -> bool - 70 val Stdlib.List.of_seq : 'a Seq.t -> 'a list - 70 val Stdlib.List.to_seq : 'a list -> 'a Seq.t - 71 mod Stdlib.StdLabels.List - 73 val Stdlib.List.cons : 'a -> 'a list -> 'a list - 73 val Stdlib.ArrayLabels.of_list : 'a list -> 'a array - 74 cons Stdlib.List.t.:: : 'a * 'a list -> 'a t - 74 val Stdlib.List.concat : 'a list list -> 'a list - 75 val Stdlib.List.assq : 'a -> ('a * 'b) list -> 'b - 75 val Stdlib.List.flatten : 'a list list -> 'a list - 76 val Stdlib.List.assoc : 'a -> ('a * 'b) list -> 'b - 77 mod Stdlib.ListLabels + 81 type 'a Base.list = 'a List.t + 93 type 'a Base.Export.list = 'a List.t + 101 type 'a Base.List.t = 'a list + 104 mod Base.List + 104 mod Caml.List + 108 val Base.List.rev : 'a t -> 'a t + 109 val Base.List.hd_exn : 'a t -> 'a + 109 val Base.List.return : 'a -> 'a t + 110 val Base.Bytes.to_list : t -> char list + 111 val Base.List.join : 'a t t -> 'a t + 111 val Base.List.tl_exn : 'a t -> 'a t + 111 val Base.Queue.of_list : 'a list -> 'a t + 111 val Base.Stack.of_list : 'a list -> 'a t + 113 val Base.List.concat : 'a t t -> 'a t + 113 mod Shadow_stdlib.List + 114 val Base.List.last : 'a t -> 'a option + 114 val Base.Set.to_list : ('a, _) t -> 'a list + 115 mod Base.List.Assoc + 115 mod Base.List.Infix + 115 cons Base.Sexp.t.List : t list -> t + 115 val Base.List.ignore_m : 'a t -> unit t + 115 val Base.Bytes.of_char_list : char list -> t + 116 val Base.List.drop : 'a t -> int -> 'a t + 116 val Base.List.take : 'a t -> int -> 'a t + 117 val Base.List.nth_exn : 'a t -> int -> 'a $ sherlodoc search --print-cost ": list" - 43 cons Stdlib.List.t.[] : 'a t - 54 cons Stdlib.ListLabels.t.[] : 'a t - 70 val Stdlib.List.tl : 'a list -> 'a list - 71 val Stdlib.List.rev : 'a list -> 'a list - 75 val Stdlib.List.of_seq : 'a Seq.t -> 'a list - 76 val Stdlib.ListLabels.tl : 'a list -> 'a list - 77 val Stdlib.Array.to_list : 'a array -> 'a list - 77 val Stdlib.ListLabels.rev : 'a list -> 'a list - 79 val Stdlib.List.concat : 'a list list -> 'a list - 79 val Stdlib.Option.to_list : 'a option -> 'a list - 80 val Stdlib.List.flatten : 'a list list -> 'a list - 80 val Stdlib.Set.Make.elements : t -> elt list - 81 val Stdlib.ListLabels.of_seq : 'a Seq.t -> 'a list - 83 val Stdlib.ArrayLabels.to_list : 'a array -> 'a list - 84 val Stdlib.Float.Array.to_list : t -> float list - 85 val Stdlib.ListLabels.concat : 'a list list -> 'a list - 86 val Stdlib.ListLabels.flatten : 'a list list -> 'a list - 90 val Stdlib.Float.ArrayLabels.to_list : t -> float list - 97 val Stdlib.(@) : 'a list -> 'a list -> 'a list - 103 val Stdlib.List.cons : 'a -> 'a list -> 'a list - 104 val Stdlib.Stream.npeek : int -> 'a t -> 'a list - 109 cons Stdlib.List.t.:: : 'a * 'a list -> 'a t - 109 val Stdlib.ListLabels.cons : 'a -> 'a list -> 'a list - 110 val Stdlib.List.append : 'a list -> 'a list -> 'a list - 110 val Stdlib.Result.to_list : ('a, 'e) result -> 'a list + 118 val Base.List.rev : 'a t -> 'a t + 119 val Base.List.return : 'a -> 'a t + 120 val Base.Bytes.to_list : t -> char list + 121 val Base.List.join : 'a t t -> 'a t + 121 val Base.List.tl_exn : 'a t -> 'a t + 122 val Base.String.split_lines : t -> t list + 123 val Base.List.concat : 'a t t -> 'a t + 125 val Base.List.ignore_m : 'a t -> unit t + 125 val Base.String.to_list_rev : t -> char list + 128 val Base.Sequence.to_list_rev : 'a t -> 'a list + 130 val Base.Pretty_printer.all : unit -> string list + 132 val Base.List.all_unit : unit t list -> unit t + 132 val Base.List.filter_opt : 'a option t -> 'a t + 132 val Base.List.transpose_exn : 'a t t -> 'a t t + 132 val Base.List.concat_no_order : 'a t t -> 'a t + 149 val Base.Set.to_list : ('a, _) t -> 'a list + 150 val Base.Hashtbl.data : (_, 'b) t -> 'b list + 150 val Base.Set.elements : ('a, _) t -> 'a list + 151 val Base.List.drop : 'a t -> int -> 'a t + 151 val Base.List.take : 'a t -> int -> 'a t + 152 val Base.String.split : t -> on:char -> t list + 154 val Base.List.append : 'a t -> 'a t -> 'a t + 154 val Base.Hashtbl.keys : ('a, _) t -> 'a key list + 158 val Base.List.rev_append : 'a t -> 'a t -> 'a t + 161 val Base.List.intersperse : 'a t -> sep:'a -> 'a t Partial name search: $ sherlodoc search --print-cost "strin" - 61 val Stdlib.string_of_int : int -> string - 63 val Stdlib.string_of_bool : bool -> string - 64 val Stdlib.Digest.string : string -> t - 65 val Stdlib.string_of_float : float -> string - 69 type Stdlib.String.t = string - 71 val Stdlib.prerr_string : string -> unit - 71 val Stdlib.print_string : string -> unit - 71 val Stdlib.int_of_string : string -> int - 73 mod Stdlib.String - 73 val Stdlib.String.empty : string - 73 val Stdlib.bool_of_string : string -> bool - 74 val Stdlib.Sys.max_string_length : int - 75 type Stdlib.StringLabels.t = string - 75 val Stdlib.Unit.to_string : t -> string - 75 val Stdlib.float_of_string : string -> float - 76 val Stdlib.Int.to_string : int -> string - 78 val Stdlib.Bool.to_string : bool -> string - 79 mod Stdlib.StringLabels - 79 val Stdlib.StringLabels.empty : string - 80 val Stdlib.String.create : int -> bytes - 80 val Stdlib.Bytes.of_string : string -> bytes - 80 val Stdlib.Bytes.to_string : bytes -> string - 80 val Stdlib.Float.of_string : string -> float - 80 val Stdlib.Float.to_string : float -> string - 80 val Stdlib.Int32.to_string : int32 -> string + 97 type Base.string = String.t + 109 type Base.Export.string = String.t + 116 val Base.Sexp.of_string : unit + 117 type Base.String.t = string + 117 type Base.String.elt = char + 119 val Base.String.rev : t -> t + 121 mod Base.String + 121 mod Caml.String + 122 val Base.String.hash : t -> int + 122 val Base.Exn.to_string : t -> string + 122 val Base.Sys.max_string_length : int + 123 val Base.String.escaped : t -> t + 123 val Base.String.max_length : int + 124 val Base.String.(^) : t -> t -> t + 124 val Base.Float.to_string : t -> string + 125 mod Base.Stringable + 125 val Base.String.uppercase : t -> t + 126 type Base.String.Caseless.t = t + 126 val Base.String.capitalize : t -> t + 127 mod Base.StringLabels + 127 mod Caml.StringLabels + 127 val Base.String.append : t -> t -> t + 127 val Base.Exn.to_string_mach : t -> string + 127 val Base.Info.to_string_hum : t -> string + 127 val Base.Sign.to_string_hum : t -> string $ sherlodoc search --print-cost "base strin" 112 type Base.string = String.t 124 type Base.Export.string = String.t @@ -315,31 +298,31 @@ Partial name search: 143 val Base.Info.to_string_mach : t -> string $ sherlodoc search --print-cost "tring" - 84 type Stdlib.String.t = string - 88 mod Stdlib.String - 88 val Stdlib.String.empty : string - 91 val Stdlib.prerr_string : string -> unit - 91 val Stdlib.print_string : string -> unit - 91 val Stdlib.int_of_string : string -> int - 93 val Stdlib.bool_of_string : string -> bool - 94 val Stdlib.Digest.string : string -> t - 95 val Stdlib.String.create : int -> bytes - 95 val Stdlib.Unit.to_string : t -> string - 95 val Stdlib.float_of_string : string -> float - 96 val Stdlib.String.equal : t -> t -> bool - 96 val Stdlib.Int.to_string : int -> string - 96 val Stdlib.String.length : string -> int - 96 val Stdlib.string_of_int : int -> string - 97 val Stdlib.String.copy : string -> string - 97 val Stdlib.String.trim : string -> string - 97 val Stdlib.String.compare : t -> t -> int - 98 val Stdlib.String.of_seq : char Seq.t -> t - 98 val Stdlib.String.to_seq : t -> char Seq.t - 98 val Stdlib.Bool.to_string : bool -> string - 98 val Stdlib.string_of_bool : bool -> string - 99 val Stdlib.Sys.max_string_length : int - 100 val Stdlib.String.escaped : string -> string - 100 val Stdlib.Int32.to_string : int32 -> string + 127 type Base.string = String.t + 132 type Base.String.t = string + 132 type Base.String.elt = char + 134 val Base.String.rev : t -> t + 136 mod Base.String + 136 mod Caml.String + 136 val Base.Sexp.of_string : unit + 137 val Base.String.hash : t -> int + 138 val Base.String.escaped : t -> t + 138 val Base.String.max_length : int + 139 val Base.String.(^) : t -> t -> t + 139 type Base.Export.string = String.t + 140 val Base.String.uppercase : t -> t + 141 type Base.String.Caseless.t = t + 141 val Base.String.capitalize : t -> t + 142 val Base.Exn.to_string : t -> string + 142 val Base.String.append : t -> t -> t + 144 val Base.String.equal : t -> t -> bool + 144 val Base.String.prefix : t -> int -> t + 144 val Base.String.suffix : t -> int -> t + 144 val Base.Float.to_string : t -> string + 145 val Base.String.compare : t -> t -> int + 145 mod Shadow_stdlib.String + 147 val Base.String.ascending : t -> t -> int + 147 val Base.String.split_lines : t -> t list $ sherlodoc search --print-cost "base tring" 142 type Base.string = String.t 147 type Base.String.t = string diff --git a/test/cram_static/base_web.t b/test/cram_static/base_web.t index 742ac60d82..198b4dd365 100644 --- a/test/cram_static/base_web.t +++ b/test/cram_static/base_web.t @@ -1,7 +1,7 @@ $ export ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') $ cat $ODOCLS > megaodocl $ du -sh megaodocl - 6.2M megaodocl + 5.4M megaodocl $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $ODOCLS > /dev/null $ gzip -k db.js @@ -11,8 +11,8 @@ database contains information than the odocl, but the information is organised in queryable way, so a size increase is expected. It should just be reasonable. $ du -s *.js *.gz - 2108 db.js - 1592 db.js.gz + 2064 db.js + 1560 db.js.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f diff --git a/test/dune b/test/dune index 0df55bf40f..5b35e17c77 100644 --- a/test/dune +++ b/test/dune @@ -4,4 +4,4 @@ (action (progn (run mkdir -p docs) - (run odig odoc --cache-dir=docs base)))) + (run odig odoc --no-pkg-deps --cache-dir=docs base)))) From 757ad2bddbb53b02fe2564a3492446b91a081aeb Mon Sep 17 00:00:00 2001 From: art-w Date: Thu, 1 Feb 2024 17:47:40 +0100 Subject: [PATCH 266/285] fix CI for various architectures (#10) --- db/type_polarity.mli | 95 +++++----- store/storage_ancient.ml | 9 +- test/cram/base_benchmark.t | 4 + test/cram/base_cli.t | 2 +- test/cram/base_odocls.t | 294 ++++++++++++++--------------- test/cram/base_web.t | 40 ++++ test/cram/cli_poly.t/run.t | 4 +- test/cram/module_type_cost.t/run.t | 4 +- test/cram/multi_package.t | 4 +- test/cram/simple.t/run.t | 18 +- test/cram/size_bound.t | 8 +- test/cram_ancient/dune | 2 +- test/cram_static/base_web.t | 10 +- test/cram_static/dune | 2 - test/dune | 9 +- 15 files changed, 269 insertions(+), 236 deletions(-) create mode 100644 test/cram/base_benchmark.t create mode 100644 test/cram/base_web.t diff --git a/db/type_polarity.mli b/db/type_polarity.mli index 0bbcac3108..e3cb13229a 100644 --- a/db/type_polarity.mli +++ b/db/type_polarity.mli @@ -1,51 +1,52 @@ (** This module provide a way to transform a type into strings, in such a way - that the strings can be used for type search. - -The chosen representation is polarity : we do not represent the [->] or the [*] -constructors, but instead compute the "polarity" of every type name/constructor -like [int] or ['a] that is part of the whole type expression. - -The polarity of a component of a type indicates if it is produced or consumed by -the type. In the type [int -> string], [int] has negative polarity because it is -being consumed, and [string] has positive polarity because it is being produced. -We say that the polarities of [int -> string] are [-int] and [+string]. - -Once you have computed the polarities of the type of an entry [e], you can -register each polarity as corresponding to [e] in the search database. - -Then, when the user queries for a type, we compute the polarities of the query -type, and search for the entries. - -We then return the result corresponding to intersection of each polarity: if the -user queries for [int -> string], we want to have every entry which consumes an -[int] and produces a [string], that is the intersection of the entries -associated to [-int] with the entries associated to [+string]. - -How is polarity computed exactly ? When you have [t -> u], the polarity of [t] -is inversed, and the polarity of [u] stays the same. A good example of this is -the type of {!Stdlib.Out_channel.with_open_gen} : - -{| val with_open_gen : open_flag list -> int -> string -> (t -> 'a) -> 'a |} - -Here the polarities are [-open_flag list], [-int], [-string], [+Out_channel.t], -[-'a] and [+'a]. The fact that we have [+Out_channel.t] might be puzzling at -first, because an [Out_channel.t] is not returned by the function, but -{!Stdlib.Out_channel.with_open_gen} is indeed one of the possible ways to create -an [Out_channel.t]. - -There is however a complication. If the user queries for [int -> int -> string], -then the polarities will be [-int], [-int] and [+string]. An entry of type [int --> string] would be included in the intersection of these polarities. But the -user explicitely asked for two integers to be consumed. To fix this issue, we -track the number of occurences of each polarity. - -The polarities for [int -> int -> string], become [(-int, 2)] and [(+string, -1)], and allows us to filter entries according to this information. - -There is a mechanism for types with parameters like ['a list]. I might explain -it in the future. -TODO : Give an example even if not the full explanation. -*) + that the strings can be used for type search. + + The chosen representation is polarity : we do not represent the [->] or the [*] + constructors, but instead compute the "polarity" of every type name/constructor + like [int] or ['a] that is part of the whole type expression. + + The polarity of a component of a type indicates if it is produced or consumed by + the type. In the type [int -> string], [int] has negative polarity because it is + being consumed, and [string] has positive polarity because it is being produced. + We say that the polarities of [int -> string] are [-int] and [+string]. + + Once you have computed the polarities of the type of an entry [e], you can + register each polarity as corresponding to [e] in the search database. + + Then, when the user queries for a type, we compute the polarities of the query + type, and search for the entries. + + We then return the result corresponding to intersection of each polarity: if the + user queries for [int -> string], we want to have every entry which consumes an + [int] and produces a [string], that is the intersection of the entries + associated to [-int] with the entries associated to [+string]. + + How is polarity computed exactly ? When you have [t -> u], the polarity of [t] + is inversed, and the polarity of [u] stays the same. A good example of this is + the type of {!Stdlib.Out_channel.with_open_gen} : + + {[ + val with_open_gen : open_flag list -> int -> string -> (t -> 'a) -> 'a + ]} + + Here the polarities are [-open_flag list], [-int], [-string], [+Out_channel.t], + [-'a] and [+'a]. The fact that we have [+Out_channel.t] might be puzzling at + first, because an [Out_channel.t] is not returned by the function, but + {!Stdlib.Out_channel.with_open_gen} is indeed one of the possible ways to create + an [Out_channel.t]. + + There is however a complication. If the user queries for [int -> int -> string], + then the polarities will be [-int], [-int] and [+string]. An entry of type [int +tring] would be included in the intersection of these polarities. But the + user explicitely asked for two integers to be consumed. To fix this issue, we + track the number of occurences of each polarity. + + The polarities for [int -> int -> string], become [(-int, 2)] and [(+string, 1)] + and allows us to filter entries according to this information. + + There is a mechanism for types with parameters like ['a list]. I might explain + it in the future. + TODO : Give an example even if not the full explanation. *) module Sign : sig type t = diff --git a/store/storage_ancient.ml b/store/storage_ancient.ml index dce23b623e..beb07b13c7 100644 --- a/store/storage_ancient.ml +++ b/store/storage_ancient.ml @@ -1,4 +1,7 @@ -let base_addr = 0x100000000000n +let base_addr () = + if Sys.word_size > 32 + then Int64.to_nativeint 0x100000000000L + else failwith "TODO: support ancient on 32 bits" type writer = { mutable write_shard : int @@ -7,7 +10,7 @@ type writer = let open_out filename = let handle = Unix.openfile filename Unix.[ O_RDWR; O_TRUNC; O_CREAT ] 0o640 in - let ancient = Ancient.attach handle base_addr in + let ancient = Ancient.attach handle (base_addr ()) in { write_shard = 0; ancient } let save ~db (t : Db.t) = @@ -34,7 +37,7 @@ let load_shards md = let db_open_in db : reader = let filename = db in let handle = Unix.openfile filename Unix.[ O_RDWR ] 0o640 in - let md = Ancient.attach handle base_addr in + let md = Ancient.attach handle (base_addr ()) in { shards = load_shards md } let load db_filename = diff --git a/test/cram/base_benchmark.t b/test/cram/base_benchmark.t new file mode 100644 index 0000000000..960ca5d776 --- /dev/null +++ b/test/cram/base_benchmark.t @@ -0,0 +1,4 @@ +This test will fail, it is not deterministic. Please just check that the values +are not crazy and discard the changes + $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl' | sort) + $ sherlodoc index --format=js --db=db.js $ODOCLS > /dev/null diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index eab14102c8..4dabb1cedd 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -1,4 +1,4 @@ - $ export ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') + $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal $ sherlodoc index --index-docstring=false $ODOCLS > /dev/null diff --git a/test/cram/base_odocls.t b/test/cram/base_odocls.t index ac85358c90..6214582519 100644 --- a/test/cram/base_odocls.t +++ b/test/cram/base_odocls.t @@ -1,151 +1,143 @@ - $ find ../docs/odoc/base/ -name '*.odocl' | sort - ../docs/odoc/base/base.odocl - ../docs/odoc/base/base__.odocl - ../docs/odoc/base/base__Applicative.odocl - ../docs/odoc/base/base__Applicative_intf.odocl - ../docs/odoc/base/base__Array.odocl - ../docs/odoc/base/base__Array0.odocl - ../docs/odoc/base/base__Array_permute.odocl - ../docs/odoc/base/base__Avltree.odocl - ../docs/odoc/base/base__Backtrace.odocl - ../docs/odoc/base/base__Binary_search.odocl - ../docs/odoc/base/base__Binary_searchable.odocl - ../docs/odoc/base/base__Binary_searchable_intf.odocl - ../docs/odoc/base/base__Blit.odocl - ../docs/odoc/base/base__Blit_intf.odocl - ../docs/odoc/base/base__Bool.odocl - ../docs/odoc/base/base__Bool0.odocl - ../docs/odoc/base/base__Buffer.odocl - ../docs/odoc/base/base__Buffer_intf.odocl - ../docs/odoc/base/base__Bytes.odocl - ../docs/odoc/base/base__Bytes0.odocl - ../docs/odoc/base/base__Bytes_tr.odocl - ../docs/odoc/base/base__Char.odocl - ../docs/odoc/base/base__Char0.odocl - ../docs/odoc/base/base__Comparable.odocl - ../docs/odoc/base/base__Comparable_intf.odocl - ../docs/odoc/base/base__Comparator.odocl - ../docs/odoc/base/base__Comparisons.odocl - ../docs/odoc/base/base__Container.odocl - ../docs/odoc/base/base__Container_intf.odocl - ../docs/odoc/base/base__Either.odocl - ../docs/odoc/base/base__Either0.odocl - ../docs/odoc/base/base__Either_intf.odocl - ../docs/odoc/base/base__Equal.odocl - ../docs/odoc/base/base__Error.odocl - ../docs/odoc/base/base__Exn.odocl - ../docs/odoc/base/base__Field.odocl - ../docs/odoc/base/base__Fieldslib.odocl - ../docs/odoc/base/base__Float.odocl - ../docs/odoc/base/base__Float0.odocl - ../docs/odoc/base/base__Floatable.odocl - ../docs/odoc/base/base__Fn.odocl - ../docs/odoc/base/base__Formatter.odocl - ../docs/odoc/base/base__Globalize.odocl - ../docs/odoc/base/base__Hash.odocl - ../docs/odoc/base/base__Hash_intf.odocl - ../docs/odoc/base/base__Hash_set.odocl - ../docs/odoc/base/base__Hash_set_intf.odocl - ../docs/odoc/base/base__Hashable.odocl - ../docs/odoc/base/base__Hashable_intf.odocl - ../docs/odoc/base/base__Hasher.odocl - ../docs/odoc/base/base__Hashtbl.odocl - ../docs/odoc/base/base__Hashtbl_intf.odocl - ../docs/odoc/base/base__Hex_lexer.odocl - ../docs/odoc/base/base__Identifiable.odocl - ../docs/odoc/base/base__Identifiable_intf.odocl - ../docs/odoc/base/base__Import.odocl - ../docs/odoc/base/base__Import0.odocl - ../docs/odoc/base/base__Indexed_container.odocl - ../docs/odoc/base/base__Indexed_container_intf.odocl - ../docs/odoc/base/base__Info.odocl - ../docs/odoc/base/base__Info_intf.odocl - ../docs/odoc/base/base__Int.odocl - ../docs/odoc/base/base__Int0.odocl - ../docs/odoc/base/base__Int32.odocl - ../docs/odoc/base/base__Int63.odocl - ../docs/odoc/base/base__Int63_emul.odocl - ../docs/odoc/base/base__Int64.odocl - ../docs/odoc/base/base__Int_conversions.odocl - ../docs/odoc/base/base__Int_intf.odocl - ../docs/odoc/base/base__Int_math.odocl - ../docs/odoc/base/base__Intable.odocl - ../docs/odoc/base/base__Invariant.odocl - ../docs/odoc/base/base__Invariant_intf.odocl - ../docs/odoc/base/base__Lazy.odocl - ../docs/odoc/base/base__Linked_queue.odocl - ../docs/odoc/base/base__Linked_queue0.odocl - ../docs/odoc/base/base__List.odocl - ../docs/odoc/base/base__List0.odocl - ../docs/odoc/base/base__List1.odocl - ../docs/odoc/base/base__Map.odocl - ../docs/odoc/base/base__Map_intf.odocl - ../docs/odoc/base/base__Maybe_bound.odocl - ../docs/odoc/base/base__Monad.odocl - ../docs/odoc/base/base__Monad_intf.odocl - ../docs/odoc/base/base__Nativeint.odocl - ../docs/odoc/base/base__Nothing.odocl - ../docs/odoc/base/base__Obj_array.odocl - ../docs/odoc/base/base__Obj_local.odocl - ../docs/odoc/base/base__Option.odocl - ../docs/odoc/base/base__Option_array.odocl - ../docs/odoc/base/base__Or_error.odocl - ../docs/odoc/base/base__Ordered_collection_common.odocl - ../docs/odoc/base/base__Ordered_collection_common0.odocl - ../docs/odoc/base/base__Ordering.odocl - ../docs/odoc/base/base__Poly0.odocl - ../docs/odoc/base/base__Popcount.odocl - ../docs/odoc/base/base__Pow_overflow_bounds.odocl - ../docs/odoc/base/base__Ppx_compare_lib.odocl - ../docs/odoc/base/base__Ppx_enumerate_lib.odocl - ../docs/odoc/base/base__Ppx_hash_lib.odocl - ../docs/odoc/base/base__Pretty_printer.odocl - ../docs/odoc/base/base__Printf.odocl - ../docs/odoc/base/base__Queue.odocl - ../docs/odoc/base/base__Queue_intf.odocl - ../docs/odoc/base/base__Random.odocl - ../docs/odoc/base/base__Random_repr.odocl - ../docs/odoc/base/base__Ref.odocl - ../docs/odoc/base/base__Result.odocl - ../docs/odoc/base/base__Sequence.odocl - ../docs/odoc/base/base__Set.odocl - ../docs/odoc/base/base__Set_intf.odocl - ../docs/odoc/base/base__Sexp.odocl - ../docs/odoc/base/base__Sexp_with_comparable.odocl - ../docs/odoc/base/base__Sexpable.odocl - ../docs/odoc/base/base__Sign.odocl - ../docs/odoc/base/base__Sign0.odocl - ../docs/odoc/base/base__Sign_or_nan.odocl - ../docs/odoc/base/base__Source_code_position.odocl - ../docs/odoc/base/base__Source_code_position0.odocl - ../docs/odoc/base/base__Stack.odocl - ../docs/odoc/base/base__Stack_intf.odocl - ../docs/odoc/base/base__Staged.odocl - ../docs/odoc/base/base__String.odocl - ../docs/odoc/base/base__String0.odocl - ../docs/odoc/base/base__Stringable.odocl - ../docs/odoc/base/base__Sys.odocl - ../docs/odoc/base/base__Sys0.odocl - ../docs/odoc/base/base__T.odocl - ../docs/odoc/base/base__Type_equal.odocl - ../docs/odoc/base/base__Uchar.odocl - ../docs/odoc/base/base__Uchar0.odocl - ../docs/odoc/base/base__Uniform_array.odocl - ../docs/odoc/base/base__Unit.odocl - ../docs/odoc/base/base__Variant.odocl - ../docs/odoc/base/base__Variantslib.odocl - ../docs/odoc/base/base__With_return.odocl - ../docs/odoc/base/base__Word_size.odocl - ../docs/odoc/base/base_internalhash_types/base_internalhash_types.odocl - ../docs/odoc/base/caml/caml.odocl - ../docs/odoc/base/md5/md5_lib.odocl - ../docs/odoc/base/page-index.odocl - ../docs/odoc/base/shadow_stdlib/shadow_stdlib.odocl - - - - - - - - + $ find ../docs/odoc/base/ -name '*.odocl' -exec basename '{}' ';' | sort + base.odocl + base__.odocl + base__Applicative.odocl + base__Applicative_intf.odocl + base__Array.odocl + base__Array0.odocl + base__Array_permute.odocl + base__Avltree.odocl + base__Backtrace.odocl + base__Binary_search.odocl + base__Binary_searchable.odocl + base__Binary_searchable_intf.odocl + base__Blit.odocl + base__Blit_intf.odocl + base__Bool.odocl + base__Bool0.odocl + base__Buffer.odocl + base__Buffer_intf.odocl + base__Bytes.odocl + base__Bytes0.odocl + base__Bytes_tr.odocl + base__Char.odocl + base__Char0.odocl + base__Comparable.odocl + base__Comparable_intf.odocl + base__Comparator.odocl + base__Comparisons.odocl + base__Container.odocl + base__Container_intf.odocl + base__Either.odocl + base__Either0.odocl + base__Either_intf.odocl + base__Equal.odocl + base__Error.odocl + base__Exn.odocl + base__Field.odocl + base__Fieldslib.odocl + base__Float.odocl + base__Float0.odocl + base__Floatable.odocl + base__Fn.odocl + base__Formatter.odocl + base__Globalize.odocl + base__Hash.odocl + base__Hash_intf.odocl + base__Hash_set.odocl + base__Hash_set_intf.odocl + base__Hashable.odocl + base__Hashable_intf.odocl + base__Hasher.odocl + base__Hashtbl.odocl + base__Hashtbl_intf.odocl + base__Hex_lexer.odocl + base__Identifiable.odocl + base__Identifiable_intf.odocl + base__Import.odocl + base__Import0.odocl + base__Indexed_container.odocl + base__Indexed_container_intf.odocl + base__Info.odocl + base__Info_intf.odocl + base__Int.odocl + base__Int0.odocl + base__Int32.odocl + base__Int63.odocl + base__Int63_emul.odocl + base__Int64.odocl + base__Int_conversions.odocl + base__Int_intf.odocl + base__Int_math.odocl + base__Intable.odocl + base__Invariant.odocl + base__Invariant_intf.odocl + base__Lazy.odocl + base__Linked_queue.odocl + base__Linked_queue0.odocl + base__List.odocl + base__List0.odocl + base__List1.odocl + base__Map.odocl + base__Map_intf.odocl + base__Maybe_bound.odocl + base__Monad.odocl + base__Monad_intf.odocl + base__Nativeint.odocl + base__Nothing.odocl + base__Obj_array.odocl + base__Obj_local.odocl + base__Option.odocl + base__Option_array.odocl + base__Or_error.odocl + base__Ordered_collection_common.odocl + base__Ordered_collection_common0.odocl + base__Ordering.odocl + base__Poly0.odocl + base__Popcount.odocl + base__Pow_overflow_bounds.odocl + base__Ppx_compare_lib.odocl + base__Ppx_enumerate_lib.odocl + base__Ppx_hash_lib.odocl + base__Pretty_printer.odocl + base__Printf.odocl + base__Queue.odocl + base__Queue_intf.odocl + base__Random.odocl + base__Random_repr.odocl + base__Ref.odocl + base__Result.odocl + base__Sequence.odocl + base__Set.odocl + base__Set_intf.odocl + base__Sexp.odocl + base__Sexp_with_comparable.odocl + base__Sexpable.odocl + base__Sign.odocl + base__Sign0.odocl + base__Sign_or_nan.odocl + base__Source_code_position.odocl + base__Source_code_position0.odocl + base__Stack.odocl + base__Stack_intf.odocl + base__Staged.odocl + base__String.odocl + base__String0.odocl + base__Stringable.odocl + base__Sys.odocl + base__Sys0.odocl + base__T.odocl + base__Type_equal.odocl + base__Uchar.odocl + base__Uchar0.odocl + base__Uniform_array.odocl + base__Unit.odocl + base__Variant.odocl + base__Variantslib.odocl + base__With_return.odocl + base__Word_size.odocl + base_internalhash_types.odocl + caml.odocl + md5_lib.odocl + page-index.odocl + shadow_stdlib.odocl diff --git a/test/cram/base_web.t b/test/cram/base_web.t new file mode 100644 index 0000000000..448ddd4c33 --- /dev/null +++ b/test/cram/base_web.t @@ -0,0 +1,40 @@ + $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl' | sort) + $ cat $ODOCLS > megaodocl +$ du -sh megaodocl +13M megaodocl + $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $ODOCLS > /dev/null + + $ gzip -k db.js + +We want to compare the compressed size with the size of the odocl. The search +database contains information than the odocl, but the information is organised +in queryable way, so a size increase is expected. It should just be reasonable. + $ gzip -k megaodocl + +Marshal size changes between OCaml versions +$ du -s db.js db.js.gz +2112 db.js +1596 db.js.gz + + $ for f in $(find . -name '*.odocl'); do + > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f + > done + $ odoc support-files -o html + $ cp db.js html/ +The --no-preserve flag is here so that copying to /tmp will not fail because of +a previous run. .js files built by dune are read only. + $ sherlodoc js html/sherlodoc.js +$ du -sh html/sherlodoc.js +104K html/sherlodoc.js + $ ls html + db.js + fonts + highlight.pack.js + katex.min.css + katex.min.js + odoc.css + odoc_search.js + sherlodoc.js +indent to see results +$ cp -r html /tmp +$ firefox /tmp/html/base/index.html diff --git a/test/cram/cli_poly.t/run.t b/test/cram/cli_poly.t/run.t index 4b840d9330..266a77111a 100644 --- a/test/cram/cli_poly.t/run.t +++ b/test/cram/cli_poly.t/run.t @@ -4,8 +4,8 @@ $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc $ cat $(find . -name '*.odocl') > megaodocl - $ du -sh megaodocl - 4.0K megaodocl +$ du -sh megaodocl +4.0K megaodocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal $ sherlodoc index $(find . -name '*.odocl') diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t index a91585251a..5be645e7fa 100644 --- a/test/cram/module_type_cost.t/run.t +++ b/test/cram/module_type_cost.t/run.t @@ -2,8 +2,8 @@ $ odoc compile -I . main.cmti $ odoc link -I . main.odoc $ cat $(find . -name '*.odocl') > megaodocl - $ du -sh megaodocl - 4.0K megaodocl +$ du -sh megaodocl +4.0K megaodocl $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal $ sherlodoc index $(find . -name '*.odocl') diff --git a/test/cram/multi_package.t b/test/cram/multi_package.t index 1f44eb2c58..f93590e749 100644 --- a/test/cram/multi_package.t +++ b/test/cram/multi_package.t @@ -1,5 +1,5 @@ - $ export ODOCLS=$(find ../docs/odoc/ -name '*.odocl' | sort) - $ echo $ODOCLS | wc -w + $ ODOCLS=$(find ../docs/odoc/ -name '*.odocl' | sort) + $ echo "$ODOCLS" | awk 'END { print NR }' 142 $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal diff --git a/test/cram/simple.t/run.t b/test/cram/simple.t/run.t index 22c3459a1d..145698ae28 100644 --- a/test/cram/simple.t/run.t +++ b/test/cram/simple.t/run.t @@ -4,26 +4,21 @@ $ odoc link -I . main.odoc $ odoc link -I . page-page.odoc $ cat $(find . -name '*.odocl') > megaodocl - $ du -sh megaodocl - 12K megaodocl - $ sherlodoc index --format=js --db=db.js $(find . -name '*.odocl') 2> /dev/null - -Here cat is used to remove weird permissions on executable built by dune - $ sherlodoc js sherlodoc.js +$ du -sh megaodocl +12K megaodocl $ mkdir html - $ cp sherlodoc.js html - $ cp db.js html + $ sherlodoc index --format=js --db=html/db.js $(find . -name '*.odocl') 2> /dev/null + $ sherlodoc js html/sherlodoc.js $ odoc support-files -o html $ for f in $(find . -name '*.odocl' | sort); do > echo $f ; > cd html ; > odoc html-generate --search-uri db.js --search-uri sherlodoc.js --output-dir . ../$f ; > cd .. - > done + > done | sort ./main.odocl ./page-page.odocl $ ls | sort - db.js html main.cmi main.cmo @@ -35,7 +30,6 @@ Here cat is used to remove weird permissions on executable built by dune page-page.odoc page-page.odocl page.mld - sherlodoc.js $ ls html | sort db.js fonts @@ -58,13 +52,11 @@ Here cat is used to remove weird permissions on executable built by dune ./html/page/Main/module-type-Signature/index.html ./html/page/index.html $ find . -name "*.js" -type f | sort - ./db.js ./html/db.js ./html/highlight.pack.js ./html/katex.min.js ./html/odoc_search.js ./html/sherlodoc.js - ./sherlodoc.js Indent to see results $ cp -r html /tmp diff --git a/test/cram/size_bound.t b/test/cram/size_bound.t index 0b97dbdaf3..2d7b2c530f 100644 --- a/test/cram/size_bound.t +++ b/test/cram/size_bound.t @@ -1,11 +1,11 @@ -This tests the sherlodoc.js is not bigger than 120000 bytes. We test a threshold +This tests that sherlodoc.js is not bigger than 120000 bytes. We test a threshold of the size because the precise size depends on specific ocaml and dependencies versions. This test should pass on every version. If it fails, we can either -update the threshold to be a larg enough or forbid certain dependency versions +update the threshold to be large enough or forbid certain dependency versions in the opam file. $ sherlodoc js sherlodoc.js - $ if [ "$(stat --printf="%s" sherlodoc.js)" -gt 120000 ]; then - > stat --printf="%s" sherlodoc.js + $ if [ "$(du sherlodoc.js | cut -f 1)" -gt 120000 ]; then + > du sherlodoc.js > else > echo "All good! "; > fi diff --git a/test/cram_ancient/dune b/test/cram_ancient/dune index 9e980dd522..693a24fd21 100644 --- a/test/cram_ancient/dune +++ b/test/cram_ancient/dune @@ -1,3 +1,3 @@ (cram -(enabled_if %{lib-available:ancient} ) + (enabled_if %{lib-available:ancient}) (deps %{bin:odoc} %{bin:sherlodoc})) diff --git a/test/cram_static/base_web.t b/test/cram_static/base_web.t index 198b4dd365..11aa91d44a 100644 --- a/test/cram_static/base_web.t +++ b/test/cram_static/base_web.t @@ -1,7 +1,7 @@ $ export ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') $ cat $ODOCLS > megaodocl - $ du -sh megaodocl - 5.4M megaodocl +$ du -sh megaodocl +5.4M megaodocl $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $ODOCLS > /dev/null $ gzip -k db.js @@ -10,9 +10,9 @@ We want to compare the compressed size with the size of the odocl. The search database contains information than the odocl, but the information is organised in queryable way, so a size increase is expected. It should just be reasonable. - $ du -s *.js *.gz - 2064 db.js - 1560 db.js.gz +$ du -s *.js *.gz +2108 db.js +1592 db.js.gz $ for f in $(find . -name '*.odocl'); do > odoc html-generate --search-uri=db.js --search-uri=sherlodoc.js --output-dir html $f diff --git a/test/cram_static/dune b/test/cram_static/dune index 0913ad956b..54d19fea64 100644 --- a/test/cram_static/dune +++ b/test/cram_static/dune @@ -1,8 +1,6 @@ (cram (enabled_if (and - (= %{version:brr} 0.0.6) (= %{version:menhirLib} 20230608) - (= %{version:js_of_ocaml} 5.6.0) (= %{ocaml_version} 4.14.1))) (deps ../docs %{bin:odoc} %{bin:sherlodoc})) diff --git a/test/dune b/test/dune index 5b35e17c77..94a91be7bb 100644 --- a/test/dune +++ b/test/dune @@ -1,7 +1,10 @@ (rule - (target (dir docs)) - (deps (package base)) + (target + (dir docs)) + (deps + (package base)) (action (progn (run mkdir -p docs) - (run odig odoc --no-pkg-deps --cache-dir=docs base)))) + (run odig odoc --cache-dir=docs --no-pkg-deps --quiet base) + (run rm docs/html/base/_doc-dir)))) From 51db06c0bff7817c09a5b8c5fee2ecd0c15d7cfa Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 5 Feb 2024 14:13:41 +0100 Subject: [PATCH 267/285] add --version to sherlodoc (0.2) --- cli/main.ml | 3 ++- test/cram/version.t | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 test/cram/version.t diff --git a/cli/main.ml b/cli/main.ml index e8856faca9..32799c2539 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -76,7 +76,8 @@ let cmd_jsoo = let cmd = let doc = "Sherlodoc" in - let info = Cmd.info "sherlodoc" ~doc in + let version = "0.2" in + let info = Cmd.info "sherlodoc" ~version ~doc in Cmd.group info [ cmd_search; cmd_index; cmd_serve; cmd_jsoo ] let () = exit (Cmd.eval cmd) diff --git a/test/cram/version.t b/test/cram/version.t new file mode 100644 index 0000000000..6a58e4dd78 --- /dev/null +++ b/test/cram/version.t @@ -0,0 +1,2 @@ + $ sherlodoc --version + 0.2 From 032c613898b5e96206eccae49ed00a5509a288e8 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 30 Jan 2024 18:31:53 +0100 Subject: [PATCH 268/285] add option to chose a list of favored prefixes --- index/index.ml | 37 +++++++++-- index/load_doc.ml | 21 ++++-- index/load_doc.mli | 1 + test/cram/favouritism.t | 140 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+), 8 deletions(-) create mode 100644 test/cram/favouritism.t diff --git a/index/index.ml b/index/index.ml index 0da9a9c9a5..404e467368 100644 --- a/index/index.ml +++ b/index/index.ml @@ -15,13 +15,28 @@ let index_file register filename = | Ok result -> result | Error (`Msg msg) -> Format.printf "Odoc warning or error %s: %s@." filename msg) -let main files file_list index_docstring index_name type_search db_format db_filename = +let main + files + file_list + index_docstring + index_name + type_search + favoured_prefixes + db_format + db_filename + = 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 id () item = List.iter - (Load_doc.register_entry ~db ~index_docstring ~index_name ~type_search ~pkg) + (Load_doc.register_entry + ~db + ~index_docstring + ~index_name + ~type_search + ~favoured_prefixes + ~pkg) (Odoc_search.Entry.entries_of_item id item) in let files = @@ -69,9 +84,16 @@ let index_name = Arg.(value & opt bool true & info ~doc [ "index-name" ]) let type_search = - let doc = "Enable type based search" in + let doc = "Enable type based search." in Arg.(value & opt bool true & info ~doc [ "type-search" ]) +let favoured_prefixes = + let doc = + "The list of favoured prefixes. Entries that start with a favoured prefix are ranked \ + higher." + in + Arg.(value & opt (list string) [ "Stdlib." ] & info ~doc [ "favoured-prefixes" ]) + let file_list = let doc = "File containing a list of .odocl files.\n\ @@ -84,4 +106,11 @@ let odoc_files = Arg.(value & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) let term = - Term.(const main $ odoc_files $ file_list $ index_docstring $ index_name $ type_search) + Term.( + const main + $ odoc_files + $ file_list + $ index_docstring + $ index_name + $ type_search + $ favoured_prefixes) diff --git a/index/load_doc.ml b/index/load_doc.ml index 5cbb9748d0..331e2f3796 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -34,10 +34,12 @@ let cost_doc = function 0 | _ -> 100 -let cost ~name ~kind ~doc_html ~rhs ~cat = +let cost ~name ~kind ~doc_html ~rhs ~cat ~favoured_prefixes = String.length name + (5 * path_length name) - + (if string_starts_with ~prefix:"Stdlib." name then 0 else 50) + + (if List.exists (fun prefix -> string_starts_with ~prefix name) favoured_prefixes + then 0 + else 50) + rhs_cost rhs + kind_cost kind + (if cat = `definition then 0 else 100) @@ -164,6 +166,7 @@ let register_entry ~index_name ~type_search ~index_docstring + ~favoured_prefixes ~pkg ~cat (Odoc_search.Entry.{ id; doc; kind } as entry) @@ -179,7 +182,7 @@ let register_entry in let rhs = Html.rhs_of_kind kind in let kind = convert_kind ~db entry in - let cost = cost ~name ~kind ~doc_html ~rhs ~cat in + let cost = cost ~name ~kind ~doc_html ~rhs ~cat ~favoured_prefixes in let url = Result.get_ok (Html.url id) 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 ; @@ -191,6 +194,7 @@ let register_entry ~index_name ~type_search ~index_docstring + ~favoured_prefixes ~pkg (Odoc_search.Entry.{ id; kind; _ } as entry) = @@ -202,4 +206,13 @@ let register_entry in if is_pure_documentation || cat = `ignore || Odoc_model.Paths.Identifier.is_internal id then () - else register_entry ~db ~index_name ~type_search ~index_docstring ~pkg ~cat entry + else + register_entry + ~db + ~index_name + ~type_search + ~index_docstring + ~favoured_prefixes + ~pkg + ~cat + entry diff --git a/index/load_doc.mli b/index/load_doc.mli index df9b8f4189..ff5c297e21 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -3,6 +3,7 @@ val register_entry -> index_name:bool -> type_search:bool -> index_docstring:bool + -> favoured_prefixes:string list -> pkg:Db.Entry.Package.t -> Odoc_search.Entry.t -> unit diff --git a/test/cram/favouritism.t b/test/cram/favouritism.t new file mode 100644 index 0000000000..d95e809dd9 --- /dev/null +++ b/test/cram/favouritism.t @@ -0,0 +1,140 @@ + $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=marshal + $ sherlodoc index $ODOCLS > /dev/null + $ sherlodoc search --print-cost "list" + 81 type 'a Base.list = 'a List.t + 93 type 'a Base.Export.list = 'a List.t + 101 type 'a Base.List.t = 'a list + 104 mod Base.List + 104 mod Caml.List + 108 val Base.List.rev : 'a t -> 'a t + 109 val Base.List.hd_exn : 'a t -> 'a + 109 val Base.List.return : 'a -> 'a t + 110 val Base.Bytes.to_list : t -> char list + 111 val Base.List.join : 'a t t -> 'a t + 111 val Base.List.tl_exn : 'a t -> 'a t + 111 val Base.Queue.of_list : 'a list -> 'a t + 111 val Base.Stack.of_list : 'a list -> 'a t + 113 val Base.List.concat : 'a t t -> 'a t + 113 mod Shadow_stdlib.List + 114 val Base.List.last : 'a t -> 'a option + 115 mod Base.List.Assoc + 115 mod Base.List.Infix + 115 cons Base.Sexp.t.List : t list -> t + 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 + $ sherlodoc index --favoured-prefixes=Base $ODOCLS > /dev/null + $ sherlodoc search --print-cost "list" + 31 type 'a Base.list = 'a List.t + 43 type 'a Base.Export.list = 'a List.t + 51 type 'a Base.List.t = 'a list + 54 mod Base.List + 58 val Base.List.rev : 'a t -> 'a t + 59 val Base.List.hd_exn : 'a t -> 'a + 59 val Base.List.return : 'a -> 'a t + 60 val Base.Bytes.to_list : t -> char list + 61 val Base.List.join : 'a t t -> 'a t + 61 val Base.List.tl_exn : 'a t -> 'a t + 61 val Base.Queue.of_list : 'a list -> 'a t + 61 val Base.Stack.of_list : 'a list -> 'a t + 63 val Base.List.concat : 'a t t -> 'a t + 64 val Base.List.last : 'a t -> 'a option + 65 mod Base.List.Assoc + 65 mod Base.List.Infix + 65 cons Base.Sexp.t.List : t list -> t + 65 val Base.List.ignore_m : 'a t -> unit t + 66 val Base.List.drop : 'a t -> int -> 'a t + 66 val Base.List.take : 'a t -> int -> 'a t + 75 mod Base.ListLabels + 294 mod Base + 297 type Base.Nothing.t = + 312 val Base.String.append : t -> t -> t + 314 val Base.Int.ascending : t -> t -> int + $ sherlodoc index --favoured-prefixes=Caml $ODOCLS > /dev/null + $ sherlodoc search --print-cost "list" + 54 mod Caml.List + 75 mod Caml.ListLabels + 81 type 'a Base.list = 'a List.t + 93 type 'a Base.Export.list = 'a List.t + 101 type 'a Base.List.t = 'a list + 104 mod Base.List + 108 val Base.List.rev : 'a t -> 'a t + 109 val Base.List.hd_exn : 'a t -> 'a + 109 val Base.List.return : 'a -> 'a t + 110 val Base.Bytes.to_list : t -> char list + 111 val Base.List.join : 'a t t -> 'a t + 111 val Base.List.tl_exn : 'a t -> 'a t + 111 val Base.Queue.of_list : 'a list -> 'a t + 111 val Base.Stack.of_list : 'a list -> 'a t + 113 val Base.List.concat : 'a t t -> 'a t + 113 mod Shadow_stdlib.List + 114 val Base.List.last : 'a t -> 'a option + 115 mod Base.List.Assoc + 115 mod Base.List.Infix + 115 cons Base.Sexp.t.List : t list -> t + 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 + $ sherlodoc index --favoured-prefixes=Base,Caml $ODOCLS > /dev/null + $ sherlodoc search --print-cost "list" + 31 type 'a Base.list = 'a List.t + 43 type 'a Base.Export.list = 'a List.t + 51 type 'a Base.List.t = 'a list + 54 mod Base.List + 54 mod Caml.List + 58 val Base.List.rev : 'a t -> 'a t + 59 val Base.List.hd_exn : 'a t -> 'a + 59 val Base.List.return : 'a -> 'a t + 60 val Base.Bytes.to_list : t -> char list + 61 val Base.List.join : 'a t t -> 'a t + 61 val Base.List.tl_exn : 'a t -> 'a t + 61 val Base.Queue.of_list : 'a list -> 'a t + 61 val Base.Stack.of_list : 'a list -> 'a t + 63 val Base.List.concat : 'a t t -> 'a t + 64 val Base.List.last : 'a t -> 'a option + 65 mod Base.List.Assoc + 65 mod Base.List.Infix + 65 cons Base.Sexp.t.List : t list -> t + 65 val Base.List.ignore_m : 'a t -> unit t + 66 val Base.List.drop : 'a t -> int -> 'a t + 66 val Base.List.take : 'a t -> int -> 'a t + 75 mod Base.ListLabels + 75 mod Caml.ListLabels + 294 mod Base + 297 type Base.Nothing.t = + $ sherlodoc index $ODOCLS --favoured-prefixes "" > /dev/null + $ sherlodoc search --print-cost "list" + 81 type 'a Base.list = 'a List.t + 93 type 'a Base.Export.list = 'a List.t + 101 type 'a Base.List.t = 'a list + 104 mod Base.List + 104 mod Caml.List + 108 val Base.List.rev : 'a t -> 'a t + 109 val Base.List.hd_exn : 'a t -> 'a + 109 val Base.List.return : 'a -> 'a t + 110 val Base.Bytes.to_list : t -> char list + 111 val Base.List.join : 'a t t -> 'a t + 111 val Base.List.tl_exn : 'a t -> 'a t + 111 val Base.Queue.of_list : 'a list -> 'a t + 111 val Base.Stack.of_list : 'a list -> 'a t + 113 val Base.List.concat : 'a t t -> 'a t + 113 mod Shadow_stdlib.List + 114 val Base.List.last : 'a t -> 'a option + 115 mod Base.List.Assoc + 115 mod Base.List.Infix + 115 cons Base.Sexp.t.List : t list -> t + 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 + +Partial name search: From db629c51203e1cb55a75b228bce8ffd0b6254d83 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Mon, 5 Feb 2024 13:54:34 +0100 Subject: [PATCH 269/285] add file level favouritism --- index/index.ml | 34 +- index/load_doc.ml | 8 +- index/load_doc.mli | 1 + test/cram/base_cli.t | 508 +++++++++++------------ test/cram/cli.t/run.t | 4 +- test/cram/cli_small.t/run.t | 10 +- test/cram/favouritism.t | 140 ------- test/cram/module_type_cost.t/run.t | 10 +- test/cram/multi_package.t | 608 ++++++++++++++-------------- test/cram/odocl_favouritism.t/a.mli | 1 + test/cram/odocl_favouritism.t/b.mli | 1 + test/cram/odocl_favouritism.t/run.t | 25 ++ test/cram/prefix_favouritism.t | 140 +++++++ test/cram_ancient/cli_small.t/run.t | 10 +- 14 files changed, 770 insertions(+), 730 deletions(-) delete mode 100644 test/cram/favouritism.t create mode 100644 test/cram/odocl_favouritism.t/a.mli create mode 100644 test/cram/odocl_favouritism.t/b.mli create mode 100644 test/cram/odocl_favouritism.t/run.t create mode 100644 test/cram/prefix_favouritism.t diff --git a/index/index.ml b/index/index.ml index 404e467368..10c017b6e9 100644 --- a/index/index.ml +++ b/index/index.ml @@ -17,6 +17,7 @@ let index_file register filename = let main files + favourite_files file_list index_docstring index_name @@ -28,13 +29,14 @@ 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 id () item = + let register ~pkg ~favourite id () item = 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) @@ -58,18 +60,19 @@ let main let t = Db_writer.export ~summarize:(db_format = `ancient) db in Storage.save ~db:h t in - List.iter - (fun odoc -> - let pkg, odoc = - match String.split_on_char '\t' odoc with - | [ filename ] -> no_pkg, filename - | [ name; filename ] -> Db.Entry.Package.v ~name ~version:"", filename - | [ name; version; filename ] -> Db.Entry.Package.v ~name ~version, filename - | _ -> failwith ("invalid line: " ^ odoc) - in - index_file (register ~pkg) odoc ; - if db_format = `ancient && Db_writer.load db > 1_000_000 then flush ()) - files ; + let loop ~favourite odoc = + let pkg, odoc = + match String.split_on_char '\t' odoc with + | [ filename ] -> no_pkg, filename + | [ name; filename ] -> Db.Entry.Package.v ~name ~version:"", filename + | [ name; version; filename ] -> Db.Entry.Package.v ~name ~version, filename + | _ -> failwith ("invalid line: " ^ odoc) + in + index_file (register ~pkg ~favourite) odoc ; + if db_format = `ancient && Db_writer.load db > 1_000_000 then flush () + in + List.iter (loop ~favourite:false) files ; + List.iter (loop ~favourite:true) favourite_files ; flush () ; Storage.close_out h @@ -101,6 +104,10 @@ let file_list = in Arg.(value & opt (some file) None & info [ "file-list" ] ~doc) +let odoc_favourite_file = + let doc = "Path to a .odocl file whose entries will be ranked higher." in + Arg.(value & opt_all file [] & info [ "favoured" ] ~doc) + let odoc_files = let doc = "Path to a .odocl file" in Arg.(value & (pos_all file [] @@ info ~doc ~docv:"ODOCL_FILE" [])) @@ -109,6 +116,7 @@ let term = Term.( const main $ odoc_files + $ odoc_favourite_file $ file_list $ index_docstring $ index_name diff --git a/index/load_doc.ml b/index/load_doc.ml index 331e2f3796..3aa9602578 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -34,12 +34,13 @@ let cost_doc = function 0 | _ -> 100 -let cost ~name ~kind ~doc_html ~rhs ~cat ~favoured_prefixes = +let cost ~name ~kind ~doc_html ~rhs ~cat ~favourite ~favoured_prefixes = String.length name + (5 * path_length name) + (if List.exists (fun prefix -> string_starts_with ~prefix name) favoured_prefixes then 0 else 50) + + (if favourite then 0 else 50) + rhs_cost rhs + kind_cost kind + (if cat = `definition then 0 else 100) @@ -166,6 +167,7 @@ let register_entry ~index_name ~type_search ~index_docstring + ~favourite ~favoured_prefixes ~pkg ~cat @@ -182,7 +184,7 @@ let register_entry in let rhs = Html.rhs_of_kind kind in let kind = convert_kind ~db entry in - let cost = cost ~name ~kind ~doc_html ~rhs ~cat ~favoured_prefixes in + let cost = cost ~name ~kind ~doc_html ~rhs ~cat ~favourite ~favoured_prefixes in let url = Result.get_ok (Html.url id) 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 ; @@ -194,6 +196,7 @@ let register_entry ~index_name ~type_search ~index_docstring + ~favourite ~favoured_prefixes ~pkg (Odoc_search.Entry.{ id; kind; _ } as entry) @@ -212,6 +215,7 @@ let register_entry ~index_name ~type_search ~index_docstring + ~favourite ~favoured_prefixes ~pkg ~cat diff --git a/index/load_doc.mli b/index/load_doc.mli index ff5c297e21..4012b9bf04 100644 --- a/index/load_doc.mli +++ b/index/load_doc.mli @@ -3,6 +3,7 @@ val register_entry -> index_name:bool -> type_search:bool -> index_docstring:bool + -> favourite:bool -> favoured_prefixes:string list -> pkg:Db.Entry.Package.t -> Odoc_search.Entry.t diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 4dabb1cedd..2def58d996 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -3,140 +3,140 @@ $ export SHERLODOC_FORMAT=marshal $ sherlodoc index --index-docstring=false $ODOCLS > /dev/null $ sherlodoc search --print-cost --limit 100 "S_poly" - 150 sig Base.Map.S_poly - 150 sig Base.Set.S_poly - 154 sig Base.Hashtbl.S_poly - 198 type 'a Base.Hashtbl.S_poly.key = 'a - 207 type ('a, 'b) Base.Map.S_poly.t - 207 type 'elt Base.Set.S_poly.t - 209 type ('a, 'cmp) Base.Set.S_poly.set - 210 val Base.Set.S_poly.mem : 'a t -> 'a -> bool - 210 type ('a, 'b) Base.Map.S_poly.tree - 210 type 'elt Base.Set.S_poly.tree - 211 type ('a, 'b) Base.Hashtbl.S_poly.t - 211 mod Base.Set.S_poly.Named - 217 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list - 221 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list - 224 type Base.Map.S_poly.comparator_witness - 224 type Base.Set.S_poly.comparator_witness - 227 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t - 227 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b - 228 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b - 230 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option - 233 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option - 233 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list - 233 mod Base.Map.S_poly.Make_applicative_traversals - 236 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t - 237 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit - 237 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit - 239 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit - 239 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list - 241 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option - 250 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit - 250 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit - 250 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t - 251 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit - 251 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit - 252 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool - 253 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit - 254 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b - 255 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] - 256 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t - 257 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit - 257 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b - 259 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b - 260 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t - 261 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit - 269 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b - 270 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t - 273 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc - 274 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t - 274 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option - 280 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t - 294 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> + 200 sig Base.Map.S_poly + 200 sig Base.Set.S_poly + 204 sig Base.Hashtbl.S_poly + 248 type 'a Base.Hashtbl.S_poly.key = 'a + 257 type ('a, 'b) Base.Map.S_poly.t + 257 type 'elt Base.Set.S_poly.t + 259 type ('a, 'cmp) Base.Set.S_poly.set + 260 val Base.Set.S_poly.mem : 'a t -> 'a -> bool + 260 type ('a, 'b) Base.Map.S_poly.tree + 260 type 'elt Base.Set.S_poly.tree + 261 type ('a, 'b) Base.Hashtbl.S_poly.t + 261 mod Base.Set.S_poly.Named + 267 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list + 271 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + 274 type Base.Map.S_poly.comparator_witness + 274 type Base.Set.S_poly.comparator_witness + 277 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t + 277 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b + 278 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b + 280 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option + 283 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option + 283 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list + 283 mod Base.Map.S_poly.Make_applicative_traversals + 286 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t + 287 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit + 287 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit + 289 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit + 289 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 291 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option + 300 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit + 300 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit + 300 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t + 301 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit + 301 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit + 302 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool + 303 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit + 304 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b + 305 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] + 306 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t + 307 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit + 307 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b + 309 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b + 310 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t + 311 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit + 319 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b + 320 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t + 323 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc + 324 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t + 324 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option + 330 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t + 344 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> 'a key -> if_found:('b -> 'c) -> if_not_found:('a key -> 'c) -> 'c - 298 val Base.Set.S_poly.empty : 'a t - 298 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> + 348 val Base.Set.S_poly.empty : 'a t + 348 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t - 303 val Base.Map.S_poly.empty : ('k, _) t - 305 val Base.Set.S_poly.length : _ t -> int - 308 val Base.Set.S_poly.is_empty : _ t -> bool - 308 val Base.Set.S_poly.singleton : 'a -> 'a t - 309 val Base.Set.S_poly.choose_exn : 'a t -> 'a - 310 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t - 310 val Base.Map.S_poly.length : (_, _) t -> int - 310 val Base.Set.S_poly.max_elt_exn : 'a t -> 'a - 310 val Base.Set.S_poly.min_elt_exn : 'a t -> 'a - 311 val Base.Set.S_poly.of_list : 'a list -> 'a t - 311 val Base.Set.S_poly.of_tree : 'a tree -> 'a t - 311 val Base.Set.S_poly.to_list : 'a t -> 'a list - 311 val Base.Set.S_poly.to_tree : 'a t -> 'a tree - 311 val Base.Set.S_poly.invariants : 'a t -> bool - 312 val Base.Set.S_poly.choose : 'a t -> 'a option - 312 val Base.Set.S_poly.elements : 'a t -> 'a list - 312 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> + 353 val Base.Map.S_poly.empty : ('k, _) t + 355 val Base.Set.S_poly.length : _ t -> int + 358 val Base.Set.S_poly.is_empty : _ t -> bool + 358 val Base.Set.S_poly.singleton : 'a -> 'a t + 359 val Base.Set.S_poly.choose_exn : 'a t -> 'a + 360 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t + 360 val Base.Map.S_poly.length : (_, _) t -> int + 360 val Base.Set.S_poly.max_elt_exn : 'a t -> 'a + 360 val Base.Set.S_poly.min_elt_exn : 'a t -> 'a + 361 val Base.Set.S_poly.of_list : 'a list -> 'a t + 361 val Base.Set.S_poly.of_tree : 'a tree -> 'a t + 361 val Base.Set.S_poly.to_list : 'a t -> 'a list + 361 val Base.Set.S_poly.to_tree : 'a t -> 'a tree + 361 val Base.Set.S_poly.invariants : 'a t -> bool + 362 val Base.Set.S_poly.choose : 'a t -> 'a option + 362 val Base.Set.S_poly.elements : 'a t -> 'a list + 362 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> dst:('k, 'b) t -> f:(key:'k key -> 'a -> 'b option -> 'b Merge_into_action.t) -> unit - 313 val Base.Map.S_poly.data : (_, 'v) t -> 'v list - 313 val Base.Map.S_poly.keys : ('k, _) t -> 'k list - 313 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t - 313 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t - 313 val Base.Set.S_poly.max_elt : 'a t -> 'a option - 313 val Base.Set.S_poly.min_elt : 'a t -> 'a option - 313 val Base.Map.S_poly.is_empty : (_, _) t -> bool - 313 val Base.Set.S_poly.of_array : 'a array -> 'a t - 313 val Base.Set.S_poly.to_array : 'a t -> 'a array - 314 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool - 314 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t - 314 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t - 314 val Base.Hashtbl.S_poly.clear : (_, _) t -> unit - 314 val Base.Hashtbl.S_poly.length : (_, _) t -> int - 314 val Base.Hashtbl.S_poly.hashable : 'a Hashable.t - 315 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool - 316 val Base.Set.S_poly.nth : 'a t -> int -> 'a option - 316 val Base.Set.S_poly.union_list : 'a t list -> 'a t - 317 val Base.Map.S_poly.invariants : ('k, 'v) t -> bool - 317 val Base.Hashtbl.S_poly.is_empty : (_, _) t -> bool - 317 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> + 363 val Base.Map.S_poly.data : (_, 'v) t -> 'v list + 363 val Base.Map.S_poly.keys : ('k, _) t -> 'k list + 363 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t + 363 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t + 363 val Base.Set.S_poly.max_elt : 'a t -> 'a option + 363 val Base.Set.S_poly.min_elt : 'a t -> 'a option + 363 val Base.Map.S_poly.is_empty : (_, _) t -> bool + 363 val Base.Set.S_poly.of_array : 'a array -> 'a t + 363 val Base.Set.S_poly.to_array : 'a t -> 'a array + 364 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool + 364 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t + 364 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t + 364 val Base.Hashtbl.S_poly.clear : (_, _) t -> unit + 364 val Base.Hashtbl.S_poly.length : (_, _) t -> int + 364 val Base.Hashtbl.S_poly.hashable : 'a Hashable.t + 365 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool + 366 val Base.Set.S_poly.nth : 'a t -> int -> 'a option + 366 val Base.Set.S_poly.union_list : 'a t list -> 'a t + 367 val Base.Map.S_poly.invariants : ('k, 'v) t -> bool + 367 val Base.Hashtbl.S_poly.is_empty : (_, _) t -> bool + 367 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> 'a key -> a:'d -> if_found:('b -> 'd -> 'c) -> if_not_found:('a key -> 'd -> 'c) -> 'c - 319 val Base.Map.S_poly.find_exn : ('k, 'v) t -> 'k -> 'v - 320 val Base.Map.S_poly.singleton : 'k -> 'v -> ('k, 'v) t - 320 val Base.Set.S_poly.remove_index : 'a t -> int -> 'a t - 321 val Base.Hashtbl.S_poly.copy : ('a, 'b) t -> ('a, 'b) t - 321 val Base.Map.S_poly.max_elt_exn : ('k, 'v) t -> 'k * 'v - 321 val Base.Map.S_poly.min_elt_exn : ('k, 'v) t -> 'k * 'v - 321 val Base.Set.S_poly.of_sequence : 'a Sequence.t -> 'a t - 321 val Base.Set.S_poly.are_disjoint : 'a t -> 'a t -> bool - 322 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int + 369 val Base.Map.S_poly.find_exn : ('k, 'v) t -> 'k -> 'v + 370 val Base.Map.S_poly.singleton : 'k -> 'v -> ('k, 'v) t + 370 val Base.Set.S_poly.remove_index : 'a t -> int -> 'a t + 371 val Base.Hashtbl.S_poly.copy : ('a, 'b) t -> ('a, 'b) t + 371 val Base.Map.S_poly.max_elt_exn : ('k, 'v) t -> 'k * 'v + 371 val Base.Map.S_poly.min_elt_exn : ('k, 'v) t -> 'k * 'v + 371 val Base.Set.S_poly.of_sequence : 'a Sequence.t -> 'a t + 371 val Base.Set.S_poly.are_disjoint : 'a t -> 'a t -> bool + 372 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int $ sherlodoc search --print-cost --no-rhs "group b" - 181 val Base.Set.group_by - 205 val Base.List.group - 212 val Base.Sequence.group - 225 val Base.List.sort_and_group - 228 val Base.List.groupi - 235 val Base.List.Assoc.group - 255 val Base.List.Assoc.sort_and_group - 275 val Base.Set.Poly.group_by - 303 val Base.Set.Using_comparator.group_by - 313 val Base.Set.Using_comparator.Tree.group_by - 323 val Base.Hashtbl.group - 377 val Base.Set.S_poly.group_by - 412 val Base.Set.Accessors_generic.group_by - 423 val Base.Hashtbl.Poly.group - 425 val Base.Set.Creators_and_accessors_generic.group_by - 430 val Base.Hashtbl.Creators.group - 437 val Base.Hashtbl.Creators.group - 449 val Base.Hashtbl.S_without_submodules.group - 525 val Base.Hashtbl.S_poly.group + 231 val Base.Set.group_by + 255 val Base.List.group + 262 val Base.Sequence.group + 275 val Base.List.sort_and_group + 278 val Base.List.groupi + 285 val Base.List.Assoc.group + 305 val Base.List.Assoc.sort_and_group + 325 val Base.Set.Poly.group_by + 353 val Base.Set.Using_comparator.group_by + 363 val Base.Set.Using_comparator.Tree.group_by + 373 val Base.Hashtbl.group + 427 val Base.Set.S_poly.group_by + 462 val Base.Set.Accessors_generic.group_by + 473 val Base.Hashtbl.Poly.group + 475 val Base.Set.Creators_and_accessors_generic.group_by + 480 val Base.Hashtbl.Creators.group + 487 val Base.Hashtbl.Creators.group + 499 val Base.Hashtbl.S_without_submodules.group + 575 val Base.Hashtbl.S_poly.group $ sherlodoc search --no-rhs "group by" val Base.Set.group_by val Base.Set.Poly.group_by @@ -146,151 +146,151 @@ val Base.Set.Accessors_generic.group_by val Base.Set.Creators_and_accessors_generic.group_by $ sherlodoc search --print-cost "map2" - 127 mod Base.Applicative.Make_using_map2 - 128 mod Base.Applicative.Make2_using_map2 - 128 mod Base.Applicative.Make3_using_map2 - 138 mod Base.Applicative.Make_using_map2_local - 139 mod Base.Applicative.Make2_using_map2_local - 139 mod Base.Applicative.Make3_using_map2_local - 142 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 147 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 150 mod Base.Applicative.Make_using_map2.Applicative_infix - 151 mod Base.Applicative.Make2_using_map2.Applicative_infix - 151 mod Base.Applicative.Make3_using_map2.Applicative_infix - 155 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 161 mod Base.Applicative.Make_using_map2_local.Applicative_infix - 162 mod Base.Applicative.Make2_using_map2_local.Applicative_infix - 162 mod Base.Applicative.Make3_using_map2_local.Applicative_infix - 166 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 178 sig Base.Applicative.Basic_using_map2 - 178 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 179 sig Base.Applicative.Basic2_using_map2 - 179 sig Base.Applicative.Basic3_using_map2 - 189 sig Base.Applicative.Basic_using_map2_local - 189 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 190 sig Base.Applicative.Basic2_using_map2_local - 190 sig Base.Applicative.Basic3_using_map2_local - 226 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 177 mod Base.Applicative.Make_using_map2 + 178 mod Base.Applicative.Make2_using_map2 + 178 mod Base.Applicative.Make3_using_map2 + 188 mod Base.Applicative.Make_using_map2_local + 189 mod Base.Applicative.Make2_using_map2_local + 189 mod Base.Applicative.Make3_using_map2_local + 192 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 197 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 200 mod Base.Applicative.Make_using_map2.Applicative_infix + 201 mod Base.Applicative.Make2_using_map2.Applicative_infix + 201 mod Base.Applicative.Make3_using_map2.Applicative_infix + 205 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 211 mod Base.Applicative.Make_using_map2_local.Applicative_infix + 212 mod Base.Applicative.Make2_using_map2_local.Applicative_infix + 212 mod Base.Applicative.Make3_using_map2_local.Applicative_infix + 216 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 228 sig Base.Applicative.Basic_using_map2 + 228 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 229 sig Base.Applicative.Basic2_using_map2 + 229 sig Base.Applicative.Basic3_using_map2 + 239 sig Base.Applicative.Basic_using_map2_local + 239 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 240 sig Base.Applicative.Basic2_using_map2_local + 240 sig Base.Applicative.Basic3_using_map2_local + 276 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc search --print-cost --static-sort "List map2" - 127 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 223 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 240 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 242 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 244 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 177 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 273 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 290 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 292 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 294 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t $ sherlodoc search --print-cost "List map2" - 152 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 238 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 250 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 252 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 264 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 202 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 288 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 300 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 302 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 314 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t $ sherlodoc search --no-rhs "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group $ sherlodoc search --print-cost "list" - 81 type 'a Base.list = 'a List.t - 93 type 'a Base.Export.list = 'a List.t - 101 type 'a Base.List.t = 'a list - 104 mod Base.List - 104 mod Caml.List - 108 val Base.List.rev : 'a t -> 'a t - 109 val Base.List.hd_exn : 'a t -> 'a - 109 val Base.List.return : 'a -> 'a t - 110 val Base.Bytes.to_list : t -> char list - 111 val Base.List.join : 'a t t -> 'a t - 111 val Base.List.tl_exn : 'a t -> 'a t - 111 val Base.Queue.of_list : 'a list -> 'a t - 111 val Base.Stack.of_list : 'a list -> 'a t - 113 val Base.List.concat : 'a t t -> 'a t - 113 mod Shadow_stdlib.List - 114 val Base.List.last : 'a t -> 'a option - 114 val Base.Set.to_list : ('a, _) t -> 'a list - 115 mod Base.List.Assoc - 115 mod Base.List.Infix - 115 cons Base.Sexp.t.List : t list -> t - 115 val Base.List.ignore_m : 'a t -> unit t - 115 val Base.Bytes.of_char_list : char list -> t - 116 val Base.List.drop : 'a t -> int -> 'a t - 116 val Base.List.take : 'a t -> int -> 'a t - 117 val Base.List.nth_exn : 'a t -> int -> 'a + 131 type 'a Base.list = 'a List.t + 143 type 'a Base.Export.list = 'a List.t + 151 type 'a Base.List.t = 'a list + 154 mod Base.List + 154 mod Caml.List + 158 val Base.List.rev : 'a t -> 'a t + 159 val Base.List.hd_exn : 'a t -> 'a + 159 val Base.List.return : 'a -> 'a t + 160 val Base.Bytes.to_list : t -> char list + 161 val Base.List.join : 'a t t -> 'a t + 161 val Base.List.tl_exn : 'a t -> 'a t + 161 val Base.Queue.of_list : 'a list -> 'a t + 161 val Base.Stack.of_list : 'a list -> 'a t + 163 val Base.List.concat : 'a t t -> 'a t + 163 mod Shadow_stdlib.List + 164 val Base.List.last : 'a t -> 'a option + 164 val Base.Set.to_list : ('a, _) t -> 'a list + 165 mod Base.List.Assoc + 165 mod Base.List.Infix + 165 cons Base.Sexp.t.List : t list -> t + 165 val Base.List.ignore_m : 'a t -> unit t + 165 val Base.Bytes.of_char_list : char list -> t + 166 val Base.List.drop : 'a t -> int -> 'a t + 166 val Base.List.take : 'a t -> int -> 'a t + 167 val Base.List.nth_exn : 'a t -> int -> 'a $ sherlodoc search --print-cost ": list" - 118 val Base.List.rev : 'a t -> 'a t - 119 val Base.List.return : 'a -> 'a t - 120 val Base.Bytes.to_list : t -> char list - 121 val Base.List.join : 'a t t -> 'a t - 121 val Base.List.tl_exn : 'a t -> 'a t - 122 val Base.String.split_lines : t -> t list - 123 val Base.List.concat : 'a t t -> 'a t - 125 val Base.List.ignore_m : 'a t -> unit t - 125 val Base.String.to_list_rev : t -> char list - 128 val Base.Sequence.to_list_rev : 'a t -> 'a list - 130 val Base.Pretty_printer.all : unit -> string list - 132 val Base.List.all_unit : unit t list -> unit t - 132 val Base.List.filter_opt : 'a option t -> 'a t - 132 val Base.List.transpose_exn : 'a t t -> 'a t t - 132 val Base.List.concat_no_order : 'a t t -> 'a t - 149 val Base.Set.to_list : ('a, _) t -> 'a list - 150 val Base.Hashtbl.data : (_, 'b) t -> 'b list - 150 val Base.Set.elements : ('a, _) t -> 'a list - 151 val Base.List.drop : 'a t -> int -> 'a t - 151 val Base.List.take : 'a t -> int -> 'a t - 152 val Base.String.split : t -> on:char -> t list - 154 val Base.List.append : 'a t -> 'a t -> 'a t - 154 val Base.Hashtbl.keys : ('a, _) t -> 'a key list - 158 val Base.List.rev_append : 'a t -> 'a t -> 'a t - 161 val Base.List.intersperse : 'a t -> sep:'a -> 'a t + 168 val Base.List.rev : 'a t -> 'a t + 169 val Base.List.return : 'a -> 'a t + 170 val Base.Bytes.to_list : t -> char list + 171 val Base.List.join : 'a t t -> 'a t + 171 val Base.List.tl_exn : 'a t -> 'a t + 172 val Base.String.split_lines : t -> t list + 173 val Base.List.concat : 'a t t -> 'a t + 175 val Base.List.ignore_m : 'a t -> unit t + 175 val Base.String.to_list_rev : t -> char list + 178 val Base.Sequence.to_list_rev : 'a t -> 'a list + 180 val Base.Pretty_printer.all : unit -> string list + 182 val Base.List.all_unit : unit t list -> unit t + 182 val Base.List.filter_opt : 'a option t -> 'a t + 182 val Base.List.transpose_exn : 'a t t -> 'a t t + 182 val Base.List.concat_no_order : 'a t t -> 'a t + 199 val Base.Set.to_list : ('a, _) t -> 'a list + 200 val Base.Hashtbl.data : (_, 'b) t -> 'b list + 200 val Base.Set.elements : ('a, _) t -> 'a list + 201 val Base.List.drop : 'a t -> int -> 'a t + 201 val Base.List.take : 'a t -> int -> 'a t + 202 val Base.String.split : t -> on:char -> t list + 204 val Base.List.append : 'a t -> 'a t -> 'a t + 204 val Base.Hashtbl.keys : ('a, _) t -> 'a key list + 208 val Base.List.rev_append : 'a t -> 'a t -> 'a t + 211 val Base.List.intersperse : 'a t -> sep:'a -> 'a t Partial name search: $ sherlodoc search --print-cost "strin" - 97 type Base.string = String.t - 109 type Base.Export.string = String.t - 116 val Base.Sexp.of_string : unit - 117 type Base.String.t = string - 117 type Base.String.elt = char - 119 val Base.String.rev : t -> t - 121 mod Base.String - 121 mod Caml.String - 122 val Base.String.hash : t -> int - 122 val Base.Exn.to_string : t -> string - 122 val Base.Sys.max_string_length : int - 123 val Base.String.escaped : t -> t - 123 val Base.String.max_length : int - 124 val Base.String.(^) : t -> t -> t - 124 val Base.Float.to_string : t -> string - 125 mod Base.Stringable - 125 val Base.String.uppercase : t -> t - 126 type Base.String.Caseless.t = t - 126 val Base.String.capitalize : t -> t - 127 mod Base.StringLabels - 127 mod Caml.StringLabels - 127 val Base.String.append : t -> t -> t - 127 val Base.Exn.to_string_mach : t -> string - 127 val Base.Info.to_string_hum : t -> string - 127 val Base.Sign.to_string_hum : t -> string + 147 type Base.string = String.t + 159 type Base.Export.string = String.t + 166 val Base.Sexp.of_string : unit + 167 type Base.String.t = string + 167 type Base.String.elt = char + 169 val Base.String.rev : t -> t + 171 mod Base.String + 171 mod Caml.String + 172 val Base.String.hash : t -> int + 172 val Base.Exn.to_string : t -> string + 172 val Base.Sys.max_string_length : int + 173 val Base.String.escaped : t -> t + 173 val Base.String.max_length : int + 174 val Base.String.(^) : t -> t -> t + 174 val Base.Float.to_string : t -> string + 175 mod Base.Stringable + 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 $ sherlodoc search --print-cost "tring" - 127 type Base.string = String.t - 132 type Base.String.t = string - 132 type Base.String.elt = char - 134 val Base.String.rev : t -> t - 136 mod Base.String - 136 mod Caml.String - 136 val Base.Sexp.of_string : unit - 137 val Base.String.hash : t -> int - 138 val Base.String.escaped : t -> t - 138 val Base.String.max_length : int - 139 val Base.String.(^) : t -> t -> t - 139 type Base.Export.string = String.t - 140 val Base.String.uppercase : t -> t - 141 type Base.String.Caseless.t = t - 141 val Base.String.capitalize : t -> t - 142 val Base.Exn.to_string : t -> string - 142 val Base.String.append : t -> t -> t - 144 val Base.String.equal : t -> t -> bool - 144 val Base.String.prefix : t -> int -> t - 144 val Base.String.suffix : t -> int -> t - 144 val Base.Float.to_string : t -> string - 145 val Base.String.compare : t -> t -> int - 145 mod Shadow_stdlib.String - 147 val Base.String.ascending : t -> t -> int - 147 val Base.String.split_lines : t -> t list + 177 type Base.string = String.t + 182 type Base.String.t = string + 182 type Base.String.elt = char + 184 val Base.String.rev : t -> t + 186 mod Base.String + 186 mod Caml.String + 186 val Base.Sexp.of_string : unit + 187 val Base.String.hash : t -> int + 188 val Base.String.escaped : t -> t + 188 val Base.String.max_length : int + 189 val Base.String.(^) : t -> t -> t + 189 type Base.Export.string = String.t + 190 val Base.String.uppercase : t -> t + 191 type Base.String.Caseless.t = t + 191 val Base.String.capitalize : t -> t + 192 val Base.Exn.to_string : t -> string + 192 val Base.String.append : t -> t -> t + 194 val Base.String.equal : t -> t -> bool + 194 val Base.String.prefix : t -> int -> t + 194 val Base.String.suffix : t -> int -> t + 194 val Base.Float.to_string : t -> string + 195 val Base.String.compare : t -> t -> int + 195 mod Shadow_stdlib.String + 197 val Base.String.ascending : t -> t -> int + 197 val Base.String.split_lines : t -> t list diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index da3c8707df..93d2faf3da 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -13,8 +13,8 @@ val Main.multiple_hit_2 : foo val Main.multiple_hit_3 : foo $ sherlodoc search --print-cost "name_conflict" - 84 type Main.name_conflict = foo - 184 val Main.name_conflict : foo + 134 type Main.name_conflict = foo + 234 val Main.name_conflict : foo $ sherlodoc search "nesting_priority" val Main.nesting_priority : foo val Main.Nest.nesting_priority : foo diff --git a/test/cram/cli_small.t/run.t b/test/cram/cli_small.t/run.t index 22a28216c8..7b0b4aa341 100644 --- a/test/cram/cli_small.t/run.t +++ b/test/cram/cli_small.t/run.t @@ -5,10 +5,10 @@ $ export SHERLODOC_FORMAT=marshal $ sherlodoc index $(find . -name '*.odocl') $ sherlodoc search --print-cost "list" - 89 type 'a Main.list - 101 type 'a Main.List.t = 'a list - 104 mod Main.List - 209 val Main.List.empty : 'a t * 'b t - 222 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 139 type 'a Main.list + 151 type 'a Main.List.t = 'a list + 154 mod Main.List + 259 val Main.List.empty : 'a t * 'b t + 272 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t $ sherlodoc search ": (int, 'a) result" val Main.ok_zero : (int, 'a) result diff --git a/test/cram/favouritism.t b/test/cram/favouritism.t deleted file mode 100644 index d95e809dd9..0000000000 --- a/test/cram/favouritism.t +++ /dev/null @@ -1,140 +0,0 @@ - $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') - $ export SHERLODOC_DB=db.bin - $ export SHERLODOC_FORMAT=marshal - $ sherlodoc index $ODOCLS > /dev/null - $ sherlodoc search --print-cost "list" - 81 type 'a Base.list = 'a List.t - 93 type 'a Base.Export.list = 'a List.t - 101 type 'a Base.List.t = 'a list - 104 mod Base.List - 104 mod Caml.List - 108 val Base.List.rev : 'a t -> 'a t - 109 val Base.List.hd_exn : 'a t -> 'a - 109 val Base.List.return : 'a -> 'a t - 110 val Base.Bytes.to_list : t -> char list - 111 val Base.List.join : 'a t t -> 'a t - 111 val Base.List.tl_exn : 'a t -> 'a t - 111 val Base.Queue.of_list : 'a list -> 'a t - 111 val Base.Stack.of_list : 'a list -> 'a t - 113 val Base.List.concat : 'a t t -> 'a t - 113 mod Shadow_stdlib.List - 114 val Base.List.last : 'a t -> 'a option - 115 mod Base.List.Assoc - 115 mod Base.List.Infix - 115 cons Base.Sexp.t.List : t list -> t - 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 - $ sherlodoc index --favoured-prefixes=Base $ODOCLS > /dev/null - $ sherlodoc search --print-cost "list" - 31 type 'a Base.list = 'a List.t - 43 type 'a Base.Export.list = 'a List.t - 51 type 'a Base.List.t = 'a list - 54 mod Base.List - 58 val Base.List.rev : 'a t -> 'a t - 59 val Base.List.hd_exn : 'a t -> 'a - 59 val Base.List.return : 'a -> 'a t - 60 val Base.Bytes.to_list : t -> char list - 61 val Base.List.join : 'a t t -> 'a t - 61 val Base.List.tl_exn : 'a t -> 'a t - 61 val Base.Queue.of_list : 'a list -> 'a t - 61 val Base.Stack.of_list : 'a list -> 'a t - 63 val Base.List.concat : 'a t t -> 'a t - 64 val Base.List.last : 'a t -> 'a option - 65 mod Base.List.Assoc - 65 mod Base.List.Infix - 65 cons Base.Sexp.t.List : t list -> t - 65 val Base.List.ignore_m : 'a t -> unit t - 66 val Base.List.drop : 'a t -> int -> 'a t - 66 val Base.List.take : 'a t -> int -> 'a t - 75 mod Base.ListLabels - 294 mod Base - 297 type Base.Nothing.t = - 312 val Base.String.append : t -> t -> t - 314 val Base.Int.ascending : t -> t -> int - $ sherlodoc index --favoured-prefixes=Caml $ODOCLS > /dev/null - $ sherlodoc search --print-cost "list" - 54 mod Caml.List - 75 mod Caml.ListLabels - 81 type 'a Base.list = 'a List.t - 93 type 'a Base.Export.list = 'a List.t - 101 type 'a Base.List.t = 'a list - 104 mod Base.List - 108 val Base.List.rev : 'a t -> 'a t - 109 val Base.List.hd_exn : 'a t -> 'a - 109 val Base.List.return : 'a -> 'a t - 110 val Base.Bytes.to_list : t -> char list - 111 val Base.List.join : 'a t t -> 'a t - 111 val Base.List.tl_exn : 'a t -> 'a t - 111 val Base.Queue.of_list : 'a list -> 'a t - 111 val Base.Stack.of_list : 'a list -> 'a t - 113 val Base.List.concat : 'a t t -> 'a t - 113 mod Shadow_stdlib.List - 114 val Base.List.last : 'a t -> 'a option - 115 mod Base.List.Assoc - 115 mod Base.List.Infix - 115 cons Base.Sexp.t.List : t list -> t - 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 - $ sherlodoc index --favoured-prefixes=Base,Caml $ODOCLS > /dev/null - $ sherlodoc search --print-cost "list" - 31 type 'a Base.list = 'a List.t - 43 type 'a Base.Export.list = 'a List.t - 51 type 'a Base.List.t = 'a list - 54 mod Base.List - 54 mod Caml.List - 58 val Base.List.rev : 'a t -> 'a t - 59 val Base.List.hd_exn : 'a t -> 'a - 59 val Base.List.return : 'a -> 'a t - 60 val Base.Bytes.to_list : t -> char list - 61 val Base.List.join : 'a t t -> 'a t - 61 val Base.List.tl_exn : 'a t -> 'a t - 61 val Base.Queue.of_list : 'a list -> 'a t - 61 val Base.Stack.of_list : 'a list -> 'a t - 63 val Base.List.concat : 'a t t -> 'a t - 64 val Base.List.last : 'a t -> 'a option - 65 mod Base.List.Assoc - 65 mod Base.List.Infix - 65 cons Base.Sexp.t.List : t list -> t - 65 val Base.List.ignore_m : 'a t -> unit t - 66 val Base.List.drop : 'a t -> int -> 'a t - 66 val Base.List.take : 'a t -> int -> 'a t - 75 mod Base.ListLabels - 75 mod Caml.ListLabels - 294 mod Base - 297 type Base.Nothing.t = - $ sherlodoc index $ODOCLS --favoured-prefixes "" > /dev/null - $ sherlodoc search --print-cost "list" - 81 type 'a Base.list = 'a List.t - 93 type 'a Base.Export.list = 'a List.t - 101 type 'a Base.List.t = 'a list - 104 mod Base.List - 104 mod Caml.List - 108 val Base.List.rev : 'a t -> 'a t - 109 val Base.List.hd_exn : 'a t -> 'a - 109 val Base.List.return : 'a -> 'a t - 110 val Base.Bytes.to_list : t -> char list - 111 val Base.List.join : 'a t t -> 'a t - 111 val Base.List.tl_exn : 'a t -> 'a t - 111 val Base.Queue.of_list : 'a list -> 'a t - 111 val Base.Stack.of_list : 'a list -> 'a t - 113 val Base.List.concat : 'a t t -> 'a t - 113 mod Shadow_stdlib.List - 114 val Base.List.last : 'a t -> 'a option - 115 mod Base.List.Assoc - 115 mod Base.List.Infix - 115 cons Base.Sexp.t.List : t list -> t - 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 - -Partial name search: diff --git a/test/cram/module_type_cost.t/run.t b/test/cram/module_type_cost.t/run.t index 5be645e7fa..ef7069cedd 100644 --- a/test/cram/module_type_cost.t/run.t +++ b/test/cram/module_type_cost.t/run.t @@ -10,10 +10,10 @@ $ du -sh megaodocl Here we expect to have the `my_function` from the module be above the one from the module type. $ sherlodoc search --print-cost --no-rhs "my_function" - 196 val Main.M.my_function - 199 val Main.Make.my_function - 296 val Main.S.my_function + 246 val Main.M.my_function + 249 val Main.Make.my_function + 346 val Main.S.my_function Here we expect both the module type and the module to be ranked the same $ sherlodoc search --print-cost "module" - 116 mod Main.Module_nype - 166 sig Main.Module_type + 166 mod Main.Module_nype + 216 sig Main.Module_type diff --git a/test/cram/multi_package.t b/test/cram/multi_package.t index f93590e749..f8f5d5f7c4 100644 --- a/test/cram/multi_package.t +++ b/test/cram/multi_package.t @@ -5,140 +5,140 @@ $ export SHERLODOC_FORMAT=marshal $ sherlodoc index --index-docstring=false $ODOCLS > /dev/null $ sherlodoc search --print-cost --limit 100 "S_poly" - 150 sig Base.Map.S_poly - 150 sig Base.Set.S_poly - 154 sig Base.Hashtbl.S_poly - 198 type 'a Base.Hashtbl.S_poly.key = 'a - 207 type ('a, 'b) Base.Map.S_poly.t - 207 type 'elt Base.Set.S_poly.t - 209 type ('a, 'cmp) Base.Set.S_poly.set - 210 val Base.Set.S_poly.mem : 'a t -> 'a -> bool - 210 type ('a, 'b) Base.Map.S_poly.tree - 210 type 'elt Base.Set.S_poly.tree - 211 type ('a, 'b) Base.Hashtbl.S_poly.t - 211 mod Base.Set.S_poly.Named - 217 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list - 221 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list - 224 type Base.Map.S_poly.comparator_witness - 224 type Base.Set.S_poly.comparator_witness - 227 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t - 227 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b - 228 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b - 230 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option - 233 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option - 233 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list - 233 mod Base.Map.S_poly.Make_applicative_traversals - 236 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t - 237 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit - 237 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit - 239 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit - 239 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list - 241 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option - 250 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit - 250 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit - 250 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t - 251 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit - 251 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit - 252 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool - 253 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit - 254 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b - 255 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] - 256 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t - 257 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit - 257 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b - 259 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b - 260 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t - 261 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit - 269 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b - 270 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t - 273 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc - 274 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t - 274 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option - 280 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t - 294 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> + 200 sig Base.Map.S_poly + 200 sig Base.Set.S_poly + 204 sig Base.Hashtbl.S_poly + 248 type 'a Base.Hashtbl.S_poly.key = 'a + 257 type ('a, 'b) Base.Map.S_poly.t + 257 type 'elt Base.Set.S_poly.t + 259 type ('a, 'cmp) Base.Set.S_poly.set + 260 val Base.Set.S_poly.mem : 'a t -> 'a -> bool + 260 type ('a, 'b) Base.Map.S_poly.tree + 260 type 'elt Base.Set.S_poly.tree + 261 type ('a, 'b) Base.Hashtbl.S_poly.t + 261 mod Base.Set.S_poly.Named + 267 val Base.Hashtbl.S_poly.data : (_, 'b) t -> 'b list + 271 val Base.Hashtbl.S_poly.keys : ('a, _) t -> 'a key list + 274 type Base.Map.S_poly.comparator_witness + 274 type Base.Set.S_poly.comparator_witness + 277 val Base.Set.S_poly.map : ('a, _) set -> f:('a -> 'b) -> 'b t + 277 val Base.Hashtbl.S_poly.find_exn : ('a, 'b) t -> 'a key -> 'b + 278 val Base.Hashtbl.S_poly.choose_exn : ('a, 'b) t -> 'a key * 'b + 280 val Base.Hashtbl.S_poly.find : ('a, 'b) t -> 'a key -> 'b option + 283 val Base.Hashtbl.S_poly.choose : ('a, 'b) t -> ('a key * 'b) option + 283 val Base.Hashtbl.S_poly.to_alist : ('a, 'b) t -> ('a key * 'b) list + 283 mod Base.Map.S_poly.Make_applicative_traversals + 286 val Base.Hashtbl.S_poly.map : ('a, 'b) t -> f:('b -> 'c) -> ('a, 'c) t + 287 val Base.Hashtbl.S_poly.map_inplace : (_, 'b) t -> f:('b -> 'b) -> unit + 287 val Base.Hashtbl.S_poly.remove_multi : ('a, _ list) t -> 'a key -> unit + 289 val Base.Hashtbl.S_poly.set : ('a, 'b) t -> key:'a key -> data:'b -> unit + 289 val Base.Hashtbl.S_poly.find_multi : ('a, 'b list) t -> 'a key -> 'b list + 291 val Base.Hashtbl.S_poly.find_and_remove : ('a, 'b) t -> 'a key -> 'b option + 300 val Base.Hashtbl.S_poly.update : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> unit + 300 val Base.Hashtbl.S_poly.add_multi : ('a, 'b list) t -> key:'a key -> data:'b -> unit + 300 val Base.Hashtbl.S_poly.filter_map : ('a, 'b) t -> f:('b -> 'c option) -> ('a, 'c) t + 301 val Base.Hashtbl.S_poly.filter_map_inplace : (_, 'b) t -> f:('b -> 'b option) -> unit + 301 val Base.Hashtbl.S_poly.filter_keys_inplace : ('a, _) t -> f:('a key -> bool) -> unit + 302 val Base.Hashtbl.S_poly.equal : ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool + 303 val Base.Hashtbl.S_poly.iteri : ('a, 'b) t -> f:(key:'a key -> data:'b -> unit) -> unit + 304 val Base.Hashtbl.S_poly.find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b + 305 val Base.Hashtbl.S_poly.add : ('a, 'b) t -> key:'a key -> data:'b -> [ `Ok | `Duplicate ] + 306 val Base.Hashtbl.S_poly.mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c) -> ('a, 'c) t + 307 val Base.Hashtbl.S_poly.change : ('a, 'b) t -> 'a key -> f:('b option -> 'b option) -> unit + 307 val Base.Hashtbl.S_poly.findi_or_add : ('a, 'b) t -> 'a key -> default:('a key -> 'b) -> 'b + 309 val Base.Hashtbl.S_poly.update_and_return : ('a, 'b) t -> 'a key -> f:('b option -> 'b) -> 'b + 310 val Base.Hashtbl.S_poly.partition_tf : ('a, 'b) t -> f:('b -> bool) -> ('a, 'b) t * ('a, 'b) t + 311 val Base.Hashtbl.S_poly.incr : ?by:int -> ?remove_if_zero:bool -> ('a, int) t -> 'a key -> unit + 319 val Base.Hashtbl.S_poly.choose_randomly_exn : ?random_state:Random.State.t -> ('a, 'b) t -> 'a key * 'b + 320 val Base.Hashtbl.S_poly.filter_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> 'c option) -> ('a, 'c) t + 323 val Base.Hashtbl.S_poly.fold : ('a, 'b) t -> init:'acc -> f:(key:'a key -> data:'b -> 'acc -> 'acc) -> 'acc + 324 val Base.Hashtbl.S_poly.partition_map : ('a, 'b) t -> f:('b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t + 324 val Base.Hashtbl.S_poly.choose_randomly : ?random_state:Random.State.t -> ('a, 'b) t -> ('a key * 'b) option + 330 val Base.Hashtbl.S_poly.partitioni_tf : ('a, 'b) t -> f:(key:'a key -> data:'b -> bool) -> ('a, 'b) t * ('a, 'b) t + 344 val Base.Hashtbl.S_poly.find_and_call : ('a, 'b) t -> 'a key -> if_found:('b -> 'c) -> if_not_found:('a key -> 'c) -> 'c - 298 val Base.Set.S_poly.empty : 'a t - 298 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> + 348 val Base.Set.S_poly.empty : 'a t + 348 val Base.Hashtbl.S_poly.partition_mapi : ('a, 'b) t -> f:(key:'a key -> data:'b -> ('c, 'd) Either.t) -> ('a, 'c) t * ('a, 'd) t - 303 val Base.Map.S_poly.empty : ('k, _) t - 305 val Base.Set.S_poly.length : _ t -> int - 308 val Base.Set.S_poly.is_empty : _ t -> bool - 308 val Base.Set.S_poly.singleton : 'a -> 'a t - 309 val Base.Set.S_poly.choose_exn : 'a t -> 'a - 310 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t - 310 val Base.Map.S_poly.length : (_, _) t -> int - 310 val Base.Set.S_poly.max_elt_exn : 'a t -> 'a - 310 val Base.Set.S_poly.min_elt_exn : 'a t -> 'a - 311 val Base.Set.S_poly.of_list : 'a list -> 'a t - 311 val Base.Set.S_poly.of_tree : 'a tree -> 'a t - 311 val Base.Set.S_poly.to_list : 'a t -> 'a list - 311 val Base.Set.S_poly.to_tree : 'a t -> 'a tree - 311 val Base.Set.S_poly.invariants : 'a t -> bool - 312 val Base.Set.S_poly.choose : 'a t -> 'a option - 312 val Base.Set.S_poly.elements : 'a t -> 'a list - 312 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> + 353 val Base.Map.S_poly.empty : ('k, _) t + 355 val Base.Set.S_poly.length : _ t -> int + 358 val Base.Set.S_poly.is_empty : _ t -> bool + 358 val Base.Set.S_poly.singleton : 'a -> 'a t + 359 val Base.Set.S_poly.choose_exn : 'a t -> 'a + 360 val Base.Set.S_poly.add : 'a t -> 'a -> 'a t + 360 val Base.Map.S_poly.length : (_, _) t -> int + 360 val Base.Set.S_poly.max_elt_exn : 'a t -> 'a + 360 val Base.Set.S_poly.min_elt_exn : 'a t -> 'a + 361 val Base.Set.S_poly.of_list : 'a list -> 'a t + 361 val Base.Set.S_poly.of_tree : 'a tree -> 'a t + 361 val Base.Set.S_poly.to_list : 'a t -> 'a list + 361 val Base.Set.S_poly.to_tree : 'a t -> 'a tree + 361 val Base.Set.S_poly.invariants : 'a t -> bool + 362 val Base.Set.S_poly.choose : 'a t -> 'a option + 362 val Base.Set.S_poly.elements : 'a t -> 'a list + 362 val Base.Hashtbl.S_poly.merge_into : src:('k, 'a) t -> dst:('k, 'b) t -> f:(key:'k key -> 'a -> 'b option -> 'b Merge_into_action.t) -> unit - 313 val Base.Map.S_poly.data : (_, 'v) t -> 'v list - 313 val Base.Map.S_poly.keys : ('k, _) t -> 'k list - 313 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t - 313 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t - 313 val Base.Set.S_poly.max_elt : 'a t -> 'a option - 313 val Base.Set.S_poly.min_elt : 'a t -> 'a option - 313 val Base.Map.S_poly.is_empty : (_, _) t -> bool - 313 val Base.Set.S_poly.of_array : 'a array -> 'a t - 313 val Base.Set.S_poly.to_array : 'a t -> 'a array - 314 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool - 314 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t - 314 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t - 314 val Base.Hashtbl.S_poly.clear : (_, _) t -> unit - 314 val Base.Hashtbl.S_poly.length : (_, _) t -> int - 314 val Base.Hashtbl.S_poly.hashable : 'a Hashable.t - 315 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool - 316 val Base.Set.S_poly.nth : 'a t -> int -> 'a option - 316 val Base.Set.S_poly.union_list : 'a t list -> 'a t - 317 val Base.Map.S_poly.invariants : ('k, 'v) t -> bool - 317 val Base.Hashtbl.S_poly.is_empty : (_, _) t -> bool - 317 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> + 363 val Base.Map.S_poly.data : (_, 'v) t -> 'v list + 363 val Base.Map.S_poly.keys : ('k, _) t -> 'k list + 363 val Base.Set.S_poly.diff : 'a t -> 'a t -> 'a t + 363 val Base.Set.S_poly.remove : 'a t -> 'a -> 'a t + 363 val Base.Set.S_poly.max_elt : 'a t -> 'a option + 363 val Base.Set.S_poly.min_elt : 'a t -> 'a option + 363 val Base.Map.S_poly.is_empty : (_, _) t -> bool + 363 val Base.Set.S_poly.of_array : 'a array -> 'a t + 363 val Base.Set.S_poly.to_array : 'a t -> 'a array + 364 val Base.Set.S_poly.equal : 'a t -> 'a t -> bool + 364 val Base.Set.S_poly.inter : 'a t -> 'a t -> 'a t + 364 val Base.Set.S_poly.union : 'a t -> 'a t -> 'a t + 364 val Base.Hashtbl.S_poly.clear : (_, _) t -> unit + 364 val Base.Hashtbl.S_poly.length : (_, _) t -> int + 364 val Base.Hashtbl.S_poly.hashable : 'a Hashable.t + 365 val Base.Map.S_poly.mem : ('k, _) t -> 'k -> bool + 366 val Base.Set.S_poly.nth : 'a t -> int -> 'a option + 366 val Base.Set.S_poly.union_list : 'a t list -> 'a t + 367 val Base.Map.S_poly.invariants : ('k, 'v) t -> bool + 367 val Base.Hashtbl.S_poly.is_empty : (_, _) t -> bool + 367 val Base.Hashtbl.S_poly.find_and_call1 : ('a, 'b) t -> 'a key -> a:'d -> if_found:('b -> 'd -> 'c) -> if_not_found:('a key -> 'd -> 'c) -> 'c - 319 val Base.Map.S_poly.find_exn : ('k, 'v) t -> 'k -> 'v - 320 val Base.Map.S_poly.singleton : 'k -> 'v -> ('k, 'v) t - 320 val Base.Set.S_poly.remove_index : 'a t -> int -> 'a t - 321 val Base.Hashtbl.S_poly.copy : ('a, 'b) t -> ('a, 'b) t - 321 val Base.Map.S_poly.max_elt_exn : ('k, 'v) t -> 'k * 'v - 321 val Base.Map.S_poly.min_elt_exn : ('k, 'v) t -> 'k * 'v - 321 val Base.Set.S_poly.of_sequence : 'a Sequence.t -> 'a t - 321 val Base.Set.S_poly.are_disjoint : 'a t -> 'a t -> bool - 322 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int + 369 val Base.Map.S_poly.find_exn : ('k, 'v) t -> 'k -> 'v + 370 val Base.Map.S_poly.singleton : 'k -> 'v -> ('k, 'v) t + 370 val Base.Set.S_poly.remove_index : 'a t -> int -> 'a t + 371 val Base.Hashtbl.S_poly.copy : ('a, 'b) t -> ('a, 'b) t + 371 val Base.Map.S_poly.max_elt_exn : ('k, 'v) t -> 'k * 'v + 371 val Base.Map.S_poly.min_elt_exn : ('k, 'v) t -> 'k * 'v + 371 val Base.Set.S_poly.of_sequence : 'a Sequence.t -> 'a t + 371 val Base.Set.S_poly.are_disjoint : 'a t -> 'a t -> bool + 372 val Base.Set.S_poly.compare_direct : 'a t -> 'a t -> int $ sherlodoc search --print-cost --no-rhs "group b" - 181 val Base.Set.group_by - 205 val Base.List.group - 212 val Base.Sequence.group - 225 val Base.List.sort_and_group - 228 val Base.List.groupi - 235 val Base.List.Assoc.group - 255 val Base.List.Assoc.sort_and_group - 275 val Base.Set.Poly.group_by - 303 val Base.Set.Using_comparator.group_by - 313 val Base.Set.Using_comparator.Tree.group_by - 323 val Base.Hashtbl.group - 377 val Base.Set.S_poly.group_by - 412 val Base.Set.Accessors_generic.group_by - 423 val Base.Hashtbl.Poly.group - 425 val Base.Set.Creators_and_accessors_generic.group_by - 430 val Base.Hashtbl.Creators.group - 437 val Base.Hashtbl.Creators.group - 449 val Base.Hashtbl.S_without_submodules.group - 525 val Base.Hashtbl.S_poly.group + 231 val Base.Set.group_by + 255 val Base.List.group + 262 val Base.Sequence.group + 275 val Base.List.sort_and_group + 278 val Base.List.groupi + 285 val Base.List.Assoc.group + 305 val Base.List.Assoc.sort_and_group + 325 val Base.Set.Poly.group_by + 353 val Base.Set.Using_comparator.group_by + 363 val Base.Set.Using_comparator.Tree.group_by + 373 val Base.Hashtbl.group + 427 val Base.Set.S_poly.group_by + 462 val Base.Set.Accessors_generic.group_by + 473 val Base.Hashtbl.Poly.group + 475 val Base.Set.Creators_and_accessors_generic.group_by + 480 val Base.Hashtbl.Creators.group + 487 val Base.Hashtbl.Creators.group + 499 val Base.Hashtbl.S_without_submodules.group + 575 val Base.Hashtbl.S_poly.group $ sherlodoc search --no-rhs "group by" val Base.Set.group_by val Base.Set.Poly.group_by @@ -148,205 +148,205 @@ val Base.Set.Accessors_generic.group_by val Base.Set.Creators_and_accessors_generic.group_by $ sherlodoc search --print-cost "map2" - 127 mod Base.Applicative.Make_using_map2 - 128 mod Base.Applicative.Make2_using_map2 - 128 mod Base.Applicative.Make3_using_map2 - 138 mod Base.Applicative.Make_using_map2_local - 139 mod Base.Applicative.Make2_using_map2_local - 139 mod Base.Applicative.Make3_using_map2_local - 142 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 147 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 150 mod Base.Applicative.Make_using_map2.Applicative_infix - 151 mod Base.Applicative.Make2_using_map2.Applicative_infix - 151 mod Base.Applicative.Make3_using_map2.Applicative_infix - 155 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 161 mod Base.Applicative.Make_using_map2_local.Applicative_infix - 162 mod Base.Applicative.Make2_using_map2_local.Applicative_infix - 162 mod Base.Applicative.Make3_using_map2_local.Applicative_infix - 166 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 178 sig Base.Applicative.Basic_using_map2 - 178 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 179 sig Base.Applicative.Basic2_using_map2 - 179 sig Base.Applicative.Basic3_using_map2 - 189 sig Base.Applicative.Basic_using_map2_local - 189 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t - 190 sig Base.Applicative.Basic2_using_map2_local - 190 sig Base.Applicative.Basic3_using_map2_local - 226 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 177 mod Base.Applicative.Make_using_map2 + 178 mod Base.Applicative.Make2_using_map2 + 178 mod Base.Applicative.Make3_using_map2 + 188 mod Base.Applicative.Make_using_map2_local + 189 mod Base.Applicative.Make2_using_map2_local + 189 mod Base.Applicative.Make3_using_map2_local + 192 val Base.Uniform_array.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 197 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 200 mod Base.Applicative.Make_using_map2.Applicative_infix + 201 mod Base.Applicative.Make2_using_map2.Applicative_infix + 201 mod Base.Applicative.Make3_using_map2.Applicative_infix + 205 val Base.Applicative.Make_using_map2.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 211 mod Base.Applicative.Make_using_map2_local.Applicative_infix + 212 mod Base.Applicative.Make2_using_map2_local.Applicative_infix + 212 mod Base.Applicative.Make3_using_map2_local.Applicative_infix + 216 val Base.Applicative.Make_using_map2_local.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 228 sig Base.Applicative.Basic_using_map2 + 228 val Base.Applicative.Make_using_map2.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 229 sig Base.Applicative.Basic2_using_map2 + 229 sig Base.Applicative.Basic3_using_map2 + 239 sig Base.Applicative.Basic_using_map2_local + 239 val Base.Applicative.Make_using_map2_local.Applicative_infix.(<*>) : ('a -> 'b) X.t -> 'a X.t -> 'b X.t + 240 sig Base.Applicative.Basic2_using_map2_local + 240 sig Base.Applicative.Basic3_using_map2_local + 276 val Base.Option.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t $ sherlodoc search --print-cost --static-sort "List map2" - 127 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 223 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 240 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 242 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 244 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 177 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 273 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 290 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 292 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 294 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t $ sherlodoc search --print-cost "List map2" - 152 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 238 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 250 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t - 252 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t - 264 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 202 val Base.List.rev_map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 288 val Base.List.map2_exn : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 300 val Base.List.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t + 302 val Base.List.Cartesian_product.map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t + 314 val Base.List.rev_map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t Or_unequal_lengths.t $ sherlodoc search --no-rhs "Base.Hashtbl.S_without_submodules.group" val Base.Hashtbl.S_without_submodules.group $ sherlodoc search --print-cost "list" - 81 type 'a Base.list = 'a List.t - 93 type 'a Base.Export.list = 'a List.t - 101 type 'a Base.List.t = 'a list - 104 mod Base.List - 104 mod Caml.List - 108 val Base.List.rev : 'a t -> 'a t - 109 val Base.List.hd_exn : 'a t -> 'a - 109 val Base.List.return : 'a -> 'a t - 110 val Base.Bytes.to_list : t -> char list - 111 val Base.List.join : 'a t t -> 'a t - 111 val Base.List.tl_exn : 'a t -> 'a t - 111 val Base.Queue.of_list : 'a list -> 'a t - 111 val Base.Stack.of_list : 'a list -> 'a t - 113 val Base.List.concat : 'a t t -> 'a t - 113 mod Shadow_stdlib.List - 114 val Base.List.last : 'a t -> 'a option - 114 val Base.Set.to_list : ('a, _) t -> 'a list - 115 mod Base.List.Assoc - 115 mod Base.List.Infix - 115 cons Base.Sexp.t.List : t list -> t - 115 val Base.List.ignore_m : 'a t -> unit t - 115 val Base.Bytes.of_char_list : char list -> t - 116 val Base.List.drop : 'a t -> int -> 'a t - 116 val Base.List.take : 'a t -> int -> 'a t - 117 val Base.List.nth_exn : 'a t -> int -> 'a + 131 type 'a Base.list = 'a List.t + 143 type 'a Base.Export.list = 'a List.t + 151 type 'a Base.List.t = 'a list + 154 mod Base.List + 154 mod Caml.List + 158 val Base.List.rev : 'a t -> 'a t + 159 val Base.List.hd_exn : 'a t -> 'a + 159 val Base.List.return : 'a -> 'a t + 160 val Base.Bytes.to_list : t -> char list + 161 val Base.List.join : 'a t t -> 'a t + 161 val Base.List.tl_exn : 'a t -> 'a t + 161 val Base.Queue.of_list : 'a list -> 'a t + 161 val Base.Stack.of_list : 'a list -> 'a t + 163 val Base.List.concat : 'a t t -> 'a t + 163 mod Shadow_stdlib.List + 164 val Base.List.last : 'a t -> 'a option + 164 val Base.Set.to_list : ('a, _) t -> 'a list + 165 mod Base.List.Assoc + 165 mod Base.List.Infix + 165 cons Base.Sexp.t.List : t list -> t + 165 val Base.List.ignore_m : 'a t -> unit t + 165 val Base.Bytes.of_char_list : char list -> t + 166 val Base.List.drop : 'a t -> int -> 'a t + 166 val Base.List.take : 'a t -> int -> 'a t + 167 val Base.List.nth_exn : 'a t -> int -> 'a $ sherlodoc search --print-cost ": list" - 118 val Base.List.rev : 'a t -> 'a t - 119 val Base.List.return : 'a -> 'a t - 120 val Base.Bytes.to_list : t -> char list - 121 val Base.List.join : 'a t t -> 'a t - 121 val Base.List.tl_exn : 'a t -> 'a t - 122 val Base.String.split_lines : t -> t list - 123 val Base.List.concat : 'a t t -> 'a t - 125 val Base.List.ignore_m : 'a t -> unit t - 125 val Base.String.to_list_rev : t -> char list - 128 val Base.Sequence.to_list_rev : 'a t -> 'a list - 130 val Base.Pretty_printer.all : unit -> string list - 132 val Base.List.all_unit : unit t list -> unit t - 132 val Base.List.filter_opt : 'a option t -> 'a t - 132 val Base.List.transpose_exn : 'a t t -> 'a t t - 132 val Base.List.concat_no_order : 'a t t -> 'a t - 149 val Base.Set.to_list : ('a, _) t -> 'a list - 150 val Base.Hashtbl.data : (_, 'b) t -> 'b list - 150 val Base.Set.elements : ('a, _) t -> 'a list - 151 val Base.List.drop : 'a t -> int -> 'a t - 151 val Base.List.take : 'a t -> int -> 'a t - 152 val Base.String.split : t -> on:char -> t list - 154 val Base.List.append : 'a t -> 'a t -> 'a t - 154 val Base.Hashtbl.keys : ('a, _) t -> 'a key list - 158 val Base.List.rev_append : 'a t -> 'a t -> 'a t - 161 val Base.List.intersperse : 'a t -> sep:'a -> 'a t + 168 val Base.List.rev : 'a t -> 'a t + 169 val Base.List.return : 'a -> 'a t + 170 val Base.Bytes.to_list : t -> char list + 171 val Base.List.join : 'a t t -> 'a t + 171 val Base.List.tl_exn : 'a t -> 'a t + 172 val Base.String.split_lines : t -> t list + 173 val Base.List.concat : 'a t t -> 'a t + 175 val Base.List.ignore_m : 'a t -> unit t + 175 val Base.String.to_list_rev : t -> char list + 178 val Base.Sequence.to_list_rev : 'a t -> 'a list + 180 val Base.Pretty_printer.all : unit -> string list + 182 val Base.List.all_unit : unit t list -> unit t + 182 val Base.List.filter_opt : 'a option t -> 'a t + 182 val Base.List.transpose_exn : 'a t t -> 'a t t + 182 val Base.List.concat_no_order : 'a t t -> 'a t + 199 val Base.Set.to_list : ('a, _) t -> 'a list + 200 val Base.Hashtbl.data : (_, 'b) t -> 'b list + 200 val Base.Set.elements : ('a, _) t -> 'a list + 201 val Base.List.drop : 'a t -> int -> 'a t + 201 val Base.List.take : 'a t -> int -> 'a t + 202 val Base.String.split : t -> on:char -> t list + 204 val Base.List.append : 'a t -> 'a t -> 'a t + 204 val Base.Hashtbl.keys : ('a, _) t -> 'a key list + 208 val Base.List.rev_append : 'a t -> 'a t -> 'a t + 211 val Base.List.intersperse : 'a t -> sep:'a -> 'a t Partial name search: $ sherlodoc search --print-cost "strin" - 97 type Base.string = String.t - 109 type Base.Export.string = String.t - 116 val Base.Sexp.of_string : unit - 117 type Base.String.t = string - 117 type Base.String.elt = char - 119 val Base.String.rev : t -> t - 121 mod Base.String - 121 mod Caml.String - 122 val Base.String.hash : t -> int - 122 val Base.Exn.to_string : t -> string - 122 val Base.Sys.max_string_length : int - 123 val Base.String.escaped : t -> t - 123 val Base.String.max_length : int - 124 val Base.String.(^) : t -> t -> t - 124 val Base.Float.to_string : t -> string - 125 mod Base.Stringable - 125 val Base.String.uppercase : t -> t - 126 type Base.String.Caseless.t = t - 126 val Base.String.capitalize : t -> t - 127 mod Base.StringLabels - 127 mod Caml.StringLabels - 127 val Base.String.append : t -> t -> t - 127 val Base.Exn.to_string_mach : t -> string - 127 val Base.Info.to_string_hum : t -> string - 127 val Base.Sign.to_string_hum : t -> string + 147 type Base.string = String.t + 159 type Base.Export.string = String.t + 166 val Base.Sexp.of_string : unit + 167 type Base.String.t = string + 167 type Base.String.elt = char + 169 val Base.String.rev : t -> t + 171 mod Base.String + 171 mod Caml.String + 172 val Base.String.hash : t -> int + 172 val Base.Exn.to_string : t -> string + 172 val Base.Sys.max_string_length : int + 173 val Base.String.escaped : t -> t + 173 val Base.String.max_length : int + 174 val Base.String.(^) : t -> t -> t + 174 val Base.Float.to_string : t -> string + 175 mod Base.Stringable + 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 $ sherlodoc search --print-cost "base strin" - 112 type Base.string = String.t - 124 type Base.Export.string = String.t - 131 val Base.Sexp.of_string : unit - 132 type Base.String.t = string - 132 type Base.String.elt = char - 134 val Base.String.rev : t -> t - 136 mod Base.String - 137 val Base.String.hash : t -> int - 137 val Base.Exn.to_string : t -> string - 137 val Base.Sys.max_string_length : int - 138 val Base.String.escaped : t -> t - 138 val Base.String.max_length : int - 139 val Base.String.(^) : t -> t -> t - 139 val Base.Float.to_string : t -> string - 140 mod Base.Stringable - 140 val Base.String.uppercase : t -> t - 141 type Base.String.Caseless.t = t - 141 val Base.String.capitalize : t -> t - 142 mod Base.StringLabels - 142 val Base.String.append : t -> t -> t - 142 val Base.Exn.to_string_mach : t -> string - 142 val Base.Info.to_string_hum : t -> string - 142 val Base.Sign.to_string_hum : t -> string - 143 val Base.Error.to_string_hum : t -> string - 143 val Base.Info.to_string_mach : t -> string + 162 type Base.string = String.t + 174 type Base.Export.string = String.t + 181 val Base.Sexp.of_string : unit + 182 type Base.String.t = string + 182 type Base.String.elt = char + 184 val Base.String.rev : t -> t + 186 mod Base.String + 187 val Base.String.hash : t -> int + 187 val Base.Exn.to_string : t -> string + 187 val Base.Sys.max_string_length : int + 188 val Base.String.escaped : t -> t + 188 val Base.String.max_length : int + 189 val Base.String.(^) : t -> t -> t + 189 val Base.Float.to_string : t -> string + 190 mod Base.Stringable + 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 $ sherlodoc search --print-cost "tring" - 127 type Base.string = String.t - 132 type Base.String.t = string - 132 type Base.String.elt = char - 134 val Base.String.rev : t -> t - 136 mod Base.String - 136 mod Caml.String - 136 val Base.Sexp.of_string : unit - 137 val Base.String.hash : t -> int - 138 val Base.String.escaped : t -> t - 138 val Base.String.max_length : int - 139 val Base.String.(^) : t -> t -> t - 139 type Base.Export.string = String.t - 140 val Base.String.uppercase : t -> t - 141 type Base.String.Caseless.t = t - 141 val Base.String.capitalize : t -> t - 142 val Base.Exn.to_string : t -> string - 142 val Base.String.append : t -> t -> t - 144 val Base.String.equal : t -> t -> bool - 144 val Base.String.prefix : t -> int -> t - 144 val Base.String.suffix : t -> int -> t - 144 val Base.Float.to_string : t -> string - 145 val Base.String.compare : t -> t -> int - 145 mod Shadow_stdlib.String - 147 val Base.String.ascending : t -> t -> int - 147 val Base.String.split_lines : t -> t list + 177 type Base.string = String.t + 182 type Base.String.t = string + 182 type Base.String.elt = char + 184 val Base.String.rev : t -> t + 186 mod Base.String + 186 mod Caml.String + 186 val Base.Sexp.of_string : unit + 187 val Base.String.hash : t -> int + 188 val Base.String.escaped : t -> t + 188 val Base.String.max_length : int + 189 val Base.String.(^) : t -> t -> t + 189 type Base.Export.string = String.t + 190 val Base.String.uppercase : t -> t + 191 type Base.String.Caseless.t = t + 191 val Base.String.capitalize : t -> t + 192 val Base.Exn.to_string : t -> string + 192 val Base.String.append : t -> t -> t + 194 val Base.String.equal : t -> t -> bool + 194 val Base.String.prefix : t -> int -> t + 194 val Base.String.suffix : t -> int -> t + 194 val Base.Float.to_string : t -> string + 195 val Base.String.compare : t -> t -> int + 195 mod Shadow_stdlib.String + 197 val Base.String.ascending : t -> t -> int + 197 val Base.String.split_lines : t -> t list $ sherlodoc search --print-cost "base tring" - 142 type Base.string = String.t - 147 type Base.String.t = string - 147 type Base.String.elt = char - 149 val Base.String.rev : t -> t - 151 mod Base.String - 151 val Base.Sexp.of_string : unit - 152 val Base.String.hash : t -> int - 153 val Base.String.escaped : t -> t - 153 val Base.String.max_length : int - 154 val Base.String.(^) : t -> t -> t - 154 type Base.Export.string = String.t - 155 val Base.String.uppercase : t -> t - 156 type Base.String.Caseless.t = t - 156 val Base.String.capitalize : t -> t - 157 val Base.Exn.to_string : t -> string - 157 val Base.String.append : t -> t -> t - 159 val Base.String.equal : t -> t -> bool - 159 val Base.String.prefix : t -> int -> t - 159 val Base.String.suffix : t -> int -> t - 159 val Base.Float.to_string : t -> string - 160 val Base.String.compare : t -> t -> int - 162 val Base.String.ascending : t -> t -> int - 162 val Base.String.split_lines : t -> t list - 162 val Base.Sys.max_string_length : int - 164 val Base.String.common_prefix : t list -> t + 192 type Base.string = String.t + 197 type Base.String.t = string + 197 type Base.String.elt = char + 199 val Base.String.rev : t -> t + 201 mod Base.String + 201 val Base.Sexp.of_string : unit + 202 val Base.String.hash : t -> int + 203 val Base.String.escaped : t -> t + 203 val Base.String.max_length : int + 204 val Base.String.(^) : t -> t -> t + 204 type Base.Export.string = String.t + 205 val Base.String.uppercase : t -> t + 206 type Base.String.Caseless.t = t + 206 val Base.String.capitalize : t -> t + 207 val Base.Exn.to_string : t -> string + 207 val Base.String.append : t -> t -> t + 209 val Base.String.equal : t -> t -> bool + 209 val Base.String.prefix : t -> int -> t + 209 val Base.String.suffix : t -> int -> t + 209 val Base.Float.to_string : t -> string + 210 val Base.String.compare : t -> t -> int + 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 diff --git a/test/cram/odocl_favouritism.t/a.mli b/test/cram/odocl_favouritism.t/a.mli new file mode 100644 index 0000000000..076f4196bd --- /dev/null +++ b/test/cram/odocl_favouritism.t/a.mli @@ -0,0 +1 @@ +val unique_name : int diff --git a/test/cram/odocl_favouritism.t/b.mli b/test/cram/odocl_favouritism.t/b.mli new file mode 100644 index 0000000000..076f4196bd --- /dev/null +++ b/test/cram/odocl_favouritism.t/b.mli @@ -0,0 +1 @@ +val unique_name : int diff --git a/test/cram/odocl_favouritism.t/run.t b/test/cram/odocl_favouritism.t/run.t new file mode 100644 index 0000000000..50f766e4f7 --- /dev/null +++ b/test/cram/odocl_favouritism.t/run.t @@ -0,0 +1,25 @@ + $ ocamlc -c a.mli -bin-annot -I . + $ odoc compile -I . a.cmti + $ ocamlc -c b.mli -bin-annot -I . + $ odoc compile -I . b.cmti + $ odoc link -I . a.odoc + $ odoc link -I . b.odoc + + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=marshal + $ sherlodoc index a.odocl b.odocl + $ sherlodoc search --print-cost "unique_name" + 229 val A.unique_name : int + 229 val B.unique_name : int + $ sherlodoc index --favoured a.odocl b.odocl + $ sherlodoc search --print-cost "unique_name" + 179 val A.unique_name : int + 229 val B.unique_name : int + $ sherlodoc index a.odocl --favoured b.odocl + $ sherlodoc search --print-cost "unique_name" + 179 val B.unique_name : int + 229 val A.unique_name : int + $ sherlodoc index --favoured a.odocl --favoured b.odocl + $ sherlodoc search --print-cost "unique_name" + 179 val A.unique_name : int + 179 val B.unique_name : int diff --git a/test/cram/prefix_favouritism.t b/test/cram/prefix_favouritism.t new file mode 100644 index 0000000000..f9db8ed7a2 --- /dev/null +++ b/test/cram/prefix_favouritism.t @@ -0,0 +1,140 @@ + $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=marshal + $ sherlodoc index $ODOCLS > /dev/null + $ sherlodoc search --print-cost "list" + 131 type 'a Base.list = 'a List.t + 143 type 'a Base.Export.list = 'a List.t + 151 type 'a Base.List.t = 'a list + 154 mod Base.List + 154 mod Caml.List + 158 val Base.List.rev : 'a t -> 'a t + 159 val Base.List.hd_exn : 'a t -> 'a + 159 val Base.List.return : 'a -> 'a t + 160 val Base.Bytes.to_list : t -> char list + 161 val Base.List.join : 'a t t -> 'a t + 161 val Base.List.tl_exn : 'a t -> 'a t + 161 val Base.Queue.of_list : 'a list -> 'a t + 161 val Base.Stack.of_list : 'a list -> 'a t + 163 val Base.List.concat : 'a t t -> 'a t + 163 mod Shadow_stdlib.List + 164 val Base.List.last : 'a t -> 'a option + 165 mod Base.List.Assoc + 165 mod Base.List.Infix + 165 cons Base.Sexp.t.List : t list -> t + 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 + $ sherlodoc index --favoured-prefixes=Base $ODOCLS > /dev/null + $ sherlodoc search --print-cost "list" + 81 type 'a Base.list = 'a List.t + 93 type 'a Base.Export.list = 'a List.t + 101 type 'a Base.List.t = 'a list + 104 mod Base.List + 108 val Base.List.rev : 'a t -> 'a t + 109 val Base.List.hd_exn : 'a t -> 'a + 109 val Base.List.return : 'a -> 'a t + 110 val Base.Bytes.to_list : t -> char list + 111 val Base.List.join : 'a t t -> 'a t + 111 val Base.List.tl_exn : 'a t -> 'a t + 111 val Base.Queue.of_list : 'a list -> 'a t + 111 val Base.Stack.of_list : 'a list -> 'a t + 113 val Base.List.concat : 'a t t -> 'a t + 114 val Base.List.last : 'a t -> 'a option + 115 mod Base.List.Assoc + 115 mod Base.List.Infix + 115 cons Base.Sexp.t.List : t list -> t + 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 + $ sherlodoc index --favoured-prefixes=Caml $ODOCLS > /dev/null + $ sherlodoc search --print-cost "list" + 104 mod Caml.List + 125 mod Caml.ListLabels + 131 type 'a Base.list = 'a List.t + 143 type 'a Base.Export.list = 'a List.t + 151 type 'a Base.List.t = 'a list + 154 mod Base.List + 158 val Base.List.rev : 'a t -> 'a t + 159 val Base.List.hd_exn : 'a t -> 'a + 159 val Base.List.return : 'a -> 'a t + 160 val Base.Bytes.to_list : t -> char list + 161 val Base.List.join : 'a t t -> 'a t + 161 val Base.List.tl_exn : 'a t -> 'a t + 161 val Base.Queue.of_list : 'a list -> 'a t + 161 val Base.Stack.of_list : 'a list -> 'a t + 163 val Base.List.concat : 'a t t -> 'a t + 163 mod Shadow_stdlib.List + 164 val Base.List.last : 'a t -> 'a option + 165 mod Base.List.Assoc + 165 mod Base.List.Infix + 165 cons Base.Sexp.t.List : t list -> t + 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 + $ sherlodoc index --favoured-prefixes=Base,Caml $ODOCLS > /dev/null + $ sherlodoc search --print-cost "list" + 81 type 'a Base.list = 'a List.t + 93 type 'a Base.Export.list = 'a List.t + 101 type 'a Base.List.t = 'a list + 104 mod Base.List + 104 mod Caml.List + 108 val Base.List.rev : 'a t -> 'a t + 109 val Base.List.hd_exn : 'a t -> 'a + 109 val Base.List.return : 'a -> 'a t + 110 val Base.Bytes.to_list : t -> char list + 111 val Base.List.join : 'a t t -> 'a t + 111 val Base.List.tl_exn : 'a t -> 'a t + 111 val Base.Queue.of_list : 'a list -> 'a t + 111 val Base.Stack.of_list : 'a list -> 'a t + 113 val Base.List.concat : 'a t t -> 'a t + 114 val Base.List.last : 'a t -> 'a option + 115 mod Base.List.Assoc + 115 mod Base.List.Infix + 115 cons Base.Sexp.t.List : t list -> t + 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 = + $ sherlodoc index $ODOCLS --favoured-prefixes "" > /dev/null + $ sherlodoc search --print-cost "list" + 131 type 'a Base.list = 'a List.t + 143 type 'a Base.Export.list = 'a List.t + 151 type 'a Base.List.t = 'a list + 154 mod Base.List + 154 mod Caml.List + 158 val Base.List.rev : 'a t -> 'a t + 159 val Base.List.hd_exn : 'a t -> 'a + 159 val Base.List.return : 'a -> 'a t + 160 val Base.Bytes.to_list : t -> char list + 161 val Base.List.join : 'a t t -> 'a t + 161 val Base.List.tl_exn : 'a t -> 'a t + 161 val Base.Queue.of_list : 'a list -> 'a t + 161 val Base.Stack.of_list : 'a list -> 'a t + 163 val Base.List.concat : 'a t t -> 'a t + 163 mod Shadow_stdlib.List + 164 val Base.List.last : 'a t -> 'a option + 165 mod Base.List.Assoc + 165 mod Base.List.Infix + 165 cons Base.Sexp.t.List : t list -> t + 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 + +Partial name search: diff --git a/test/cram_ancient/cli_small.t/run.t b/test/cram_ancient/cli_small.t/run.t index b8545e0ed3..452edd9458 100644 --- a/test/cram_ancient/cli_small.t/run.t +++ b/test/cram_ancient/cli_small.t/run.t @@ -8,10 +8,10 @@ $ export SHERLODOC_FORMAT=ancient $ sherlodoc index $(find . -name '*.odocl') $ sherlodoc search --print-cost "list" - 89 type 'a Main.list - 101 type 'a Main.List.t = 'a list - 104 mod Main.List - 209 val Main.List.empty : 'a t * 'b t - 222 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 139 type 'a Main.list + 151 type 'a Main.List.t = 'a list + 154 mod Main.List + 259 val Main.List.empty : 'a t * 'b t + 272 val Main.List.map : ('a -> 'b) -> 'a t -> 'b t $ sherlodoc search ": (int, 'a) result" val Main.ok_zero : (int, 'a) result From 9b06e297f5ea18e7ef18d1a1d8ec33119eecae5e Mon Sep 17 00:00:00 2001 From: ArthurW Date: Fri, 2 Feb 2024 15:47:04 +0100 Subject: [PATCH 270/285] fix result version, thanks to opam CI lower bounds check --- dune-project | 1 + sherlodoc.opam | 1 + 2 files changed, 2 insertions(+) diff --git a/dune-project b/dune-project index 5acfe35684..6391a984b7 100644 --- a/dune-project +++ b/dune-project @@ -35,6 +35,7 @@ (menhir (>= 20230608)) (ppx_blob (>= 0.7.2)) (tyxml (>= 4.6.0)) + (result (>= 1.5)) (odig :with-test) (base (and :with-test (= v0.16.3))) (alcotest :with-test)) diff --git a/sherlodoc.opam b/sherlodoc.opam index 6bd90ee2a6..63134b8f76 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -21,6 +21,7 @@ depends: [ "menhir" {>= "20230608"} "ppx_blob" {>= "0.7.2"} "tyxml" {>= "4.6.0"} + "result" {>= "1.5"} "odig" {with-test} "base" {with-test & = "v0.16.3"} "alcotest" {with-test} From 67dd91f021f875def33f0468120804cbe2a532d0 Mon Sep 17 00:00:00 2001 From: ArthurW Date: Tue, 6 Feb 2024 11:41:22 +0100 Subject: [PATCH 271/285] prepare for release --- dune-project | 2 + installable_packages | 3668 ------------------------------------------ sherlodoc.opam | 1 + 3 files changed, 3 insertions(+), 3668 deletions(-) delete mode 100644 installable_packages diff --git a/dune-project b/dune-project index 6391a984b7..6b85aa6fc1 100644 --- a/dune-project +++ b/dune-project @@ -8,6 +8,8 @@ (name sherlodoc) +(version 0.2) + (source (github art-w/sherlodoc)) (authors "Arthur Wendling" "Emile Trotignon") diff --git a/installable_packages b/installable_packages deleted file mode 100644 index 2433070cdf..0000000000 --- a/installable_packages +++ /dev/null @@ -1,3668 +0,0 @@ -# Packages matching: installable -# Name # Installed # Synopsis -0install -- Decentralised installation system -0install-gtk -- Decentralised installation system - GTK UI -0install-solver -- Package dependency solver -ANSITerminal -- Basic control of ANSI compliant terminals and the windows shell -aacplus -- Bindings for the aacplus library which provides functions for decoding AAC audio files -abella -- Interactive theorem prover based on lambda-tree syntax -absolute 0.3 AbSolute solver -abstract_algebra -- A small library describing abstract algebra concepts -accessor v0.16.0 A library that makes it nicer to work with nested functional data structures -accessor_async -- Accessors for Async types, for use with the Accessor library -accessor_base -- Accessors for Base types, for use with the Accessor library -accessor_core -- Accessors for Core types, for use with the Accessor library -acgtk -- Abstract Categorial Grammar development toolkit -aches 1.0.0 Caches (bounded-size stores) for in-memory values and for resources -aches-lwt 1.0.0 Caches (bounded-size stores) for Lwt promises -acp4 1.0.1 ACP4: AutoCorrelation of Pharmacophore Features -acpc -- Chemoinformatics tool for ligand-based virtual screening -advi -- Active DVI Dune package! -aez -- Alt-Ergo Zero is an OCaml library for an SMT solver. -afl -- American Fuzzy Lop fuzzer by Michal Zalewski, repackaged for convenient use in opam -afl-persistent -- Use afl-fuzz in persistent mode -ago -- ago(1) - compute the number of days between two calendar dates -agrid -- Adjustable grid (two dimensional array) library -ahrocksdb -- A binding to RocksDB -aifad -- AIFAD - Automated Induction of Functions over Algebraic Datatypes -aio -- Linux kernel AIO access library for ocaml -alba -- Alba compiler -albatross -- Albatross - orchestrate and manage MirageOS unikernels with Solo5 -alcotest 1.7.0 Alcotest is a lightweight and colourful test framework -alcotest-async -- Async-based helpers for Alcotest -alcotest-js -- Virtual package containing optional JavaScript dependencies for Alcotest -alcotest-lwt -- Lwt-based helpers for Alcotest -alcotest-mirage -- Mirage implementation for Alcotest -alg_structs -- Interfaces and module combinators for algebraic structures -alg_structs_qcheck -- Provides qCheck generators for laws of alg_structs -aliases -- In memory indexes -alonzo -- STLC type system -alsa 0.3.0 Bindings for the ALSA library which provides functions for using soundcards -alt-ergo 2.5.2 The Alt-Ergo SMT prover -alt-ergo-free -- Alt-Ergo, an SMT Solver for Software Verification -alt-ergo-lib 2.5.2 The Alt-Ergo SMT prover library -alt-ergo-parsers 2.5.2 The Alt-Ergo SMT prover parser library -alt-ergo-plugin-ab-why3 -- An experimental Why3 frontend for Alt-Ergo -altgr-ergo -- The GUI for the Alt-Ergo SMT prover -ambient-context -- Abstraction over thread-local / continuation-local storage mechanisms for communication with transitive dependencies -ambient-context-lwt -- Storage backend for ambient-context using Lwt's sequence-associated storage -amqp-client -- Amqp client base library -amqp-client-async -- Amqp client library, async version -amqp-client-lwt -- Amqp client library, lwt version -ancient 0.9.1 Use data structures larger than available memory -anders -- Modal Homotopy Type System -angstrom 0.15.0 Parser combinators built for speed and memory-efficiency -angstrom-async -- Async support for Angstrom -angstrom-lwt-unix -- Lwt_unix support for Angstrom -angstrom-unix -- Unix support for Angstrom -ansi -- ANSI escape sequence parser -ansi-parse -- Ansiparse is a library for converting raw terminal output, replete with escape codes, into formatted HTML -ansicolor -- Simple ANSI terminal color library (deprecated in favor of ANSITerminal). -antic -- Stub of the C library Antic. Algebraic number -anycache -- Scan-resistant LRU/2Q cache -anycache-lwt -- Scan-resistant LRU/2Q cache -ao -- Bindings for the AO library which provides high-level functions for using soundcards -apron v0.9.14 APRON numerical abstract domain library -apronext 1.0.4 Apron extension -arb -- Stub of the C library Arb. Ball approximation -archetype -- Archetype language compiler -archi -- A library for managing the lifecycle of stateful components in OCaml -archi-async -- Async runtime for Archi, a library for managing the lifecycle of stateful components in OCaml -archi-lwt -- Lwt runtime for Archi, a library for managing the lifecycle of stateful components in OCaml -archimedes -- Extensible 2D plotting library. -archsat -- A first-order theorem prover with formal proof output -arg-complete -- Bash completion support for Stdlib.Arg -argon2 -- OCaml bindings to Argon2 -arp -- Address Resolution Protocol purely in OCaml -arp-mirage -- Address Resolution Protocol for MirageOS -arrakis 1.0.0 A RISC-V simulator -art 0.2.0 Adaptive Radix Tree -ascii85 -- ascii85 - Adobe's Ascii85 encoding as a module and a command line tool -asetmap 0.8.1 Alternative, compatible, OCaml standard library Sets and Maps -ask -- Create/Answer questionnaires -ask-integrator -- Link questionnaires to an uuid of 'a type -asl -- Bindings for the Apple System Log API -asli -- Interpreter for Arm's Architecture Specification Language (ASL) -asn1-combinators 0.2.6 Embed typed ASN.1 grammars in OCaml -assertions -- Basic assert statements -assimp -- OCaml bindings to Assimp, Open Asset Import Library -ast_generic -- Abstract Syntax Tree (AST) supporting 31 programming languages -astring 0.8.5 Alternative String module for OCaml -async v0.16.0 Monadic concurrency library -async-uri -- Open Async (TLS) TCP connections with Uri.t -async_durable -- Durable connections for use with async -async_extra -- Monadic concurrency library -async_find -- Directory traversal with Async -async_graphics -- Async wrapper for the OCaml Graphics library -async_inotify -- Async wrapper for inotify -async_interactive -- Utilities for building simple command-line based user interfaces -async_js -- A small library that provide Async support for JavaScript platforms -async_kernel v0.16.0 Monadic concurrency library -async_rpc_kernel v0.16.0 Platform-independent core of Async RPC library -async_rpc_websocket -- Library to serve and dispatch Async RPCs over websockets -async_sendfile -- Thin wrapper around [Linux_ext.sendfile] to send full files -async_shell -- Shell helpers for Async -async_smtp -- SMTP client and server -async_ssl -- An Async-pipe-based interface with OpenSSL -async_udp -- Monadic concurrency library -async_unix v0.16.0 Monadic concurrency library -async_websocket v0.16.0 A library that implements the websocket protocol on top of Async -atable -- Basic spreadsheet tool with HTML tables -atd -- Parser for the ATD data format description language -atd2cconv -- Convert ATD definitions to OCaml code that uses the CConv 0.1 library -atdd -- DLang code generation for ATD APIs -atdgen -- Generates efficient JSON serializers, deserializers and validators -atdgen-codec-runtime -- Runtime for atdgen generated bucklescript converters -atdgen-runtime -- Runtime library for code generated by atdgen -atdj -- Java code generation for ATD -atdpy -- Python/mypy code generation for ATD APIs -atds -- ATD Code generator for Scala -atdts -- TypeScript code generation for ATD APIs -atomic -- Compatibility package for OCaml's Atomic module starting from 4.12 -autofonce -- A modern runner for GNU Autoconf Testsuites -autofonce_config -- A modern runner for GNU Autoconf Testsuites -autofonce_core -- A modern runner for GNU Autoconf Testsuites -autofonce_lib -- A modern runner for GNU Autoconf Testsuites -autofonce_m4 -- A modern runner for GNU Autoconf Testsuites -autofonce_misc -- A modern runner for GNU Autoconf Testsuites -autofonce_patch -- A modern runner for GNU Autoconf Testsuites -autofonce_share -- A modern runner for GNU Autoconf Testsuites -avro -- Runtime library for encoding/decoding Avro -avro-compiler -- Schema compiler for Avro -awa -- SSH implementation in OCaml -awa-lwt -- SSH implementation in OCaml -awa-mirage -- SSH implementation in OCaml -aws -- Amazon Web Services SDK -aws-async -- Amazon Web Services SDK bindings for async -aws-autoscaling -- Amazon Web Services SDK bindings to Auto Scaling -aws-cloudformation -- Amazon Web Services SDK bindings to AWS CloudFormation -aws-cloudtrail -- Amazon Web Services SDK bindings to AWS CloudTrail -aws-cloudwatch -- Amazon Web Services SDK bindings to Amazon CloudWatch -aws-config -- Read AWS configuration in OCaml -aws-ec2 -- Amazon Web Services SDK bindings to Amazon Elastic Compute Cloud -aws-elasticache -- Amazon Web Services SDK bindings to Amazon ElastiCache -aws-elasticloadbalancing -- Amazon Web Services SDK bindings to Elastic Load Balancing -aws-lwt -- Amazon Web Services SDK bindings for lwt -aws-rds -- Amazon Web Services SDK bindings to Amazon Relational Database Service -aws-route53 -- Amazon Web Services SDK bindings to Amazon Route 53 -aws-s3 -- Ocaml library for accessing Amazon S3 -aws-s3-async -- Ocaml library for accessing Amazon S3 - Async version -aws-s3-lwt -- Ocaml library for accessing Amazon S3 - Lwt version -aws-sdb -- Amazon Web Services SDK bindings to Amazon SimpleDB -aws-sqs -- Amazon Web Services SDK bindings to Amazon Simple Queue Service -aws-ssm -- Amazon Web Services SDK bindings to Amazon Simple Systems Management Service -aws-sts -- Amazon Web Services SDK bindings to AWS Security Token Service -awsm -- AWS API base library -awsm-async -- AWS API base library Async -awsm-codegen -- AWS botocore code generator -awsm-lwt -- AWS API base library Lwt -azblob -- A trivial Azure Blob Storage interface for OCaml -azblob-async -- A trivial Azure Blob Storage interface for OCaml -azure-cosmos-db -- Azure cosmos db interface -BetterErrors -- Better compiler error output. -b0 0.0.5 Software construction and deployment kit -babel -- A library for defining Rpcs that can evolve over time without breaking backward compatibility. -backoff -- Exponential backoff mechanism for OCaml -bag -- Bags (aka multisets) -baguette_sharp -- The Baguette# Interpreter REPL -balancer -- A collection of load balancing algorithms implemented in pure Ocaml -bap -- Binary Analysis Platform -bap-abi -- BAP ABI integration subsystem -bap-analyze -- Implements the analyze command -bap-api -- A pass that adds parameters to subroutines based on known API -bap-arm -- BAP ARM lifter and disassembler -bap-beagle -- BAP obfuscated string solver -bap-beagle-strings -- Finds strings of characters using microexecution -bap-bil -- Controls the BIL transformation pipeline -bap-build -- BAP build automation tools -bap-bundle -- BAP bundler -bap-byteweight -- BAP facility for indentifying code entry points -bap-byteweight-frontend -- BAP Toolkit for training and controlling Byteweight algorithm -bap-c -- A C language support library for BAP -bap-cache -- BAP caching service -bap-callgraph-collator -- Collates programs based on their callgraphs -bap-callsites -- Inject data definition terms at callsites -bap-constant-tracker -- Constant Tracking Analysis based on Primus -bap-core -- Binary Analysis Platform -bap-core-theory -- BAP Semantics Representation -bap-cxxfilt -- A demangler that relies on a c++filt utility -bap-demangle -- Provides names service and demangling facilities -bap-dependencies -- Analyzes program dependencies -bap-disassemble -- Implements the disassemble command -bap-dump-symbols -- BAP plugin that dumps symbols information from a binary -bap-dwarf -- BAP DWARF parsing library -bap-elementary -- BAP floating point approximations of elementary functions -bap-elf -- BAP ELF parser and loader written in native OCaml -bap-emacs-dot -- Will automatically detect graph specifications in a dot syntax and display them using overlaying -bap-emacs-goodies -- A collection of useful Emacs tools for BAP -bap-emacs-mode -- Emacs major mode for reading and analyzing programs in BAP's IR -bap-extra -- Binary Analysis Platform -bap-flatten -- A BAP plugin, that translates a program into the flatten form -bap-frontc -- A C language frontend for based on FrontC library -bap-frontend -- BAP frontend -bap-future -- A library for asynchronous values -bap-ghidra -- BAP Ghidra backend -bap-glibc-runtime -- Detects the presence of glibc runtime -bap-ida-plugin -- Plugins for IDA and BAP integration -bap-knowledge -- Knowledge Representation Library -bap-llvm -- BAP LLVM backend -bap-main -- Build BAP Main Framework Configuration Library -bap-mc -- BAP machine instruction playground -bap-microx -- A micro execution framework -bap-mips -- BAP MIPS lifter -bap-objdump -- Extract symbols from binary, using binutils objdump -bap-optimization -- A BAP plugin that removes dead IR code -bap-patterns -- Applies semantic actions to the matching byte patterns -bap-phoenix -- BAP plugin that dumps information in a phoenix decompiler format -bap-piqi -- BAP plugin for serialization based on piqi library -bap-plugins -- BAP plugins support library -bap-powerpc -- BAP PowerPC lifter -bap-primus -- The BAP Microexecution Framework -bap-primus-dictionary -- BAP Primus Lisp library that provides dictionaries -bap-primus-exploring-scheduler -- Evaluates all machines, prioritizing the least visited -bap-primus-greedy-scheduler -- Evaluates all machines in the DFS order -bap-primus-limit -- Ensures termination by limiting Primus machines -bap-primus-lisp -- BAP Primus Lisp Runtime -bap-primus-loader -- Generic program loader for Primus -bap-primus-mark-visited -- Registers the bap:mark-visited component -bap-primus-powerpc -- Performs the PowerPC target specific setup -bap-primus-print -- Prints Primus states and observations -bap-primus-promiscuous -- Enables the promiscuous mode of execution -bap-primus-propagate-taint -- A compatibility layer between different taint analysis frameworks -bap-primus-random -- Provides components for Primus state randomization -bap-primus-region -- Provides a set of operations to store and manipulate interval trees -bap-primus-round-robin-scheduler -- Evaluates all machines in the BFS order -bap-primus-support -- Provides supporting components for Primus -bap-primus-symbolic-executor -- Primus Symbolic Executor -bap-primus-systems -- Loads Primus systems and registers them in the system repository -bap-primus-taint -- A taint analysis control interface -bap-primus-test -- BAP Primus Testing and Program Verification module -bap-primus-track-visited -- Tracks basic blocks visited by Primus -bap-primus-wandering-scheduler -- Evaluates all machines while -bap-primus-x86 -- The x86 CPU support package for BAP Primus CPU emulator -bap-print -- Print plugin - print project in various formats -bap-radare2 -- Extract symbols from binary using radare2 -bap-raw -- Provides a loader for raw binaries -bap-recipe -- Stores command line parameters and resources in a single file -bap-recipe-command -- Provides commands to manipulate the recipe subsystem -bap-relation -- A set of relations (bimap) -bap-relocatable -- Extracts symbolic information from the program relocations -bap-report -- A BAP plugin that reports program status -bap-riscv -- BAP RISCV lifter and disassembler -bap-run -- A BAP plugin that executes a binary -bap-signatures -- A data package with binary signatures for BAP -bap-specification -- Implements the specification command -bap-ssa -- A BAP plugin, that translates a program into the SSA form -bap-std -- The Binary Analysis Platform Standard Library -bap-strings -- Text utilities useful in Binary Analysis and Reverse Engineering -bap-stub-resolver -- Identifies and manages stub functions in a binary -bap-symbol-reader -- BAP plugin that reads symbol information from files -bap-systemz -- A target support package for the Systemz (Z9) ISA -bap-taint -- BAP Taint Analysis Framework -bap-taint-propagator -- BAP Taint propagation engine using based on microexecution -bap-term-mapper -- A BAP DSL for mapping program terms -bap-thumb -- A target support package for the Thumb instruction set -bap-toplevel -- BAP toplevel, baptop -bap-trace -- A plugin to load and run program execution traces -bap-traces -- BAP Library for loading and parsing execution traces -bap-trivial-condition-form -- Eliminates complex conditionals in branches -bap-warn-unused -- Emit a warning if an unused result may cause a bug or security issue -bap-x86 -- BAP x86 lifter -bare -- BAP Rule Engine Library -bare_encoding -- BARE encoding, see https://baremessages.org/ -bark -- Unofficial OCaml port of elm/parser (v1.1.0) -base v0.16.3 Full standard library replacement for OCaml -base-bigarray base -base-bytes base Bytes library distributed with the OCaml compiler -base-native-int63 -- Virtual package for enabling native int63 support in Base -base-threads base -base-unix base -base32 -- Base32 encoding for OCaml -base58 -- Base58 encoding and decoding -base64 3.5.1 Base64 encoding for OCaml -base_bigstring v0.16.0 String type based on [Bigarray], for use in I/O and C-bindings -base_quickcheck v0.16.0 Randomized testing framework, designed for compatibility with Base -base_trie -- Trie data structure library -bastet -- An OCaml library for category theory and abstract algebra -bastet_async -- Async implementations for bastet -bastet_lwt -- Lwt implementations for bastet -batch_jaro_winkler -- Fast batch jaro winkler distance implementation in C99 -batsat -- OCaml bindings for batsat, a SAT solver in rust -batteries 3.7.1 A community-maintained standard library extension -bdd -- Quick implementation of a Binary Decision Diagrams (BDD) library for OCaml -bddrand -- A simple front-end to the lutin Random toss machinary -bear -- Bare essential additions to the stdlib -bech32 -- Bech32 addresses for OCaml (see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) -bechamel -- Yet Another Benchmark in OCaml -bechamel-js -- HTML generator for bechamel's output -bechamel-notty -- CLI generator for bechamel's output -bechamel-perf -- Linux perf's metrics for bechamel -beluga -- Implementation of contextual modal logic for reasoning with higher-order abstract syntax -benchmark -- Benchmark running times of code -benchpress -- Tool to run one or more logic programs, on a set of files, and collect the results -benchpress-server -- Server and web UI for benchpress -bencode -- Bencode (`.torrent` file format) reader/writer in OCaml -bentov -- 1D histogram sketching -bestline -- OCaml bindings for the bestline C library -bheap 2.0.0 Priority queues -bibtex2html -- BibTeX to HTML translator -bidirectional_map -- A library for bidirectional maps and multimaps. -bigarray-compat 1.1.0 Compatibility library to use Stdlib.Bigarray when possible -bigarray-overlap 0.2.1 Bigarray.overlap -bigdecimal -- Arbitrary-precision decimal based on Zarith -bignum -- Core-flavoured wrapper around zarith's arbitrary-precision rationals -bigstring 0.3 A set of utils for dealing with `bigarrays` of `char` -bigstring-unix -- I/O functions for bigstrings using file descriptors and memory-maps -bigstringaf 0.9.1 Bigstring intrinsics and fast blits based on memcpy/memmove -bimage -- A simple, efficient image-processing library -bimage-display -- Window system for Bimage -bimage-gtk -- Bimage_gtk allows images to be displayed in GTK windows -bimage-io -- Input/output for Bimage using OpenImageIO -bimage-lwt -- A simple, efficient image-processing library (LWT bindings) -bimage-sdl -- Bimage_gtk allows images to be displayed using SDL -bimage-unix -- Bimage_unix provides methods for encoding/decoding images in many formats using ImageMagick/stb_image -bimap -- An OCaml library implementing bi-directional maps and multi-maps -bin_prot v0.16.0 A binary protocol generator -binaryen -- OCaml bindings for Binaryen -binaryen_dsl -- Writing Webassembly text format in DSL -binbin -- Convenient and human-readable bitmap manipulation -bindlib -- OCaml Bindlib library for bound variables -biniou -- Binary data format designed for speed, safety, ease of use and backward compatibility as protocols evolve -binning -- A datastructure to accumulate values in bins -binsec -- Semantic analysis of binary executables -bio_io -- A library for reading and writing common file formats used in bioinformatics like FASTA files -biocaml -- The OCaml Bioinformatics Library -biotk -- Bioinformatics toolkit -bip32 -- Hierarchical Deterministic Wallets -bisect -- Code coverage tool for the OCaml language (deprecated) -bisect_ppx -- Code coverage for OCaml -bisect_ppx-ocamlbuild -- Ocamlbuild plugin for Bisect_ppx, the coverage tool -bistro -- A library to build and run distributed scientific workflows -bistro-bio -- Bistro workflows for computational biology -bitcoin -- Bitcoin Client API logic-only -bitcoin-cohttp-async -- Bitcoin Client API cohttp-async interface -bitcoin-cohttp-lwt -- Bitcoin Client API cohttp-lwt interface -bitcoin-ocurl -- Bitcoin Client API ocurl interface -bitlib -- A library for writing binary files -bitmasks -- BitMasks over int and int64 exposed as sets -bitpack_serializer -- This library provides functions for encoding efficiently simple OCaml data -bitstring -- Bitstrings and bitstring matching for OCaml -bitv -- A bit vector library for OCaml -bitvec -- Fixed-size bitvectors and modular arithmetic, based on Zarith -bitvec-binprot -- Janestreet's Binprot serialization for Bitvec -bitvec-order -- Base style comparators and orders for Bitvec -bitvec-sexp -- Sexp serializers for Bitvec -bitwuzla -- SMT solver for AUFBVFP -bitwuzla-bin -- Bitwuzla SMT solver executable -bitwuzla-c -- SMT solver for AUFBVFP (C API) -bitwuzla-cxx -- SMT solver for AUFBVFP (C++ API) -bjack -- Bindings for the Jack library which provides functions for linking audio programs -blake2 -- Blake2 cryptography -blake3 -- Blake3 cryptography -bloomf -- Efficient Bloom filters for OCaml -bls12-381 18.0 Implementation of the BLS12-381 curve (wrapper for the Blst library) -bls12-381-gen -- Functors to generate BLS12-381 primitives based on stubs -bls12-381-hash -- Implementation of some cryptographic hash primitives using the scalar field of BLS12-381 -bls12-381-js -- JavaScript version of BLS12-381 primitives implementing the virtual package bls12-381 -bls12-381-js-gen -- Functors to generate BLS12-381 JavaScript primitives based on stubs -bls12-381-legacy -- UNIX version of BLS12-381 primitives. Not implementating the virtual package bls12-381 -bls12-381-signature -- Implementation of BLS signatures for the pairing-friendly curve BLS12-381 -bls12-381-unix -- UNIX version of BLS12-381 primitives implementing the virtual package bls12-381 with blst backend -blurhash -- A BlurHash encoder in OCaml -bn128 -- Barreto-Naehrig 128 Elliptic Curve pairing function library in OCAML -bnfgen -- Random text generator that takes context-free grammars from BNF files -bogue -- GUI library for ocaml, with animations, based on SDL2 -bogue-tutorials -- Bogue Tutorials -boltzgen -- Generate tests using boltzman sampling -bonsai -- A library for building dynamic webapps, using Js_of_ocaml -bookaml -- Library for retrieving information about published books -bos 0.2.1 Basic OS interaction for OCaml -boulangerie -- B# Package Manager -box -- Render boxes in the terminal -bpf -- Embedded eBPF assembler -bracetax -- Simple and deterministic text processing syntax -broken -- The Broken package is a simple testsuite framework. -brr 0.0.6 Browser programming toolkit for OCaml -brr-lwd -- Make reactive webpages in Js_of_ocaml using Brr and Lwd -bsdowl -- This collection of BSD Make directives aims at providing a highly -bst 7.0.1 Bisector tree implementation in OCaml -buffer-pool -- A pool of buffers which automatically increases in size as required -build_path_prefix_map -- An OCaml implementation of the BUILD_PATH_PREFIX_MAP specification -builder -- Scheduling and executing shell jobs -builder-web -- Web interface for builder -bun -- Simple management of afl-fuzz processes -bwd -- Backward lists -bwrap -- Use Bubblewrap to sandbox executables -bytearray -- Efficient marshaling to and from bigarrays -bytebuffer -- Extensible buffers built on top of bigarrays -ca-certs 0.2.3 Detect root CA certificates from the operating system -ca-certs-nss -- X.509 trust anchors extracted from Mozilla's NSS -cactus -- A B-Tree based index implementation -cairn -- A derivation explorer and logger for menhir parser -cairo2 -- Binding to Cairo, a 2D Vector Graphics Library -cairo2-gtk -- Rendering Cairo on Gtk2 canvas -cairo2-pango -- Interface between Cairo and Pango (for Gtk2) -caisar -- A platform for characterizing the safety and robustness of artificial intelligence based software -caisar-ir -- CAISAR's intermediate representation -caisar-nnet -- NNet parser for CAISAR -caisar-onnx -- ONNX parser for CAISAR -caisar-ovo -- OVO parser for CAISAR -caisar-xgboost -- XGBOOST parser for CAISAR -calcium -- Stub of the C library Antic. For exact computation with real and complex numbers, presently in early development -calculon -- Library for writing IRC bots in OCaml and a collection of plugins -calculon-redis -- A redis plugin for Calculon -calculon-redis-lib -- A library to interact with Calculon via Redis -calculon-web -- A collection of web plugins for Calculon -caldav -- A CalDAV server -calendar -- Library for handling dates and times in your program -calendars -- Convert dates between gregorian/julian/french/hebrew calendars -calipso -- Rewrites C programs to remove non-structured control-flow -callipyge -- Pure OCaml implementation of Curve25519 -camelot -- An OCaml Linter / Style Checker -camels -- A game about camels -camelsnakekebab -- A Ocaml library for word case conversion -caml-mode -- Caml mode for GNU Emacs -camlbz2 -- Bindings for bzip2 -camlgpc -- Interface to Alan Murta's General Polygon Clipper -camlidl 1.11 Stub code generator for OCaml -camlimages -- Image processing library -camlix -- Simple circuit breaker -camllib -- Utility Library (including various datatypes) -camlmix -- Camlmix is a generic preprocessor which converts text with embedded -camlon -- Caml Object Notion, parsing and printing OCaml like data expressions -camlp-streams 5.0.1 The Stream and Genlex libraries for use with Camlp4 and Camlp5 -camlp4 -- Camlp4 is a system for writing extensible parsers for programming languages -camlp5 -- Preprocessor-pretty-printer of OCaml -camlp5-buildscripts -- Camlp5 Build scripts (written in OCaml) -camlpdf -- Read, write and modify PDF files -camlprime -- Primality testing with lazy lists of prime numbers -camlrack -- S-Expression parsing for OCaml -camltc -- OCaml bindings for tokyo cabinet -camlzip 1.11 Accessing compressed files in ZIP, GZIP and JAR format -camomile -- A Unicode library -camyll -- A static site generator -canary -- Capture unhandled exceptions and automatically report them through various channels -capnp -- OCaml code generation plugin for the Cap'n Proto serialization framework -capnp-rpc -- Cap'n Proto is a capability-based RPC system with bindings for many languages -capnp-rpc-lwt -- Cap'n Proto is a capability-based RPC system with bindings for many languages -capnp-rpc-mirage -- Cap'n Proto is a capability-based RPC system with bindings for many languages -capnp-rpc-net -- Cap'n Proto is a capability-based RPC system with bindings for many languages -capnp-rpc-unix -- Cap'n Proto is a capability-based RPC system with bindings for many languages -captureio -- Capture output to Stderr and Stdout -caqti 1.9.0 Unified interface to relational database libraries -caqti-async -- Async support for Caqti -caqti-driver-mariadb -- MariaDB driver for Caqti using C bindings -caqti-driver-pgx -- PostgreSQL driver for Caqti based on the pure-OCaml PGX library -caqti-driver-postgresql -- PostgreSQL driver for Caqti based on C bindings -caqti-driver-sqlite3 -- Sqlite3 driver for Caqti using C bindings -caqti-dynload -- Dynamic linking of Caqti drivers using findlib.dynload -caqti-lwt 1.9.0 Lwt support for Caqti -caqti-mirage -- MirageOS support for Caqti -caqti-type-calendar -- Date and time field types using the calendar library -carray -- Contiguous arrays in OCaml -carton -- Implementation of PACKv2 file in OCaml -carton-git -- Implementation of PACK file in OCaml -carton-lwt -- Implementation of PACK file in OCaml -catala -- Compiler and library for the literate programming language for tax code specification -catapult -- Tracing system based on the Catapult/TEF format -catapult-client -- Network client for catapult, to be paired with catapult-daemon -catapult-daemon -- Daemon for reliable multi-process logging with catapult -catapult-file -- File logger for catapult -catapult-sqlite -- Sqlite-based backend for Catapult tracing -cb-check -- Json schema checker for current-bench -cbor -- CBOR encoder/decoder (RFC 7049) - native OCaml implementation -cborl -- CBOR library -cca -- A framework for differential source code analyses -ccbg -- Wallpaper utility for Wayland -cconv -- Combinators for Type Conversion in OCaml -cdrom -- Query the state and contents of CDROM devices under Linux -certify -- CLI utilities for simple X509 certificate manipulation -cf -- OCaml bindings to macOS CoreFoundation -cf-lwt -- Lwt interface to macOS CoreFoundation -cfg -- CFG - Context-Free Grammars -cfgen -- This package was renamed to bnfgen. -cfml -- The CFML program verification tool -cfstream -- Stream operations in the style of Core's API -cgi -- Library for writing CGIs -cgroups -- An OCaml interface for the Linux control groups -chacha -- The Chacha functions, in OCaml -chalk -- Composable and simple terminal highlighting package -chamelon -- Subset of littlefs filesystem fulfilling MirageOS KV -chamelon-unix -- Command-line Unix utilities for chamelon filesystems -chamo -- A kind of emacs-like editor, using OCaml instead of lisp -charInfo_width -- Determine column width for a character -charrua -- DHCP wire frame encoder and decoder -charrua-client -- DHCP client implementation -charrua-client-lwt -- A DHCP client using lwt as effectful layer -charrua-client-mirage -- A DHCP client for MirageOS -charrua-server -- DHCP server -charrua-unix -- Unix DHCP daemon -charset -- Fast char sets -chartjs -- OCaml bindings for Chart.js -chartjs-annotation -- OCaml bindigns for Chart.js annotation plugin -chartjs-colorschemes -- OCaml bindigns for Chart.js colorschemes plugin -chartjs-datalabels -- OCaml bindigns for Chart.js datalabels plugin -chartjs-streaming -- OCaml bindings for Chart.js streaming plugin -chase -- Model finder for geometric theories using the chase -checkseum 0.5.2 Adler-32, CRC32 and CRC32-C implementation in C and OCaml -choice -- Choice monad, for easy backtracking -chrome-trace 3.11.1 Chrome trace event generation library -cid -- Content-addressed Identifiers -cinaps -- Trivial metaprogramming tool -clangml -- OCaml bindings for Clang API -clangml-transforms -- Code transformers for clangml -clap -- Command-Line Argument Parsing, imperative style with a consumption mechanism -clarity-lang -- Clarity smart contract parser and AST -class_group_vdf 0.0.4 Verifiable Delay Functions bindings to Chia's VDF -clim -- Command Line Interface Maker -cloudi -- OCaml CloudI API -clp_operations -- A Clp domain -clz -- Compression support for cohttp-lwt client using decompress -cmark -- OCaml bindings for the CMark Common Markdown parsing and rendering library. -cmarker -- Bindings for a local installation of CMark -cmarkit -- CommonMark parser and renderer for OCaml -cmdliner 1.2.0 Declarative definition of command line interfaces for OCaml -cmdliner-stdlib -- A collection of cmdliner terms to control OCaml runtime parameters -cmdtui -- Interactive command completion and execution for building REPLs -cmdtui-lambda-term -- Interactive command completion and execution for building REPLs -cmitomli -- Converts compiled interface files (.cmi) into source interface files (.mli) -cmon -- A library for printing OCaml values with sharing -coccinelle -- Coccinelle is a C source code matching and transformation engine -codept -- Alternative ocaml dependency analyzer -cohttp 5.3.0 An OCaml library for HTTP clients and servers -cohttp-async -- CoHTTP implementation for the Async concurrency library -cohttp-curl -- Shared code between the individual cohttp-curl clients -cohttp-curl-async -- Cohttp client using Curl & Async as the backend -cohttp-curl-lwt -- Cohttp client using Curl & Lwt as the backend -cohttp-lwt 5.3.0 CoHTTP implementation using the Lwt concurrency library -cohttp-lwt-jsoo -- CoHTTP implementation for the Js_of_ocaml JavaScript compiler -cohttp-lwt-unix 5.3.0 CoHTTP implementation for Unix and Windows using Lwt -cohttp-mirage -- CoHTTP implementation for the MirageOS unikernel -cohttp-server-lwt-unix -- Lightweight Cohttp + Lwt based HTTP server -cohttp-top -- CoHTTP toplevel pretty printers for HTTP types -cohttp_async_websocket -- Websocket library for use with cohttp and async -cohttp_static_handler -- A library for easily creating a cohttp handler for static files -coin -- Mapper of KOI8-{U,R} to Unicode -colibri2 -- A CP solver for smtlib -colibrics -- A CP solver proved in Why3 -colibrilib -- A library of domains and propagators proved in Why3 -colombe -- SMTP protocol in OCaml -color -- -color-brewery -- Offer colors palettes and functions to brew colors -combinaml -- Simple, customizable, dependency free parser combinator library -combinat -- Fast combinatorics for OCaml -combine -- Combine is a library for combinatorics problem solving. -comby -- A tool for structural code search and replace that supports ~every language -comby-kernel -- A match engine for structural code search and replace that supports ~every language -comby-semantic -- A match engine for structural code search and replace that supports ~every language -command_rpc -- Utilities for Versioned RPC communication with a child process over stdin and stdout -commons -- Yet another set of common utilities -conan -- Identify type of your file (such as the MIME type) -conan-cli -- Identify type of your file (such as the MIME type) -conan-database -- A database of decision trees to recognize MIME type -conan-lwt -- Identify type of your file (such as the MIME type) -conan-unix -- Identify type of your file (such as the MIME type) -conduit 6.2.0 A network connection establishment library -conduit-async -- A network connection establishment library for Async -conduit-lwt 6.2.0 A portable network connection establishment library using Lwt -conduit-lwt-unix 6.2.0 A network connection establishment library for Lwt_unix -conduit-mirage -- A network connection establishment library for MirageOS -conex -- Establishing trust in community repositories -conex-mirage-crypto -- Establishing trust in community repositories: crypto provided via mirage-crypto -conex-nocrypto -- Establishing trust in community repositories: crypto provided via nocrypto -conf-aclocal -- Virtual package relying on aclocal -conf-adwaita-icon-theme -- Virtual package relying on adwaita-icon-theme -conf-alsa 1 Virtual package relying on alsa -conf-antic -- Virtual package relying on a Antic lib system installation -conf-ao -- Virtual package relying on libao -conf-arb -- Virtual package relying on a Arb lib system installation -conf-asciidoc -- Virtual package relying on asciidoc -conf-assimp -- Check if assimp (Open Asset Import Library) is installed -conf-autoconf 0.1 Virtual package relying on autoconf installation -conf-automake -- Virtual package relying on GNU automake -conf-bap-llvm -- Checks that supported version of LLVM is installed -conf-bash -- Virtual package to install the Bash shell -conf-binutils -- Checks that binutils are installed -conf-bison -- Virtual package relying on GNU bison -conf-blas -- Virtual package for BLAS configuration -conf-bluetooth -- Virtual package for Bluetooth library -conf-bmake -- Virtual package relying on a BSD Make compatible program -conf-boost -- Virtual package relying on boost -conf-brotli -- Virtual package relying on a brotli system installation -conf-c++ -- Virtual package relying on the c++ compiler -conf-cairo -- Virtual package relying on a Cairo system installation -conf-calcium -- Virtual package relying on a Calcium lib system installation -conf-capnproto -- Virtual package relying on captnproto installation -conf-clang -- Virtual package relying on clang -conf-clang-format -- Virtual package relying on clang-format -conf-cmake 1 Virtual package relying on cmake -conf-cosmopolitan -- Virtual package relying on APE/Cosmopolitan -conf-cpio -- Virtual package relying on cpio -conf-csdp -- Virtual package relying on a CSDP binary system installation -conf-dbm -- Virtual package relying on gdbm -conf-diffutils -- Virtual package relying on diffutils -conf-dpkg -- Virtual package relying on dpkg -conf-dssi -- Virtual package relying on dssi -conf-efl -- Virtual package relying on the EFL system installation -conf-emacs -- Virtual package to install the Emacs editor -conf-env-travis -- Detect Travis CI and lift its environment to opam -conf-expat -- Virtual package relying on an expat system installation -conf-faad -- Virtual package relying on libfaad -conf-fdkaac -- Virtual package relying on fdk-aac -conf-ffmpeg -- Virtual package relying on FFmpeg -conf-fftw3 -- Virtual package relying on a FFTW3 lib system installation -conf-findutils -- Virtual package relying on findutils -conf-flex -- Virtual package relying on GNU flex -conf-flint -- Virtual package relying on a Flint lib system installation -conf-freetype -- Virtual package relying on a freetype lib system installation -conf-frei0r -- Virtual package relying on frei0r -conf-fswatch -- Virtual package relying on libfswatch installation -conf-ftgl -- Virtual package relying on an ftgl system installation -conf-fts -- Virtual package relying on the fts.h header -conf-g++ 1.0 Virtual package relying on the g++ compiler (for C++) -conf-gcc -- Virtual package relying on the gcc compiler (for C) -conf-gd -- Virtual package relying on a libgd system installation -conf-gfortran -- Virtual package relying on a gfortran system installation -conf-ghostscript -- Virtual package relying on ghostscript -conf-git -- Virtual package relying on git -conf-glade -- Virtual package relying on a libglade system installation -conf-gles2 -- Virtual package relying on a OpenGL ES 2 system installation -conf-glew -- Virtual package relying on a GLEW system installation -conf-glfw3 -- Virtual package relying on a GLFW3 system installation -conf-glib-2 -- Virtual package relying on a system GLib 2 installation -conf-glpk -- Virtual package for GLPK (GNU Linear Programming Kit) -conf-gmp 4 Virtual package relying on a GMP lib system installation -conf-gmp-powm-sec 3 Virtual package relying on a GMP lib with constant-time modular exponentiation -conf-gnome-icon-theme3 -- Virtual package relying on gnome-icon-theme -conf-gnuplot -- Virtual package relying on gnuplot installation -conf-gnutls -- Virtual package relying on a gnutls system installation -conf-gobject-introspection -- Virtual package relying on a system gobject-introspection installation -conf-goocanvas2 -- Virtual package relying on a Goocanvas-2 system installation -conf-gpiod -- C libgpiod library for GPIO on recent (>4.8) Linux kernels -conf-graphviz -- Virtual package relying on graphviz installation -conf-gsl -- Virtual package relying on a GSL lib system installation -conf-gssapi -- Virtual package relying on a krb5-gssapi system installation -conf-gstreamer -- Virtual package relying on libgstreamer -conf-gtk2 -- Virtual package relying on gtk2 -conf-gtk3 -- Virtual package relying on GTK+ 3 -conf-gtksourceview -- Virtual package relying on a GtkSourceView system installation -conf-gtksourceview3 -- Virtual package relying on a GtkSourceView-3 system installation -conf-guile -- Virtual package relying on an GNU Guile system installation -conf-haveged -- Check if havaged is installed on the system -conf-hidapi 0 Virtual package relying on a hidapi system installation -conf-ida -- Checks that IDA Pro is installed -conf-jack -- Virtual package relying on jack -conf-jq -- Virtual package relying on jq -conf-ladspa -- Virtual package relying on ladspa -conf-lame -- Virtual package relying on lame -conf-lapack -- Virtual package for LAPACK configuration -conf-leveldb -- Virtual package relying on a LevelDB lib system installation -conf-libargon2 -- Virtual package relying on libargon2 -conf-libbz2 -- Virtual package relying on libbz2 -conf-libclang -- Virtual package relying on the installation of llvm and clang libraries (<= 15.0.x) -conf-libcurl -- Virtual package relying on a libcurl system installation -conf-libdw -- Virtual package relying on libdw -conf-libev 4-12 High-performance event loop/event model with lots of features -conf-libevent -- Virtual package relying on libevent -conf-libffi 2.0.0 Virtual package relying on libffi system installation -conf-libflac -- Virtual package relying on libFLAC -conf-libfontconfig -- Virtual package relying on fontconfig -conf-libfuse -- Virtual package relying on FUSE -conf-libgif -- Virtual package relying on a libgif system installation -conf-libgsasl -- Virtual package relying on a GSASL lib system installation -conf-libjpeg -- Virtual package relying on a libjpeg system installation -conf-liblinear-tools -- Virtual package relying on liblinear-{train|predict} installation -conf-liblo -- Virtual package relying on liblo -conf-liblz4 -- Virtual package relying on liblz4 system installation -conf-liblzma -- Virtual package relying on liblzma -conf-libMagickCore -- Virtual package relying on an ImageMagick system installation -conf-libmagic -- Virtual package relying on a libmagic system installation -conf-libmaxminddb -- Virtual package relying on a libmaxminddb system installation -conf-libmosquitto -- Virtual package relying on a libmosquitto system installation -conf-libmpg123 -- Virtual package relying on libmpg123 -conf-libnl3 -- Virtual package relying on a libnl system installation -conf-libogg -- Virtual package relying on libogg -conf-libopus -- Virtual package relying on libopus -conf-libpcre -- Virtual package relying on a libpcre system installation -conf-libpcre2-8 -- Virtual package relying on a libpcre2 system installation -conf-libpng -- Virtual package relying on a libpng system installation -conf-libportmidi -- Virtual package relying on libportmidi -conf-librsvg2 -- Virtual package relying on Librsvg2 system installation -conf-libsamplerate -- Virtual package relying on libsamplerate -conf-libseccomp -- Virtual package relying on a libseccomp system installation -conf-libsodium -- Virtual package relying on a libsodium system installation -conf-libspeex -- Virtual package relying on libspeex -conf-libssl 4 Virtual package relying on an OpenSSL library system installation -conf-libsvm -- Virtual package relying on libsvm library installation -conf-libsvm-tools -- Virtual package relying on libsvm-tools installation -conf-libtheora -- Virtual package relying on libtheora -conf-libtool -- Virtual package relying on libtool installation -conf-libudev -- Virtual package relying on a libudev system installation -conf-libuv -- Virtual package relying on a libuv system installation -conf-libvorbis -- Virtual package relying on libvorbis -conf-libwayland -- Virtual package relying on libwayland -conf-libX11 -- Virtual package relying on an Xlib system installation -conf-libxcb -- Virtual package relying on xcb -conf-libxcb-image -- Virtual package relying on xcb-image -conf-libxcb-keysyms -- Virtual package relying on xcb-shm -conf-libxcb-shm -- Virtual package relying on xcb-shm -conf-libxcb-xkb -- Virtual package relying on xcb-xkb -conf-libxcursor -- Virtual package relying on an libXcursor system installation -conf-libxi -- Virtual package relying on an libXi system installation -conf-libxinerama -- Virtual package relying on an libXinerama system installation -conf-libxrandr -- Virtual package relying on an libXRandR system installation -conf-lilv -- Virtual package relying on lilv -conf-linux-libc-dev -- Virtual package relying on the installation of the Linux kernel headers files -conf-lldb -- Virtual package to check the availability of LLDB 3.5 development packages -conf-llvm -- Virtual package relying on llvm library installation -conf-lua -- Virtual package relying on a Lua system installation -conf-lz4 -- Virtual package requiring the lz4 command to be available -conf-m4 -- Virtual package relying on m4 -conf-mad -- Virtual package relying on mad -conf-mariadb -- Virtual package relying on a libmariadbclient system installation -conf-mbedtls -- Virtual package relying on an mbedtls system installation -conf-mecab -- Virtual package relying on MeCab library installation -conf-mesa -- Virtual package relying on an mesa system installation -conf-mpfr 3 Virtual package relying on library MPFR installation -conf-mpi -- Virtual package relying on a mpi system installation -conf-mysql -- Virtual package relying on a libmysqlclient system installation -conf-nanomsg -- Virtual package relying on a nanomsg system installation -conf-nauty -- Virtual package relying on nauty -conf-ncurses -- Virtual package relying on ncurses -conf-neko -- Virtual package relying on a Neko system installation -conf-netsnmp -- Package relying on net-snmp libs -conf-nlopt -- Virtual package relying on nlopt -conf-nmap -- Virtual package relying on nmap installation -conf-npm -- Virtual package relying on npm installation -conf-numa -- Package relying on libnuma -conf-ode -- Virtual package relying on a ODE system installation -conf-oniguruma -- Virtual package relying on an Oniguruma system installation -conf-openbabel -- Virtual package relying on openbabel library installation -conf-openblas -- Virtual package to install OpenBLAS and LAPACKE -conf-opencc0 -- Virtual package relying on opencc v0 (libopencc.so.1) installation -conf-opencc1 -- Virtual package relying on opencc v1 (libopencc.so.2) installation -conf-opencc1_1 -- Virtual package relying on opencc v1.1 (libopencc.so.1.1) installation -conf-openimageio -- Virtual package relying on OpenImageIO development package installation -conf-openjdk -- Virtual package relying on OpenJDK / Javac -conf-openssl -- Virtual package relying on an OpenSSL binary system installation -conf-pam -- Virtual package relying on a system installation of PAM -conf-pandoc -- Virtual package relying on pandoc installation -conf-pango -- Virtual package relying on a Pango system installation -conf-perl 2 Virtual package relying on perl -conf-perl-ipc-system-simple -- Virtual package relying on perl's IPC::System::Simple -conf-perl-string-shellquote -- Virtual package relying on perl's String::ShellQuote -conf-pixz -- Virtual package relying on pixz -conf-pkg-config 3 Check if pkg-config is installed and create an opam switch local pkgconfig folder -conf-plplot -- Virtual package relying on plplot -conf-portaudio -- Virtual package relying on portaudio -conf-postgresql -- Virtual package relying on a PostgreSQL system installation -conf-ppl -- Virtual package relying on the Parma Polyhedra Library (PPL) system installation -conf-protoc -- Virtual package to install protoc compiler -conf-pulseaudio -- Virtual package relying on pulseaudio -conf-python-2-7 -- Virtual package relying on Python-2.7 installation -conf-python-2-7-dev -- Virtual package relying on Python-2.7 development package installation -conf-python-3 -- Virtual package relying on Python-3 installation -conf-python-3-7 -- Virtual package relying on Python >=3.7 installation -conf-python-3-dev -- Virtual package relying on Python 3 development package installation -conf-python3-yaml -- Virtual package relying on PyYAML -conf-qt -- Installation of Qt5 using APT packages or from source -conf-r -- Virtual package relying on the R interpreter -conf-r-mathlib -- Virtual package relying on a system installation of R Standalone Mathlib -conf-radare2 -- Checks that radare2 is installed -conf-rdkit -- Virtual package relying on rdkit library installation -conf-readline -- Virtual package relying on a readline system installation -conf-rocksdb -- Virtual package relying on a system installation of RocksDB -conf-ruby -- Virtual package relying on Ruby -conf-rust 0.1 Virtual package relying on cargo (rust build system) -conf-rust-2018 -- Virtual package relying on cargo (rust build system) -conf-rust-2021 1 Virtual package relying on cargo (rust build system) -conf-samplerate -- Virtual package relying on samplerate -conf-sdl-gfx -- Virtual package relying on a sdl-gfx system installation -conf-sdl-image -- Virtual package relying on a sdl-image system installation -conf-sdl-mixer -- Virtual package relying on a sdl-mixer system installation -conf-sdl-net -- Virtual package relying on a sdl-net system installation -conf-sdl-ttf -- Virtual package relying on a sdl-ttf system installation -conf-sdl2 1 Virtual package relying on a SDL2 system installation -conf-sdl2-image -- Virtual package relying on a sdl2-image system installation -conf-sdl2-mixer -- Virtual package relying on a sdl2-mixer system installation -conf-sdl2-net -- Virtual package relying on a sdl2-net system installation -conf-sdl2-ttf -- Virtual package relying on a sdl2-ttf system installation -conf-sdpa -- Virtual package relying on a SDPA binary system installation -conf-secp256k1 -- Virtual package relying on a secp256k1 lib system installation -conf-sfml2 -- Virtual package relying on a SFML2 system installation -conf-shine -- Virtual package relying on libshine -conf-snappy -- Virtual package relying on snappy -conf-soundtouch -- Virtual package relying on soundtouch -conf-sqlite3 -- Virtual package relying on an SQLite3 system installation -conf-srt -- Virtual package relying on srt -conf-srt-gnutls -- Virtual package relying on srt build with gnutls -conf-srt-openssl -- Virtual package relying on srt compiled with openssl -conf-sundials -- Virtual package relying on sundials -conf-swi-prolog -- Virtual package to install the swi-prolog interpreter -conf-taglib -- Virtual package relying on taglib -conf-tcl -- Virtual package relying on tcl -conf-texlive -- Virtual package relying on texlive / pdflatex -conf-tidy -- Virtual package relying on libtidy installation -conf-time -- Virtual package relying on the "time" command -conf-timeout -- Virtual package relying on the "timeout" command -conf-tk -- Virtual package relying on tk -conf-tree-sitter -- Check if tree-sitter is installed -conf-trexio -- Virtual package relying on trexio library installation -conf-tzdata -- Virtual package relying on tzdata -conf-unwind -- Virtual package relying on libunwind -conf-vim -- Virtual package to install the Vim editor -conf-wayland-protocols -- Virtual package relying on wayland-protocols -conf-wget -- Virtual package relying on wget -conf-which 1 Virtual package relying on which -conf-wxwidgets -- Virtual package to check the availability of wxWidgets 3.0 development packages -conf-xen -- Virtual package relying on Xen headers -conf-xkbcommon -- Virtual package relying on xkbcommon -conf-xxhash -- Virtual package relying on a xxhash system installation -conf-zig -- Virtual package relying on zig -conf-zlib 1 Virtual package relying on zlib -conf-zmq -- Virtual package relying on zmq library installation -conf-zstd -- Virtual package relying on zstd -confero -- Unicode Collation -config-file -- A library used to manage configuration files -configuration -- Analyse configuration files -conformist -- Conformist allows you to define schemas to decode, validate and sanitize input data declaratively -conjury -- Conjury library for OMake -containers -- A modular, clean and powerful extension of the OCaml standard library -containers-data -- A set of advanced datatypes for containers -containers-thread -- An extension of containers for threading -content_security_policy -- A library for building content-security policies -cookie -- Cookie handling for OCaml and ReasonML -cookies -- HTTP cookies library for OCaml -coq -- The Coq Proof Assistant -coq-core -- The Coq Proof Assistant -- Core Binaries and Tools -coq-lsp -- Language Server Protocol native server for Coq -coq-native -- Package flag enabling coq's native-compiler flag -coq-of-ocaml -- Compile a subset of OCaml to Coq -coq-serapi -- Serialization library and protocol for machine interaction with the Coq proof assistant -coq-shell -- Simplified OPAM shell for Coq -coq-stdlib -- The Coq Proof Assistant -- Standard Library -coq-waterproof -- Coq proofs in a style that resembles non-mechanized mathematical proofs -coqide -- The Coq Proof Assistant --- GTK3 IDE -coqide-server -- The Coq Proof Assistant, XML protocol server -cordova -- Binding OCaml to cordova Javascript object. -cordova-plugin-activity-indicator -- Binding OCaml to cordova-plugin-activity-indicator using gen_js_api. -cordova-plugin-background-mode -- Binding to cordova-plugin-background-mode using gen_js_api. -cordova-plugin-barcode-scanner -- Binding OCaml to cordova-plugin-barcode-scanner using gen_js_api. -cordova-plugin-battery-status -- Binding OCaml to cordova-plugin-battery-status using gen_js_api. -cordova-plugin-camera -- Binding OCaml to cordova-plugin-camera using gen_js_api. -cordova-plugin-clipboard -- Binding OCaml to cordova-plugin-clipboard using gen_js_api. -cordova-plugin-device -- Binding OCaml to cordova-plugin-device using gen_js_api. -cordova-plugin-device-orientation -- Binding OCaml to cordova-plugin-device-orientation using gen_js_api. -cordova-plugin-dialogs -- Binding OCaml to cordova-plugin-dialogs using gen_js_api. -cordova-plugin-email-composer -- Binding OCaml to cordova-plugin-email-composer using gen_js_api. -cordova-plugin-fcm -- Binding OCaml to cordova-plugin-fcm using gen_js_api. -cordova-plugin-file -- Binding OCaml to cordova-plugin-file using gen_js_api. -cordova-plugin-file-opener -- Binding OCaml to cordova-plugin-file-opener using gen_js_api. -cordova-plugin-file-transfer -- Binding OCaml to cordova-plugin-file-transfer using gen_js_api. -cordova-plugin-geolocation -- Binding OCaml to cordova-plugin-geolocation using gen_js_api. -cordova-plugin-image-picker -- Binding OCaml to cordova-plugin-image-picker using gen_js_api. -cordova-plugin-inappbrowser -- Binding OCaml to cordova-plugin-inappbrowser using gen_js_api. -cordova-plugin-insomnia -- Binding OCaml to cordova-plugin-insomnia using gen_js_api. -cordova-plugin-keyboard -- Binding OCaml to cordova-plugin-keyboard using gen_js_api. -cordova-plugin-loading-spinner -- Binding OCaml to cordova-plugin-loading-spinner using gen_js_api. -cordova-plugin-local-notifications -- Binding to cordova-plugin-local-notifications using gen_js_api. -cordova-plugin-media -- Binding OCaml to cordova-plugin-media using gen_js_api. -cordova-plugin-media-capture -- Binding OCaml to cordova-plugin-media-capture using gen_js_api. -cordova-plugin-network-information -- Binding OCaml to cordova-plugin-network-information using gen_js_api. -cordova-plugin-progress -- Binding OCaml to cordova-plugin-progress using gen_js_api. -cordova-plugin-push-notifications -- Binding OCaml to phonegap-plugin-push using gen_js_api. -cordova-plugin-qrscanner -- Binding OCaml to cordova-plugin-qrscanner using gen_js_api. -cordova-plugin-screen-orientation -- Binding OCaml to cordova-plugin-screen-orientation using gen_js_api. -cordova-plugin-sim-card -- Binding OCaml to cordova-plugin-sim-card using gen_js_api. -cordova-plugin-sms -- Binding OCaml to cordova-plugin-sms using gen_js_api. -cordova-plugin-social-sharing -- Binding OCaml to cordova-plugin-x-socialsharing using gen_js_api. -cordova-plugin-statusbar -- Binding OCaml to cordova-plugin-statusbar using gen_js_api. -cordova-plugin-toast -- Binding OCaml to cordova-plugin-toast using gen_js_api. -cordova-plugin-touch-id -- Binding OCaml to cordova-plugin-touch-id using gen_js_api. -cordova-plugin-vibration -- Binding OCaml to cordova-plugin-vibration using gen_js_api. -cordova-plugin-videoplayer -- Binding OCaml to cordova-plugin-videoplayer using gen_js_api. -core v0.16.2 Industrial strength alternative to OCaml's standard library -core-and-more -- Includes core, and some more useful extensions -core_bench -- Benchmarking library -core_compat -- Compatibility for core 0.14 -core_extended -- Extra components that are not as closely vetted or as stable as Core -core_kernel v0.16.0 Industrial strength alternative to OCaml's standard library -core_profiler -- Profiling library -core_unix v0.16.0 Unix-specific portions of Core -corecount -- Get count of cores on machine -cosovo -- An OCaml library parsing CSV files -cow -- Caml on the Web -cpdf -- High-level PDF tools based on CamlPDF -cpm 12.2.0 The Classification and Regression Performance Metrics library -cppffigen -- A C++ foreign-function-interface generator for Ocaml based on C++ STL Containers -cppo 1.6.9 Code preprocessor like cpp for OCaml -cppo_ocamlbuild -- Plugin to use cppo with ocamlbuild -cps_toolbox -- A partial OCaml standard library replacement written with continuation passing style in mind -cpu 2.0.0 Pin current process to given core number -cpuid -- Detect CPU features -craml -- A CRAM-testing framework for testing command line applications -crc -- CRC implementation supporting strings and cstructs -crdt-ml -- CRDTs - Conflict-Free Replicated Data Types for OCaml -crlibm -- Binding to CRlibm, a correctly rounded math lib -crontab -- Interacting with cron from OCaml -crowbar -- Write tests, let a fuzzer find failing cases -crunch -- Convert a filesystem into a static OCaml module -cry -- OCaml client for the various icecast & shoutcast source protocols -crypt -- Tiny binding for the unix crypt function -cryptodbm -- Encrypted layer over the dbm library: access to serverless, key-value databases with symmetric encryption. -cryptohash -- hash functions for OCaml -cryptokit 1.16.1 A library of cryptographic primitives -cryptoverif -- CryptoVerif: Cryptographic protocol verifier in the computational model -csexp 1.5.2 Parsing and printing of S-expressions in Canonical form -css -- CSS parser and printer -css-parser -- A CSS parser written in OCaml -cstruct 6.2.0 Access C-like structures directly from OCaml -cstruct-async -- Access C-like structures directly from OCaml -cstruct-lwt 6.2.0 Access C-like structures directly from OCaml -cstruct-sexp -- S-expression serialisers for C-like structures -cstruct-unix -- Access C-like structures directly from OCaml -csv -- A pure OCaml library to read and write CSV files -csv-lwt -- A pure OCaml library to read and write CSV files, LWT version -csvfields -- Runtime support for ppx_xml_conv and ppx_csv_conv_deprecated -csvtool -- Command line tool for handling CSV files -ctoxml -- Parses a C program into Cabs AST and dumps as an XML document -ctypes 0.20.2 Combinators for binding to C libraries without writing any C -ctypes-build -- Support for building Ctypes bindings. -ctypes-foreign 0.18.0 Virtual package for enabling the ctypes.foreign subpackage -ctypes-zarith -- Ctypes wrapper for zarith -ctypes_stubs_js 0.1 Js_of_ocaml Javascript stubs for the OCaml ctypes library -cubicle -- SMT based model checker for parameterized systems -cucumber -- Cucumber BDD for OCaml -cudf -- CUDF library (part of the Mancoosi tools) -cue_sheet_maker -- A library to create cuesheet -cuid -- CUID generator for OCaml. -cumulus -- Differential FRP based on the React library -curly -- Curly is a brain dead wrapper around the curl command line utility -current -- Pipeline language for keeping things up-to-date -current-albatross-deployer -- An ocurrent plugin to deploy MirageOS unikernels -current-web-pipelines -- Simplify the creation of pipeline websites -current_ansi -- ANSI escape sequence parser -current_docker -- OCurrent Docker plugin -current_examples -- Example pipelines for OCurrent -current_git -- Git plugin for OCurrent -current_github -- GitHub plugin for OCurrent -current_gitlab -- GitLab plugin for OCurrent -current_incr -- Self-adjusting computations -current_ocluster -- OCurrent plugin for OCluster builds -current_rpc -- Cap'n Proto RPC plugin for OCurrent -current_slack -- Slack plugin for OCurrent -current_ssh -- SSH plugin for OCurrent -current_web -- Test web UI for OCurrent -curses -- Bindings to ncurses -curve-sampling -- Sampling of parametric and implicit curves -cviode -- Contact variational integrators - native ocaml version -DAGaml -- DAGaml : Abstract DAG manipulation in OCaml -DkSDKFFIOCaml_Std -- DkSDK FFI for OCaml -DkSDKFFIOCaml_StdExport-linux_x86_64 -- The DkSDKFFIOCaml_StdExport foreign library on 64-bit Intel/AMD Linux -daft -- DAFT Allows File Transfers -dap -- Debug adapter protocol -data-encoding 0.7.1 Library of JSON and binary encoding combinators -datakit-server -- A library to write Datakit servers -datakit-server-9p -- Build Datakit servers using the 9P filesystem protocol -datalog -- An in-memory datalog implementation for OCaml -dates_calc -- A date calculation library -daypack-lib -- A schedule, time and time slots handling library -dbf -- DBF format parsing -dbm -- Binding to the NDBM/GDBM Unix "databases" -deadlock -- Frama-C plugin for deadlock detection -debian-formats -- Parse debian files -decimal -- Arbitrary-precision floating-point decimal library -decoders -- Elm-inspired decoders for Ocaml -decoders-bencode -- Bencode backend for decoders -decoders-cbor -- CBOR backend for decoders -decoders-ezjsonm -- Ezjsonm backend for decoders -decoders-ezxmlm -- Ezxmlm backend for decoders -decoders-jsonaf -- Jsonaf backend for decoders -decoders-jsonm -- Jsonm backend for decoders -decoders-msgpck -- Msgpck backend for decoders -decoders-sexplib -- Sexplib backend for decoders -decoders-yojson -- Yojson backend for decoders -decompress 1.5.3 Implementation of Zlib and GZip in OCaml -dedent -- A library for improving redability of multi-line string constants in code. -dedukti -- An implementation of The Lambda-Pi Modulo Theory -delimcc -- Oleg's delimited continuations library for byte-code and native OCaml -delimited_parsing -- Parsing of character (e.g., comma) separated and fixed-width values -depgraph -- dot graphs out of ocamldep output -depyt -- Yet-an-other type combinator library -deriving -- Extension to OCaml for deriving functions from type declarations -devkit -- Development kit - general purpose library -diet -- Discrete Interval Encoding Trees -diffable -- An interface for diffs. -digestif 1.1.4 Hashes implementations (SHA*, RIPEMD160, BLAKE2* and MD5) -directories -- An OCaml library that provides configuration, cache and data paths (and more!) following the suitable conventions on Linux, macOS and Windows -dirsift -- Search for directories by type -dirsp-exchange -- Published protocols for the authenticated message exchange -dirsp-exchange-kbb2017 -- The formally verified KBB2017 protocol for 1-on-1 secure conversations similar to the Signal Protocol -dirsp-proscript -- OCaml-ified interfaces for the ProScript Cryptography Library -dirsp-proscript-mirage -- Mirage crypto backed implementation of the ProScript Cryptography Library -dirsp-ps2ocaml -- ProScript to OCaml translator -diskuvbox -- Cross-platform basic set of script commands -dispatch -- Path-based dispatching for client- and server-side applications -dispatch-js -- Path-based dispatch: js_of_ocaml-specific support -distributed -- Library to provide Erlang style distributed computations. This library is inspired by Cloud Haskell -distributed-lwt -- A library to probide a lwt based implementation of Distributed -diy -- Tool suite for testing shared memory models -dkim -- Implementation of DKIM in OCaml -dkim-bin -- Implementation of DKIM in OCaml -dkim-mirage -- Implementation of DKIM in OCaml for MirageOS -dkml-c-probe -- Cross-compiler friendly ABI and library discovery for OCaml's native C compilers -dkml-compiler-env -- Scripts to configure DKML compilation in various environments -dkml-component-offline-ocamlrun -- DKML staging component for ocamlrun -dkml-component-offline-opam -- Offline install of Opam -dkml-component-staging-ocamlrun -- DKML staging component for ocamlrun -dkml-component-staging-opam32 -- DKML component for 32-bit versions of opam -dkml-component-staging-opam64 -- DKML component for 64-bit versions of opam -dkml-component-xx-console -- Component used by the dkml-package-console Console Packager -dkml-dune-dsl -- Embedded DSL for Dune files to do syntax checking, auto-completion and generate dune.inc include files -dkml-dune-dsl-show -- An interpreter for the embedded DSL of Dune that shows the DSL as a real Dune file -dkml-install -- API and registry for DkML installation components -dkml-install-installer -- Build tools for DkML installers -dkml-install-runner -- Runner executable for DkML installation -dkml-option-vcpkg -- Configures DKML components to support vcpkg -dkml-package-console -- Console setup and uninstall executables for DkML installation -dkml-runtime-common -- Common runtime code used in DKML -dkml-runtime-common-native -- Common runtime code used in DKML -dkml-workflows -- GitLab CI/CD and GitHub Action workflows used by and with Diskuv OCaml (DKML) tooling -dlm -- Libdlm bindings -dmap -- A library that implements dependent (heterogeneous) maps -dns -- An opinionated Domain Name System (DNS) library -dns-certify -- MirageOS let's encrypt certificate retrieval -dns-cli -- Unix command line utilities using uDNS -dns-client -- DNS client API -dns-client-lwt -- DNS client API using lwt -dns-client-mirage -- DNS client API for MirageOS -dns-mirage -- An opinionated Domain Name System (DNS) library -dns-resolver -- DNS resolver business logic -dns-server -- DNS server, primary and secondary -dns-stub -- DNS stub resolver -dns-tsig -- TSIG support for DNS -dnssec -- DNSSec support for OCaml-DNS -docfd -- TUI fuzzy document finder -docker-api -- Binding to the Docker Remote API -docker_hub -- Library aiming to provide data from hub.docker.com -dockerfile -- Dockerfile eDSL in OCaml -dockerfile-cmd -- Dockerfile eDSL -- generation support -dockerfile-opam -- Dockerfile eDSL -- opam support -docout -- Functor to create (text) output functions -docteur -- A simple read-only Key/Value from Git to MirageOS -docteur-solo5 -- A simple read-only Key/Value from Git to MirageOS -docteur-unix -- A simple read-only Key/Value from Git to MirageOS -doculib -- A GUI for tagging and managing document metadata for books, textbooks, or articles -doi2bib -- Small CLI to get a bibtex entry from a DOI, an arXiv ID or a PubMed ID -dokeysto -- The dumb OCaml key-value store -dokeysto_camltc -- The dumb OCaml key-value store w/ tokyocabinet backend -dokeysto_lz4 -- The dumb OCaml key-value store w/ LZ4 compression -dolmen 0.9 A parser library for automated deduction -dolmen_bin -- A linter for logic languages -dolmen_loop 0.9 A tool library for automated deduction tools -dolmen_lsp -- A LSP server for automated deduction languages -dolmen_model -- A model checker for automated deduction languages -dolmen_type 0.9 A typechecker for automated deduction languages -dolog 6.0.0 The dumb OCaml logging library -domain-local-await -- A scheduler independent blocking mechanism -domain-local-timeout -- A scheduler independent timeout mechanism -domain-name 0.4.0 RFC 1035 Internet domain names -domain_shims -- A non-parallel implementation of Domains compatible with OCaml 4 -dose3 -- Dose library (part of Mancoosi tools) -dose3-extra -- Dose-extra libraries and tools (part of Mancoosi tools) -dot-merlin-reader -- Reads config files for merlin -dotenv -- Javascript's dotenv port to OCaml -down -- An OCaml toplevel (REPL) upgrade -dream 1.0.0~alpha5 Tidy, feature-complete Web framework -dream-accept -- Accept headers parsing for Dream -dream-cli -- Command Line Interface for Dream applications -dream-encoding -- Encoding primitives for Dream -dream-html -- HTML generator eDSL for Dream -dream-htmx -- Htmx utilities for Dream -dream-httpaf 1.0.0~alpha2 Internal: shared http/af stack for Dream (server) and Hyper (client) -dream-livereload -- Live reloading for Dream applications -dream-pure 1.0.0~alpha2 Internal: shared HTTP types for Dream (server) and Hyper (client) -dream-serve -- Static HTML website server with live reload -drom -- The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like user experience -drom_lib -- The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like user experience -drom_toml -- The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like user experience -dropbox -- Binding to the Dropbox Remote API -dropbox_lwt_unix -- Binding to the Dropbox Remote API (Unix) -dryunit -- A detection tool for traditional and popular testing frameworks -dssi -- Bindings for the DSSI API which provides audio synthesizers -dtc-pb -- DTC Protocol library autogenerated from Protobuf description -dtoa -- Converts OCaml floats into strings, using the efficient Grisu3 algorithm -dtools -- Library providing various helper functions to make daemons -dual -- Dual numbers library -duff -- Rabin's fingerprint and diff algorithm in OCaml -dum -- Inspect the runtime representation of arbitrary OCaml values -dump_ocamlformat -- Dump preset configuration files for ocamlformat -dune 3.10.0 Fast, portable, and opinionated build system -dune-action-plugin -- [experimental] API for writing dynamic Dune actions -dune-build-info 3.11.1 Embed build information inside executable -dune-compiledb -- Generate compile_commands.json from dune rules -dune-configurator 3.11.1 Helper library for gathering system configuration -dune-deps -- Show dependency graph of a multi-component dune project -dune-expand -- Tool to view ppx-expanded OCaml source files -dune-glob -- Glob string matching language supported by dune -dune-private-libs 3.11.1 Private libraries of Dune -dune-release -- Release dune packages in opam -dune-rpc 3.11.1 Communicate with dune using rpc -dune-rpc-lwt -- Communicate with dune using rpc and Lwt -dune-site 3.11.1 Embed locations information inside executable and libraries -duppy -- Library providing monadic threads -duration 0.2.1 Conversions to various time units -dyn 3.11.1 Dynamic type -dyntype -- syntax extension which makes OCaml types and values easier to manipulate programmatically -earley -- Parsing library based on Earley Algorithm -earlybird -- OCaml debug adapter -easy-format -- High-level and functional interface to the Format module of the OCaml standard library -easy_logging -- Module to log messages. Aimed at being both powerful and easy to use -easy_logging_yojson -- Configuration loader for easy_logging with yojson backend -ecaml -- Library for writing Emacs plugin in OCaml -edn -- Parsing OCaml library for EDN format -efl -- An OCaml interface to the Enlightenment Foundation Libraries (EFL) and Elementary. -ego -- Ego (EGraphs OCaml) is extensible EGraph library for OCaml -eigen -- Owl's OCaml interface to Eigen3 C++ library -either 1.0.0 Compatibility Either module -elasticsearch-cli -- Command-line client for Elasticsearch -electrod -- Formal analysis for the Electrod formal pivot language -elina -- ETH LIBRARY FOR NUMERICAL ANALYSIS -eliom -- Client/server Web and mobile framework -elpi -- ELPI - Embeddable λProlog Interpreter -email_message -- E-mail message parser -embedded_ocaml_templates -- EML is a simple templating language that lets you generate text with plain OCaml -emile -- Parser of email address according RFC822 -emoji -- Use emojis by name -encore -- Library to generate encoder/decoder which ensure isomorphism -enumerators -- Finite lazy enumerators -env_config -- Helper library for retrieving configuration from an environment variable -epictetus -- Elegant Printer of Insanely Complex Tables Expressing Trees with Uneven Shapes -eprover -- E Theorem Prover -eqaf 0.9 Constant-time equal function on string -equinoxe -- An OCaml wrapper for the Equinix API -equinoxe-cohttp -- Equinoxe with the cohttp-lwt-unix request handler -equinoxe-hlc -- Equinoxe with the http-lwt-client request handler -eris -- Encoding for Robust Immutable Storage (ERIS) -eris-lwt -- Lwt bindings to eris -erlang -- Libraries to manipulate Erlang sources -errpy -- Errpy: An Error Recovering Python Parser implemented in Rust -erssical -- Converting RSS event feeds to ical -esgg -- Elasticsearch guided (code) generator -esperanto -- An OCaml compiler with Cosmopolitan -esperanto-cosmopolitan -- Cosmopolitan toolchain for OCaml compiler -ethernet -- OCaml Ethernet (IEEE 802.3) layer, used in MirageOS -euler -- An arithmetic library for OCaml's standard integers -exenum -- Build efficient enumerations for datatypes. Inspired by Feat for Haskell. -exn-source -- Exception backtrace for OCaml with source code printing -expect -- Simple implementation of "expect" to help building unitary testing of interactive program -expect_test_helpers_async -- Async helpers for writing expectation tests -expect_test_helpers_core v0.16.0 Helpers for writing expectation tests -extism -- Extism bindings -extism-manifest -- Extism manifest bindings -extlib -- A complete yet small extension for OCaml standard library -extprot -- Extensible binary protocols for cross-language communication and long-term serialization -extunix -- Collection of thin bindings to various low-level system API -ez_api -- Easy API library and tools -ez_cmdliner -- Easy interface to Cmdliner à la Arg.parse with sub-commands -ez_config -- Easy management of configuration files -ez_file -- Easy file manipulation (read_file, write_file, etc.) -ez_hash -- Ez hash & crypto utilities -ez_opam_file -- Package ez_opam_file is a simple compatibility layer on top of opam-file-format -ez_pgocaml -- A simple library to work with pgocaml -ez_search -- The ez_search library -ez_subst -- Ez_subst is a simple module to perform string substitutions -ezcurl -- Friendly wrapper around OCurl -ezcurl-lwt -- Friendly wrapper around OCurl, Lwt version -ezdl -- Easy dynamic linking of C functions from ocaml -ezgzip -- Simple gzip (de)compression library -ezjs_ace -- Bindings for the Ace editor -ezjs_blockies -- Bindings for Blockies -ezjs_cleave -- Bindings for Cleave -ezjs_crypto -- Bindings for SubtleCrypto -ezjs_cytoscape -- Bindings for Cytoscape -ezjs_d3pie -- Bindings for d3pie -ezjs_extension -- Binding for Chrome and Firefox extension API -ezjs_fetch -- Bindings for Fetch -ezjs_idb -- Bindings for IndexedDB -ezjs_jquery -- Bindings for JQuery -ezjs_min -- A bunch of js_of_ocaml shortcuts -ezjs_odometer -- Bindings for odometer -ezjs_push -- Bindings for Push Notification -ezjs_qrcode -- Bindings for QRCode.js -ezjs_recaptcha -- Bindings for reCAPTCHA -ezjs_timeline -- Bindings for TimelineJS -ezjsonm 1.3.0 Simple interface on top of the Jsonm JSON library -ezjsonm-lwt -- Simple Lwt-based interface to the Jsonm JSON library -ezresto -- A minimal OCaml library for type-safe HTTP/JSON RPCs -ezresto-directory -- A minimal OCaml library for type-safe HTTP/JSON RPCs -ezsqlite -- Simplified SQLite3 bindings for OCaml -ezxmlm -- Combinators for parsing and selection of XML structures -FPauth -- Easy authentication system for Dream framework -FPauth-core -- Easy authentication system for Dream framework -FPauth-responses -- Responses on basic events in FPauth-core authentication system -FPauth-strategies -- Strategies to be used with FPauth-core authentication system -FrontC -- Parses C programs to an abstract syntax tree -faad -- Bindings for the faad library which provides functions for decoding AAC audio files -facile -- A Functional Constraint Library implemented in Objective Caml. -fadbadml -- FADBAD++ for OCaml -faraday 0.8.2 A library for writing fast and memory-efficient serializers -faraday-async -- Async support for Faraday -faraday-lwt 0.8.2 Lwt support for Faraday -faraday-lwt-unix 0.8.2 Lwt_unix support for Faraday -farfadet -- A printf-like for [Faraday](https://github.com/inhabitedtype/faraday) library -farith -- Floating point numbers library extracted from the Flocq Coq Library -farmhash -- Bindings for Google's farmhash library -fasmifra -- Molecular Generation by Fast Assembly of SMILES Fragments -fat-filesystem -- Pure OCaml implementation of the FAT filesystem -fd-send-recv -- Bindings for sendmsg/recvmsg that allow Unix.file_descrs to be sent and received over Unix domain sockets -fdkaac -- Fraunhofer FDK AAC Codec Library -feat -- Facilities for enumerating and sampling algebraic data types, using Zarith for big numbers -feat-core -- Facilities for enumerating and sampling algebraic data types -feat-num -- Facilities for enumerating and sampling algebraic data types, using Num for big numbers -feather -- A minimal shell interface -feather_async -- Async interface to Feather -febusy -- Embedded build system library -ff -- OCaml implementation of Finite Field operations -ff-bench -- Benchmark library for finite fields over the package ff-sig -ff-pbt -- Property based testing library for finite fields over the package ff-sig -ff-sig -- Minimal finite field signatures -ffmpeg -- Bindings for the ffmpeg libraries -ffmpeg-av -- Bindings for the ffmpeg libraries -- top-level helpers -ffmpeg-avcodec -- Bindings for the ffmpeg avcodec library -ffmpeg-avdevice -- Bindings for the ffmpeg avdevice library -ffmpeg-avfilter -- Bindings for the ffmpeg avfilter library -ffmpeg-avutil -- Bindings for the ffmpeg avutil libraries -ffmpeg-swresample -- Bindings for the ffmpeg swresample library -ffmpeg-swscale -- Bindings for the ffmpeg swscale library -fftw3 -- Binding to the Fast Fourier Transform library FFTW -fiat-p256 -- Primitives for Elliptic Curve Cryptography taken from Fiat -fiber 3.7.0 Dune's monadic structured concurrency library -fiber-lwt -- Compatibility layer for fibers inside Lwt -fieldslib v0.16.0 Syntax extension to define first class values representing record fields, to get and set record fields, iterate and fold over all fields of a record and create new record values -file_path -- A library for typed manipulation of UNIX-style file paths -fileutils -- API to manipulate files (POSIX like) and filenames -finch -- Simple and fast site generator -findlib_top -- Exposes findlib_top.cma without the need for using predicates -fit -- A parser for Garmin FIT data files -fix 20230505 Algorithmic building blocks for memoization, recursion, and more -flac -- Bindings to libflac -flex-array -- Flexible arrays -flint -- Stub of the C library Flint2 -flock -- Ctypes bindings to flock for OCaml -fm-simplex-plugin -- Alt-Ergo, an SMT Solver for Software Verification: FM-Simplex Plugin -fmlib 0.5.6 Functional monadic library -fmlib_browser 0.5.6 Write web applications for the browser in elm style -fmlib_js 0.5.6 Library for easy compilation from ocaml to javascript -fmlib_parse 0.5.6 Parsing with combinators and indentation sensitivity -fmlib_pretty 0.5.6 Pretty printing support for tree like structures -fmlib_std 0.5.6 Standard datatypes of Fmlib -fmt 0.9.0 OCaml Format pretty-printer combinators -fontforge-of-ocaml -- OCaml binding of FontForge -format -- Format is a syntax extension which defines quotations for building -fpath 0.7.3 File system paths for OCaml -frama-c -- Platform dedicated to the analysis of source code written in C -frama-c-lannotate -- Lannotate plugin of Frama-C, part of the LTest suite -frama-c-luncov -- Luncov plugin of Frama-C, part of the LTest suite -frama-c-metacsl -- MetAcsl plugin of Frama-C for writing pervasives properties -frama-clang -- Frama-C plug-in based on Clang for parsing C++ files -freetds -- Binding to the FreeTDS library -frei0r -- Bindings for the frei0r API which provides video effects -frenetic -- The Frenetic Programming Language and Runtime System -fromager -- A CLI to format an ocaml codebase -fsevents -- OCaml bindings to macOS FSEvents -fsevents-lwt -- Lwt interface to macOS FSEvents -fsml -- A library for describing and describing synchronous finite state machines -fstar -- Verification system for effectful programs -fstreams -- Functional, lazy, infinite streams. -fswatch -- Bindings for libfswatch -- file change monitor -fswatch_async -- JaneStreet Async extension for fswatch -fswatch_lwt -- Lwt extension for fswatch -functoria -- A DSL to organize functor applications -functoria-runtime -- Runtime support library for functoria-generated code -functory -- Distributed computing library. -funfields -- Functional bit field library -fuzzy_compare -- Fastest bounded Levenshtein comparator over generic structures -fuzzy_match -- Libraries for fuzzy string matching -fzf -- A library for running the fzf command line tool -GT -- Generic programming with extensible transformations -GuaCaml -- GuaCaml : Generic Unspecific Algorithmic in OCaml -gadelac -- Preprocessor for the Game Description Language. -gammu -- Cell phone and SIM card access. -gapi-ocaml -- A simple OCaml client for Google Services -gappa -- Tool intended for formally proving properties on numerical programs dealing with floating-point or fixed-point arithmetic -gavl -- Bindings for the gavl library which provides functions for converting images formats, colorspaces, etc. -gbddml -- The Verimag bdd library -gd -- OCaml interface to the GD graphics library. -gdal -- GDAL and OGR bindings -gdbprofiler -- A profiler for native OCaml and other executables -gedcom -- GEDCOM parsing. -gen 1.1 Iterators for OCaml, both restartable and consumable -gen-bs -- generate bucklescript code from Javascript type specifications -gen_js_api -- Easy OCaml bindings for JavaScript libraries -genspio -- Typed EDSL to generate POSIX Shell scripts -genspir -- Generate almost uniformly points on a sphere -geoip -- Bindings to GeoIP database library. -geojson -- Pure OCaml library for GeoJSON -geoml -- Geoml: 2D Geometry library for OCaml -get_line -- Robustly select lines from file; can replace the head and tail shell commands and do even more -getopt -- Parsing of command line arguments (similar to GNU GetOpt) for OCaml -getopts -- Analyse command line arguments -gettext -- Internationalization library (i18n) -gettext-camomile -- Internationalization library using camomile (i18n) -gettext-stub -- Internationalization using C gettext library (i18n) -gg 1.0.0 Basic types for computer graphics in OCaml -git -- Git format and protocol in pure OCaml -git-cohttp -- A package to use HTTP-based ocaml-git with Unix backend -git-cohttp-mirage -- A package to use HTTP-based ocaml-git with MirageOS backend -git-cohttp-unix -- A package to use HTTP-based ocaml-git with Unix backend -git-http -- Client implementation of the "Smart" HTTP Git protocol in pure OCaml -git-kv -- A Mirage_kv implementation using git -git-mirage -- A package to use ocaml-git with MirageOS backend -git-paf -- A package to use HTTP-based ocaml-git with MirageOS backend -git-unix -- Virtual package to install and configure ocaml-git's Unix backend -github -- GitHub APIv3 OCaml library -github-data -- GitHub APIv3 data library -github-hooks -- GitHub API web hook listener library -github-hooks-unix -- GitHub API web hook listener library using unix functions -github-jsoo -- GitHub APIv3 JavaScript library -github-unix -- GitHub APIv3 Unix library -gitlab -- GitLab APIv4 OCaml library -gitlab-jsoo -- Gitlab APIv4 OCaml library -gitlab-unix -- GitLab APIv4 OCaml library -gitlab_pipeline_notifier -- Watches GitLab pipelines and notifies on status updates using 'send-notify' -gles3 -- OCaml GLES 3.0 bindings -glfw-ocaml -- A GLFW binding for OCaml -glical -- Glical: glancing at iCalendar data. -glicko2 -- Implementation of the Glicko2 algorithm -glMLite -- OpenGL bindings for OCaml -globlon -- A globbing library for OCaml -glpk -- Bindings for glpk -gluten -- A reusable runtime library for network protocols -gluten-async -- Async support for gluten -gluten-lwt -- Lwt-specific runtime for gluten -gluten-lwt-unix -- Lwt + Unix support for gluten -gluten-mirage -- Mirage support for gluten -gmap 0.3.0 Heterogenous maps over a GADT -gmp -- The GNU Multiple Precision Arithmetic Library -gmp-ecm -- GMP-ECM library for the Elliptic Curve Method (ECM) for integer factorization -gmp-freestanding -- The GNU Multiple Precision Arithmetic Library -gmp-xen -- The GNU Multiple Precision Arithmetic Library -gnuplot -- Simple interface to Gnuplot Gnuplot-OCaml provides a simple interface to Gnuplot from OCaml. The API supports only 2D graphs and was inspired by FnuPlot -goblint -- Static analysis framework for C -goblint-cil -- A front-end for the C programming language that facilitates program analysis and transformation -google-drive-ocamlfuse -- A FUSE filesystem over Google Drive -gopcaml-mode -- Ultimate Ocaml editing plugin, providing advanced structural editing, movement and analysis in Emacs -gopcaml-mode-merlin -- Ultimate Ocaml editing plugin, providing advanced structural editing, movement and analysis in Emacs (uses Merlin parser) -gospel -- A tool-agnostic formal specification language for OCaml -gotd -- Quickly start an OCaml project -gperftools -- Bindings to gperftools -gpiod -- A wrapper around the C libgpiod library for GPIO on recent (>4.8) Linux kernels -gpr -- GPR - Library and Application for Gaussian Process Regression -gpx -- Conversions between XML and GPX (1.1) types. -gr -- OCaml bindings to the GR plotting library -gradescope_submit -- A small script to submit to Gradescope via GitHub -grain_dypgen -- Self-extensible parsers and lexers for OCaml -graphics -- The OCaml graphics library -graphicspdf -- Version of OCaml's Graphics library which outputs PDFs. -graphlib -- Generic Graph library -graphql 0.14.0 Build GraphQL schemas and execute queries against them -graphql-async -- Build GraphQL schemas with Async support -graphql-cohttp -- Run GraphQL servers with `cohttp` -graphql-lwt 0.14.0 Build GraphQL schemas with Lwt support -graphql_parser 0.14.0 Library for parsing GraphQL queries -graphql_ppx -- GraphQL PPX rewriter for ReScript/ReasonML -graphv -- Top_level graphv package, includes all dependencies -graphv_core -- Functor for creating a new Graphv library based on a font render and backend renderer -graphv_core_lib -- Primitives for the Graphv vector graphics library -graphv_font -- Functor for generating the Graphv font library -graphv_font_js -- Javascript implementation of the font interface for Graphv -graphv_font_stb_truetype -- STB truetype implementation of the font interface for Graphv -graphv_gles2 -- Functor for creating a Graphv renderer based on GLES2 -graphv_gles2_native -- Full version of the Graphv library based on native GLES2 -graphv_gles2_native_impl -- Native GLES2 implementation of the backend renderer for the Graphv library -graphv_webgl -- Full version of the Graphv library based on WebGL -graphv_webgl_impl -- WebGL implementation of the backend renderer for the Graphv library -gremlin -- Gremlin Client Library -grenier -- A collection of various algorithms in OCaml -grib -- Bindings for the ECMWF GRIB API -grpc -- A modular gRPC library -grpc-async -- An Async implementation of gRPC -grpc-lwt -- An Lwt implementation of gRPC -gsl -- GSL - Bindings to the GNU Scientific Library -gstreamer -- Bindings for the GStreamer library which provides functions for playning and manipulating multimedia streams -guardian -- Role-based access control for OCaml -gufo -- A fonctionnal shell -guile -- Bindings to GNU Guile Scheme for OCaml -gxl-light -- Gxl parser and in-place destructive update library -h1_parser -- Parser for HTTP 1.1 -h2 -- A high-performance, memory-efficient, and scalable HTTP/2 library for OCaml -h2-async -- Async support for h2 -h2-lwt -- Lwt support for h2 -h2-lwt-unix -- Lwt + UNIX support for h2 -h2-mirage -- Lwt support for h2 -hack_parallel -- Parallel and shared memory library -hacl -- Tezos binding for Hacl* -hacl-star 0.7.1 OCaml API for EverCrypt/HACL* -hacl-star-raw 0.7.1 Auto-generated low-level OCaml bindings for EverCrypt/HACL* -hacl_func -- Minimal Hacl bindings -hacl_x25519 -- Primitives for Elliptic Curve Cryptography taken from Project Everest -hamt -- Hash Array Mapped Tries -happy-eyeballs -- Connecting to a remote host via IP version 4 or 6 -happy-eyeballs-lwt -- Connecting to a remote host via IP version 4 or 6 using Lwt_unix -happy-eyeballs-mirage -- Connecting to a remote host via IP version 4 or 6 using Mirage -hardcaml -- RTL Hardware Design in OCaml -hardcaml_axi -- Hardcaml AXI Interface Types -hardcaml_c -- Hardcaml C Simulation Backend -hardcaml_circuits -- Hardcaml Circuits -hardcaml_fixed_point -- Hardcaml fixed point arithmetic -hardcaml_handshake -- Hardcaml Handshake -hardcaml_of_verilog -- Convert Verilog to a Hardcaml design -hardcaml_step_testbench -- Hardcaml Testbench Monad -hardcaml_verify -- Hardcaml Verification Tools -hardcaml_verilator -- Hardcaml Verilator Simulation Backend -hardcaml_waveterm -- A terminal based digital waveform viewer for Hardcaml -hardcaml_xilinx -- Hardcaml wrappers for Xilinx memory primitives -hardcaml_xilinx_components -- Hardcaml Xilinx component definitions -hardcaml_xilinx_reports -- Hardcaml Xilinx Reports -hashcons 1.3 OCaml hash-consing library -hashset -- Sets as hash tables -haxe -- Multi-target universal programming language -hdfs -- Bindings to libhdfs -hdr_histogram -- OCaml bindings to Hdr Histogram -headache -- Automatic generation of files headers -header-check -- A tool to check and update source headers, using checksums -heptagon -- Compiler for the Heptagon/BZR synchronous programming language -herdtools7 -- The herdtools suite for simulating and studying weak memory models -hevea -- A quite complete and fast LATEX to HTML translator -hex 1.5.0 Library providing hexadecimal converters -hex_encode -- Hexadecimal encoding library -hexstring -- A library to encode to and decode from hexadecimal strings -hg_lib -- A library that wraps the Mercurial command line interface -hidapi 1.1.2 Bindings to Signal11's hidapi library -higher -- Library for higher-kinded programming -higher_kinded v0.16.0 A library with an encoding of higher kinded types in OCaml -higlo -- Syntax highlighting library -hilite -- Build time syntax highlighting -hiredis -- Redis tools based on the Hiredis C library -hiredis-value -- Hiredis Value type -hkdf 1.0.4 HMAC-based Extract-and-Expand Key Derivation Function (RFC 5869) -hlarp -- Normalize and compare HLA typing output. -hll -- -hmap 0.8.1 Heterogeneous value maps for OCaml -hockmd -- A library to access hackmd's api -hpack -- An HPACK (Header Compression for HTTP/2) implementation in OCaml -htmlfromtexbooks -- From TeX To Human-Readable HTML -htmlit 0.1.0 HTML generation combinators for OCaml -hts_shrink -- Distance-Based Boolean Applicability Domain for High Throughput Screening data -http -- Type definitions of HTTP essentials -http-cookie -- HTTP cookie library for OCaml -http-date -- HTTP Datetime encoder/decoder -http-lwt-client -- A simple HTTP client using http/af, h2, and lwt -http-mirage-client -- HTTP client for MirageOS -http-multipart-formdata -- Http multipart/formdata parser -http_async -- Async library for HTTP/1.1 servers -httpaf -- A high-performance, memory-efficient, and scalable web server for OCaml -httpaf-lwt-unix -- Lwt support for http/af -httpaf_caged -- A higher-level httpaf-async server interface -httph -- Minimal OCaml to the httpserver.h http server toolkit -huffman -- An OCaml library to manipulate Huffman trees -humane-re -- A human friendly interface to regular expressions in OCaml -hvsock -- Bindings for Hyper-V AF_VSOCK -hweak -- An hastable with weak pointer enabling the GC to collect things that are in the hashtable -hxd -- Hexdump in OCaml -hyper -- Web client with HTTP/1, HTTP/2, TLS, and WebSocket support -ISO3166 -- OCaml library for working with ISO3166 -ISO8601 -- ISO 8601 and RFC 3999 date parsing for OCaml -i2c -- i2c -i3ipc -- A pure OCaml implementation of the i3 IPC protocol -icalendar -- A library to parse and print the iCalendar (RFC 5545) format -idd -- Identity-suppressed decision diagrams (IDDs) -idds -- Identity-suppressed decision diagrams (IDDs) -igvxml -- Create IGV session files from the command-line -imagelib -- Library implementing parsing of image formats such as PNG, BMP, PPM -incr_dom -- A library for building dynamic webapps, using Js_of_ocaml -incr_dom_interactive -- A monad for composing chains of interactive UI elements -incr_dom_partial_render -- A library for simplifying rendering of large amounts of data -incr_dom_sexp_form -- A library for building forms that allow the user to edit complicated types -incr_map -- Helpers for incremental operations on map like data structures -incr_select -- Handling of large set of incremental outputs from a single input -incremental -- Library for incremental computations -indentation_buffer -- A library for building strings with indentation -index 1.6.1 A platform-agnostic multi-level index for OCaml -index-bench -- Index benchmarking suite -inferno -- A library for constraint-based Hindley-Milner type inference -influxdb -- InfluxDB client library -influxdb-async -- InfluxDB client library using async for concurrency -influxdb-lwt -- InfluxDB client library using lwt for concurrency -inotify -- Inotify bindings for OCaml -inquire -- Create beautiful interactive command line interface in OCaml -inquirer_oc -- A collection of common interactive command line user interfaces -inspect -- Inspect the runtime representation of arbitrary OCaml values. -int_repr v0.16.0 Integers of various widths -integers 0.7.0 Various signed and unsigned integer types for OCaml -integers_stubs_js 1.0 Javascript stubs for the integers library in js_of_ocaml -integration1d -- Collection of 1D numerical integration routines -interface-prime -- Interfaces for common design patterns -interface-prime-lwt -- Interfaces for common design patterns (LWT implementation) -interval -- An interval arithmetic library for OCaml (meta package) -interval-map -- An immutable interval map data structure -interval_base -- An interval library for OCaml (base package) -interval_crlibm -- An interval library for OCaml (crlibm version) -interval_intel -- An interval library for OCaml -inuit -- Make interactive text-based user-interfaces in OCaml -io -- Simple, secure and composable abstraction for efficient component -io-page -- Support for efficient handling of I/O memory pages -io-page-unix -- Support for efficient handling of I/O memory pages on Unix -iomux -- IO Multiplexer bindings -iostream -- Generic, composable IO input and output streams -ip2location -- IP2Location OCaml module to get geolocation data -ip2locationio -- IP2Location.io OCaml module to get geolocation and WHOIS data -ipaddr 5.5.0 A library for manipulation of IP (and MAC) address representations -ipaddr-cstruct -- A library for manipulation of IP address representations using Cstructs -ipaddr-sexp 5.5.0 A library for manipulation of IP address representations using sexp -ipv6-multicast -- UNIX bindings for IPv6 multicast -ipv6-multicast-lwt -- UNIX bindings for IPv6 multicast — Lwt -irc-client -- IRC client library - core functionality -irc-client-lwt -- IRC client library - Lwt implementation -irc-client-lwt-ssl -- IRC client library - Lwt SSL implementation -irc-client-tls -- IRC client library - TLS implementation -irc-client-unix -- IRC client library - Unix implementation -iri -- Implementation of Internationalized Resource Identifiers (IRIs) -irmin 3.7.2 Irmin, a distributed database that follows the same design principles as Git -irmin-bench -- Irmin benchmarking suite -irmin-chunk -- Irmin backend which allow to store values into chunks -irmin-cli -- CLI for Irmin -irmin-client -- A client for irmin-server -irmin-containers -- Mergeable Irmin data structures -irmin-fs -- Generic file-system backend for Irmin -irmin-git -- Git backend for Irmin -irmin-graphql -- GraphQL server for Irmin -irmin-http -- HTTP client and server for Irmin -irmin-indexeddb -- Irmin backend using the web-browser's IndexedDB store -irmin-layers -- Combine different Irmin stores into a single, layered store -irmin-mem -- Generic in-memory Irmin stores -irmin-mirage -- MirageOS-compatible Irmin stores -irmin-mirage-git -- MirageOS-compatible Irmin stores -irmin-mirage-graphql -- MirageOS-compatible Irmin stores -irmin-pack 3.7.2 Irmin backend which stores values in a pack file -irmin-pack-tools -- Utils for Irmin-pack -irmin-server -- A high-performance server for Irmin -irmin-test -- Irmin test suite -irmin-tezos -- Irmin implementation of the Tezos context hash specification -irmin-tezos-utils -- Utils for Irmin tezos -irmin-unix -- Unix backends for Irmin -irmin-watcher -- Portable Irmin watch backends using FSevents or Inotify -iso639 -- Language Codes for OCaml -iter -- Simple abstraction over `iter` functions, intended to iterate efficiently on collections while performing some transformations -itv-tree -- Float intervals tree library -jane-street-headers v0.16.0 Jane Street C header files -jane_rope -- String representation with cheap concatenation. -janestreet_cpuid -- A library for parsing CPU capabilities out of the `cpuid` instruction. -janestreet_csv -- Tools for working with CSVs on the command line -jasmin -- Compiler for High-Assurance and High-Speed Cryptography -javalib -- Javalib is a library written in OCaml with the aim to provide a high level representation of Java .class files -javascriptcore -- OCaml bindings to JavaScriptCore -jbuilder -- Fast, portable and opinionated build system -jekyll-format -- Jekyll post parsing library -jemalloc -- Bindings to jemalloc mallctl api -jext -- Js_of_ocaml tools to help handling web extension -jhupllib -- A collection of OCaml utilities used by the JHU PL lab -jingoo -- Template engine almost compatible with Jinja2(python template engine) -jose -- JOSE implementation for OCaml and ReasonML -js-build-tools -- Collection of tools to help building Jane Street Packages -js_of_ocaml 5.4.0 Compiler from OCaml bytecode to JavaScript -js_of_ocaml-camlp4 -- Compiler from OCaml bytecode to Javascript -js_of_ocaml-compiler 5.4.0 Compiler from OCaml bytecode to JavaScript -js_of_ocaml-lwt -- Compiler from OCaml bytecode to JavaScript -js_of_ocaml-ocamlbuild -- An ocamlbuild plugin to compile to JavaScript using js_of_ocaml -js_of_ocaml-ppx 5.4.0 Compiler from OCaml bytecode to JavaScript -js_of_ocaml-ppx_deriving_json -- Compiler from OCaml bytecode to JavaScript -js_of_ocaml-toplevel 5.4.0 Compiler from OCaml bytecode to JavaScript -js_of_ocaml-tyxml -- Compiler from OCaml bytecode to JavaScript -js_of_ocaml-webgpu -- Js_of_ocaml bindings for webgpu -js_of_ocaml-webidl -- Generate js_of_ocaml bindings from webidl definitions -js_of_ocaml_patches -- Additions to js_of_ocaml's standard library that are required by Jane Street libraries. -json-data-encoding 0.12.1 Type-safe encoding to and decoding from JSON -json-data-encoding-browser -- Type-safe encoding to and decoding from JSON (browser support) -json-data-encoding-bson 0.12.1 Type-safe encoding to and decoding from JSON (bson support) -json-derivers -- Common Derivers for Jsonm/Yjson -json-rpc -- JSON RPC -json-static -- JSON camlp4 syntax extension using json-wheel -json-wheel -- JSON parser and writer, with optional C-style comments -json_decoder -- -json_of_jsonm -- json_of_jsonm_lib is a JSON encoder and decoder library that converts text to and from a -jsonaf -- A library for parsing, manipulating, and serializing data structured as JSON -jsondiff -- JSON sensitive diffing -jsonm 1.0.2 Non-blocking streaming JSON codec for OCaml -jsonoo -- JSON library for Js_of_ocaml -jsonrpc -- Jsonrpc protocol implemenation -jsonxt -- Jsonxt - JSON parsers for files, strings and more -jsoo-react -- Bindings to ReactJS for js_of_ocaml, including JSX ppx -jsoo_broadcastchannel -- A wrapper in Js_of_ocaml to deal with BroadcastChannel -jsoo_storage -- A wrapper in Js_of_ocaml for the WebStorage API -jst-config v0.16.0 Compile-time configuration for Jane Street libraries -junit -- JUnit XML reports generation library -junit_alcotest -- JUnit XML reports generation for alcotest tests -junit_ounit -- JUnit XML reports generation for OUnit tests -jupyter -- An OCaml kernel for Jupyter notebook -jupyter-kernel -- Library to write jupyter kernels (interactive notebooks) -jwt -- Implementation of JWT in OCaml. -jwto -- JWT encoding, decoding and verification -kafka -- OCaml bindings for Kafka -kafka_async -- OCaml bindings for Kafka, Async bindings -kafka_lwt -- OCaml bindings for Kafka, Lwt bindings -kaputt -- Testing tool -kcas -- Software transactional memory based on lock-free multi-word compare-and-set -kcas_data -- Compositional lock-free data structures and primitives for communication and synchronization -kdl -- An implementation of the KDL document laguage -ke 0.6 Queue implementation -key-parsers -- Parsers for multiple key formats -kicadsch -- Library to read and convert Kicad Sch files -kind2 -- Multi-engine, parallel, SMT-based automatic model checker for safety properties of Lustre programs -kinetic-client -- Client API for Seagate's Kinetic drives -kittyimg -- An implementation of Kitty's terminal graphics protocol -kkmarkdown -- A safe markdown engine -kmt -- Framework for deriving Kleene Algebras with Tests (KAT) -knights_tour -- Solves the 'Knights Tour' and various 'Poyomino' puzzles -kqueue -- OCaml bindings for kqueue event notification interface -krb -- A library for using Kerberos for both Rpc and Tcp communication -kyotocabinet -- OCaml bindings for Kyoto Cabinet DBM -lab -- GitLab cli -lablgl -- Interface to OpenGL -lablgtk -- OCaml interface to GTK+ -lablgtk3 -- OCaml interface to GTK+3 -lablgtk3-extras -- A collection of additional tools and libraries to develop ocaml applications based on Lablgtk3 -lablgtk3-goocanvas2 -- OCaml interface to GTK+ GooCanvas library -lablgtk3-gtkspell3 -- OCaml interface to GTK+3 -lablgtk3-sourceview3 -- OCaml interface to GTK+ gtksourceview library -lablqml -- OCamlfind package and PPX extension to interface OCaml and QtQuick -labltk -- OCaml interface to Tcl/Tk -labrys -- A toy language based on LLVM that implements the System Fω type-system -lacaml -- Lacaml - OCaml-bindings to BLAS and LAPACK -ladspa -- Bindings for the LADSPA API which provides audio effects -lambda -- λ-calculus ocaml library -lambda-runtime -- A custom runtime for AWS Lambda written in OCaml -lambda-term -- Terminal manipulation library for OCaml -lambda_streams -- Lambda-based streaming library -lambda_streams_async -- Async helpers for lambda_streams -lambda_streams_lwt -- Lwt helpers for lambda_streams -lambdapi -- Proof assistant for the λΠ-calculus modulo rewriting -lambdasoup -- Easy functional HTML scraping and manipulation with CSS selectors -lame -- MP3 encoding library -landmarks -- A simple profiling library -landmarks-ppx -- Preprocessor instrumenting code using the landmarks library -lascar -- A library for manipulating Labeled Transition Systems in OCaml -lastfm -- The lastfm library is an implementation of the API used by the last.fm to keep count of played songs -lazy-trie -- Implementation of lazy prefix trees -lbfgs -- Bound-constrainted optimization in many variables -lbvs_consent -- Chemoinformatics software for consensus fingerprint queries -ldap -- Implementation of the Light Weight Directory Access Protocol -ldp -- Library to build LDP applications -ldp_curl -- Library to build LDP applications using Curl -ldp_js -- Library to build LDP applications in JS -ldp_tls -- Library to build LDP applications using TLS -leaflet -- Bindings for the Leaflet JavaScript library -ledgerwallet 0.3.0 Ledger wallet library for OCaml -ledgerwallet-tezos 0.3.0 Ledger wallet library for OCaml: Tezos app -ledit -- Line editor, a la rlwrap -lem -- Lem is a tool for lightweight executable mathematics -lemonade -- A monad library with bubbles -lemonade-sqlite -- A monadic interface to sqlite -lens -- Functional lenses -let-if -- A let%if syntax inspired by Rust's if let syntax -letsencrypt -- ACME implementation in OCaml -letsencrypt-app -- ACME implementation in OCaml -letsencrypt-dns -- DNS solver for ACME implementation in OCaml -letsencrypt-mirage -- ACME implementation in OCaml for MirageOS -letters -- Client library for sending emails over SMTP -leveldb -- OCaml bindings for Google's LevelDB library -lib_parsing -- Small library to help writing parsers -libabsolute 0.1 Libabsolute -libbinaryen -- Libbinaryen packaged for OCaml -libdash -- Bindings to the dash shell's parser -libevent -- OCaml wrapper for the libevent API -libirmin -- C bindings for irmin -libsail -- Sail is a language for describing the instruction semantics of processors -libssh -- Bindings to libssh -libsvm -- LIBSVM bindings for OCaml -libtensorflow -- TensorFlow library package -libtorch -- LibTorch library package -libudev -- Bindings to libudev for OCaml -libwasmer -- The official Wasmer library -libwasmtime -- The libwasmtime library package -libzipperposition -- Library for Zipperposition -lilac -- Get the value of any field in a YAML file as a string -lilv -- Bindings to lilv library for using LV2 audio plugins -line-up-words -- Align words in an intelligent way -line_oriented 1.3.0 Library to operate on files made of lines of text -linenoise -- Lightweight readline alternative -linkage -- easier plugin loading -links -- The Links Programming Language -links-mysql -- MySQL database driver for the Links Programming Language -links-postgresql -- Postgresql database driver for the Links Programming Language -links-sqlite3 -- SQLite database driver for the Links Programming Language -linksem -- A formalisation of the core ELF and DWARF file formats written in Lem -linol -- LSP server library -linol-lwt -- LSP server library (with Lwt for concurrency) -lintcstubs -- OCaml C stub static analyzer -lintcstubs-arity -- Generate headers for C bindings -lintcstubs-gen -- OCaml C stub wrapper generator -linwrap -- Wrapper on top of liblinear-tools -lipsum -- lipsum - self-contained tool for literate programming in tradition of NoWeb -liquid_interpreter -- The interpreter for Liquid -liquid_ml -- Shopify's Liquid templating language in OCaml -liquid_parser -- The parser for Liquid -liquid_std -- The Standard Libarary for Liquid -liquid_syntax -- The Syntax Definitions for Liquid -liquidsoap -- Swiss-army knife for multimedia streaming -liquidsoap-core -- Liquidsoap core library and binary -liquidsoap-daemon -- Daemonization scripts for liquidsoap -liquidsoap-js -- Liquidsoap language - javascript wrapper -liquidsoap-lang -- Liquidsoap language library -liquidsoap-libs -- Liquidosap standard library -liquidsoap-libs-extra -- Liquidosap standard library -- extra functionalities -liquidsoap-mode -- Liquidosap emacs mode -little_logger -- A tiny, little logger <3 -llama -- Language for Live Audio Module Arrangement -llama-cpp-ocaml -- Ctypes bindings to llama.cpp -llama_core -- Core types and operations for the Llama synthesizer library -llama_interactive -- Visualization and live interaction for Llama synthesizer library -llama_midi -- Minimal library for parsing and representing midi data -llopt -- Just a tiny LLVM-IR optimizer for testing stuff. -llvm -- The OCaml bindings distributed with LLVM -llvmgraph -- Ocamlgraph overlay for llvm -lmdb -- Bindings for LMDB, a fast in-file database with ACID transactions -lo -- Bindings for the lo library which provides functions for communicating with input controls using the OSC protocol -lockfree -- Lock-free data structures for multicore OCaml -logger-p5 -- Camlp5 syntax extension for logging -logical -- Logical is a minimalistic logic programming inspired by microKanren -logs 0.7.0 Logging infrastructure for OCaml -logs-async -- Jane Street Async logging with Logs -logs-async-reporter -- Logs reporter compatible with Async -logs-ppx -- PPX to cut down on boilerplate when using Logs -logs-syslog -- Logs reporter to syslog (UDP/TCP/TLS) -logtk -- Core types and algorithms for logic -lp -- LP and MIP modeling in OCaml -lp-glpk -- LP and MIP modeling in OCaml (GLPK interface) -lp-glpk-js -- LP and MIP modeling in OCaml (glpk.js interface) -lp-gurobi -- LP and MIP modeling in OCaml (Gurobi interface) -lpd -- A Line Printer Daemon (LPD) server library written entirely in OCaml. -lpi -- A REPL and library for a small dependently-typed language. -lreplay -- Executes a test suite and computes test coverage -lru 0.3.1 Scalable LRU caches -lru-cache -- A simple implementation of a LRU cache. -lru_cache -- An LRU Cache implementation. -lsp -- LSP protocol implementation in OCaml -lt-code -- OCaml implementation of a Luby Transform code -lua-ml -- An embeddable Lua 2.5 interpreter implemented in OCaml -lua_parser -- A Lua 5.2 Parser -lua_pattern -- Implementation of Lua patterns -lucid -- Super simple logging library for OCaml -lun -- Optics in OCaml -lustre-v6 -- The Lustre V6 Verimag compiler -lutils -- Tools and libs shared by Verimag/synchronous tools (lustre, lutin, rdbg) -lutin -- Lutin: modeling stochastic reactive systems -luv -- Binding to libuv: cross-platform asynchronous I/O -luv_unix -- Helpers for interfacing Luv and Unix -lwd -- Lightweight reactive documents -lwt 5.7.0 Promises and event-driven I/O -lwt-canceler 0.3 Cancellation synchronization object -lwt-dllist -- Mutable doubly-linked list with Lwt iterators -lwt-exit 1.0 An opinionated clean-exit and signal-handling library for Lwt programs -lwt-parallel -- Lwt-enabled Parallel Processing Library -lwt-pipe -- An alternative to `Lwt_stream` with interfaces for producers and consumers and a bounded internal buffer -lwt-pipeline -- Pipeline library for Lwt -lwt-watcher 0.2 One-to-many broadcast in Lwt -lwt_camlp4 -- Camlp4 syntax extension for Lwt (deprecated) -lwt_glib -- GLib integration for Lwt -lwt_log -- Lwt logging library (deprecated) -lwt_ppx 2.1.0 PPX syntax for Lwt, providing something similar to async/await from JavaScript -lwt_ppx_let -- Dummy package context for ppx_let tests -lwt_react -- Helpers for using React with Lwt -lwt_ssl 1.2.0 OpenSSL binding with concurrent I/O -lymp -- Use Python functions and objects from OCaml -lz4 -- Bindings to the LZ4 compression algorithm -lz4_chans -- LZ4-compressed binary channels -lzo -- Bindings to LZO - a portable lossless data compression library -m_tree -- An implementation of M-trees -macaddr 5.5.0 A library for manipulation of MAC address representations -macaddr-cstruct -- A library for manipulation of MAC address representations using Cstructs -macaddr-sexp -- A library for manipulation of MAC address representations using sexp -macaque -- DSL for SQL Queries in Caml -macaroons -- Macaroons for OCaml -mad -- Mad decoding library -magic -- Bindings for libmagic (to determine the type of files) -magic-mime 1.3.1 Map filenames to common MIME types -magic-trace -- Collects and displays high-resolution traces of what a process is doing -maildir -- This is a preliminary release of an OCaml library to access directories in the Maildir format. -make-random -- Helper to build a module similar to Stdlib.Random -malfunction -- Compiler back-end for functional languages, based on OCaml -man_in_the_middle_debugger -- Man-in-the-middle debugging library -mariadb -- OCaml bindings for MariaDB -markdown -- Markdown processor for Ocsigen -markup -- Error-recovering functional HTML5 and XML parsers and writers -markup-lwt -- Adapter between Markup.ml and Lwt -mastodon-archive-viewer -- View your Mastodon archive offline -matita -- An experimental, interactive theorem prover -matplotlib -- Plotting using Matplotlib through python -maxminddb -- Bindings to Maxmind.com's libmaxminddb library, like geoip2 -mbr-format -- A simple library for manipulating Master Boot Records -mc2 -- A mcsat-based SMT solver in pure OCaml -mccs -- MCCS (which stands for Multi Criteria CUDF Solver) is a CUDF problem solver developed at UNS during the European MANCOOSI project -md2mld -- Little cli tool to convert md files into mld files -mdx 2.3.1 Executable code blocks inside markdown files -mec -- Mec - Mini Elliptic Curve library -mechaml -- A functional web scraping library -mehari -- A cross-platform library for building Gemini servers -mehari-lwt-unix -- Mehari IO implementation using Lwt and Unix bindings -mehari-mirage -- Mehari IO implementation for MirageOS -mel -- Build system for Melange that defers to Dune for build orchestration -melange -- Toolchain to produce JS from Reason/OCaml -melange-compiler-libs -- Compiler libraries for Melange, a toolchain to produce JavaScript from OCaml -meldep -- Melange counterpart to `ocamldep` that understands Melange-specific constructs -mem_usage -- Cross-platform stats about memory usage -memcad -- The MemCAD analyzer -memcpy -- Safe and efficient copying between blocks of memory. -memgraph -- A small library to inspect memory representation of ocaml values -memgraph_kitty -- Display the representation of memory values in the Kitty terminal emulator -memprof-limits -- Memory limits, allocation limits, and thread cancellation -memtrace -- Streaming client for Memprof -memtrace-mirage -- Streaming client for Memprof using MirageOS API -memtrace_viewer -- Interactive memory profiler based on Memtrace -menhir 20230608 An LR(1) parser generator -menhirLib 20230608 Runtime support library for parsers generated by Menhir -menhirSdk 20230608 Compile-time library for auxiliary tools related to Menhir -merge-fmt -- Git mergetool leveraging code formatters -mergeable-vector -- Mergeable vector based on operational transformation -merlin -- Editor helper, provides completion, typing and source browsing in Vim and Emacs -merlin-extend -- A protocol to provide custom frontend to Merlin -merlin-lib 4.12-414 Merlin's libraries -merlin-of-pds -- Simple script that turns a pds.conf into a .merlin file -mesh -- Triangular mesh generation and manipulation -mesh-easymesh -- Triangular mesh generation with EasyMesh -mesh-graphics -- Triangular mesh representation using the graphics module -mesh-triangle -- Binding to the triangle mesh generator -metadata -- Read metadata from various file formats -metadb -- A database for storing and managing file metadata in JSON format -metapp -- Meta-preprocessor for OCaml -metaquot -- OCaml syntax extension for quoting code -metrics -- Metrics infrastructure for OCaml -metrics-influx -- Influx reporter for the Metrics library -metrics-lwt -- Lwt backend for the Metrics library -metrics-mirage -- Mirage backend for the Metrics library -metrics-rusage -- Resource usage (getrusage) sources for the Metrics library -metrics-unix -- Unix backend for the Metrics library -mew -- Modal editing witch -mew_vi -- Modal editing witch, VI interpreter -mikmatch -- OCaml syntax extension for regexps -mimic -- A simple protocol dispatcher -mimic-happy-eyeballs -- A happy-eyeballs integration into mimic -mindstorm -- Drive Lego Mindstorms bricks from OCaml -mindstorm-lwt -- Drive Lego Mindstorms bricks from OCaml (LWT version) -minicaml -- A simple, didactical, purely functional programming language -minicli 5.0.2 Minimalist library for command line parsing -minilight -- Minimal global illumination renderer. -minima-theme -- OCaml port of the Jekyll Minima theme -minimal -- Minima.l, a minimal Lisp -minios-xen -- A minimal OS for running under the Xen hypervisor -minisat -- Bindings to the SAT solver Minisat, with the solver included. -minivpt -- Minimalist vantage point tree implementation in OCaml. -mirage -- The MirageOS library operating system -mirage-block -- Block signatures and implementations for MirageOS -mirage-block-ccm -- AES-CCM encrypted Mirage Mirage_types.BLOCK storage -mirage-block-combinators -- Block signatures and implementations for MirageOS using Lwt -mirage-block-lwt -- Block signatures and implementations for MirageOS using Lwt -mirage-block-partition -- Mirage block device partitioning -mirage-block-ramdisk -- In-memory BLOCK device for MirageOS -mirage-block-solo5 -- Solo5 implementation of MirageOS block interface -mirage-block-unix -- MirageOS disk block driver for Unix -mirage-block-xen -- MirageOS block driver for Xen that implements the blkfront/back protocol -mirage-bootvar-solo5 -- Solo5 implementation of MirageOS Bootvar interface -mirage-bootvar-unix -- Unix implementation of MirageOS Bootvar interface -mirage-bootvar-xen -- Handle boot-time arguments for Xen platform -mirage-btrees -- An implementation of BTrees designed for use with MirageOS's BLOCK interface -mirage-channel -- Buffered channels for MirageOS FLOW types -mirage-channel-lwt -- Buffered Lwt channels for MirageOS FLOW types -mirage-clock 4.2.0 Libraries and module types for portable clocks -mirage-clock-freestanding -- Paravirtual implementation of the MirageOS Clock interface -mirage-clock-lwt -- Lwt-based implementation of the MirageOS Clock interface -mirage-clock-solo5 -- Paravirtual implementation of the MirageOS Clock interface -mirage-clock-unix -- Unix-based implementation for the MirageOS Clock interface -mirage-clock-xen -- A Mirage-compatible Clock library for Xen -mirage-console -- Implementations of Mirage console devices -mirage-console-lwt -- Implementation of Mirage consoles using Lwt -mirage-console-solo5 -- Solo5 implementation of MirageOS console interface -mirage-console-unix -- Implementation of Mirage consoles for Unix -mirage-console-xen -- Implementation of Mirage console for Xen -mirage-console-xen-backend -- Implementation of Mirage console backend for Xen -mirage-console-xen-proto -- Implementation of Mirage console protocol for Xen -mirage-crypto 0.11.2 Simple symmetric cryptography for the modern age -mirage-crypto-ec 0.11.2 Elliptic Curve Cryptography with primitives taken from Fiat -mirage-crypto-entropy -- Entropy source for MirageOS unikernels -mirage-crypto-pk 0.11.2 Simple public-key cryptography for the modern age -mirage-crypto-rng 0.11.2 A cryptographically secure PRNG -mirage-crypto-rng-async -- Feed the entropy source in an Async-friendly way -mirage-crypto-rng-lwt 0.11.2 A cryptographically secure PRNG -mirage-crypto-rng-mirage -- Entropy collection for a cryptographically secure PRNG -mirage-device -- Abstract devices for MirageOS -mirage-entropy -- Entropy source for MirageOS unikernels -mirage-flow -- Flow implementations and combinators for MirageOS -mirage-flow-combinators -- Flow implementations and combinators for MirageOS specialized to lwt -mirage-flow-lwt -- Flow implementations and combinators for MirageOS specialized to lwt -mirage-flow-rawlink -- Expose rawlink interfaces as MirageOS flows -mirage-flow-unix -- Flow implementations and combinators for MirageOS on Unix -mirage-fs -- MirageOS signatures for filesystem devices -mirage-fs-lwt -- MirageOS signatures for filesystem devices using Lwt -mirage-fs-mem -- In-memory file system for for MirageOS -mirage-fs-unix -- Passthrough filesystem for MirageOS on Unix -mirage-kv -- MirageOS signatures for key/value devices -mirage-kv-lwt -- MirageOS signatures for key/value devices -mirage-kv-mem -- In-memory key value store for MirageOS -mirage-kv-unix -- Key-value store for MirageOS backed by Unix filesystem -mirage-logs -- A reporter for the Logs library that writes log messages to stderr, using a Mirage `CLOCK` to add timestamps -mirage-monitoring -- Monitoring of MirageOS unikernels -mirage-nat -- Mirage-nat is a library for network address translation to be used with MirageOS -mirage-net -- Network signatures for MirageOS -mirage-net-fd -- MirageOS network interfaces using raw sockets -mirage-net-flow -- Build MirageOS network interfaces on top of MirageOS flows -mirage-net-lwt -- Network signatures for MirageOS -mirage-net-solo5 -- Solo5 implementation of MirageOS network interface -mirage-net-unix -- Unix implementation of the Mirage_net_lwt interface -mirage-net-xen -- Network device for reading and writing Ethernet frames via then Xen netfront/netback protocol -mirage-no-solo5 -- Virtual package conflicting with mirage-solo5 -mirage-no-xen -- Virtual package conflicting with mirage-xen -mirage-os-shim -- Portable shim for MirageOS OS API -mirage-profile -- Collect runtime profiling information in CTF format -mirage-profile-unix -- Collect runtime profiling information in CTF format -mirage-protocols -- MirageOS signatures for network protocols -mirage-protocols-lwt -- MirageOS signatures for network protocols -mirage-qubes -- Implementations of various Qubes protocols for MirageOS -mirage-qubes-ipv4 -- Implementations of IPv4 stack which reads configuration from QubesDB for MirageOS -mirage-random -- Random-related devices for MirageOS -mirage-random-stdlib -- Random device implementation using the OCaml stdlib -mirage-random-test -- Stub random device implementation for testing -mirage-runtime -- The base MirageOS runtime library, part of every MirageOS unikernel -mirage-seal -- Serve static files over HTTPS, using Mirage+ocaml-TLS. -mirage-solo5 -- Solo5 core platform libraries for MirageOS -mirage-stack -- MirageOS signatures for network stacks -mirage-stack-lwt -- MirageOS signatures for network stacks -mirage-tc -- MirageOS type-classes -mirage-time -- Time operations for MirageOS -mirage-time-lwt -- Time operations for MirageOS with Lwt -mirage-time-unix -- Time operations for MirageOS on Unix -mirage-types -- Module type definitions for MirageOS applications -mirage-types-lwt -- Lwt module type definitions for MirageOS applications -mirage-unix -- Unix core platform libraries for MirageOS -mirage-vnetif -- Virtual network interface and software switch for Mirage -mirage-vnetif-stack -- Vnetif implementation of mirage-stack for Mirage TCP/IP -mirage-xen -- Xen core platform libraries for MirageOS -mirage-xen-minios -- Xen MiniOS guest operating system library -mirage-xen-posix -- MirageOS library for posix headers -misuja -- A library to drive the MIDI system of the Jack Audio Connection Kit. -mixture -- The Mixture package is a mixin library for the module system -mkaudio -- CLI program for generating audio files -mkocaml -- Tool to generate OCaml projects -mlbdd -- An OCaml library for Binary Decision Diagrams (BDDs) -mlcuddidl -- OCaml interface to the CUDD BDD library -mlfenv -- OCaml C bindings for fenv(3) -mlgmpidl 1.2.15 OCaml interface to the GMP library -mlmpfr -- OCaml C bindings for MPFR-4.1.1 -mlt_parser -- Parsing of top-expect files -mm -- The mm library contains high-level APIs to create and manipulate multimedia streams (audio, video, MIDI) -mmap -- File mapping functionality -mmdb -- Binding to the MaxMind DB library for GeoIP lookups -mmseg -- This is a transition package, mmseg is now named wseg. Use the wseg package instead -mnd -- A small monads library -mock -- Configurable functions to test impure code -mock-ounit -- OUnit wrapper for OCaml mock -modular-arithmetic -- A library for operations on integers modulo some integer (the modulus) -module-graph -- The module-graph tool generates a graph of dependencies between OCaml modules using compiled object files -molenc -- Molecular encoder/featurizer using rdkit and OCaml -monaco_jsoo -- JSOO interface for Monaco-editor -monadlib -- A starter library for monads, with transformers and applicatives. -monads -- A missing monad library -monocypher -- OCaml bindings to the Monocypher cryptographic library -monolith -- A framework for testing a library using afl-fuzz -monomorphic -- A small library used to shadow polymorphic operators (and functions) contained in the stdlib -monorobot -- Notification bot for monorepos -moonpool -- Pools of threads supported by a pool of domains -morbig -- A trustworthy parser for POSIX shell -more-ocaml -- Support code for the book 'More OCaml' -morsmall -- A concise AST for POSIX shell -mosquitto -- mosquitto -moss -- A client for the MOSS plagiarism detection service -mparser -- A simple monadic parser combinator library -mparser-pcre -- MParser plugin: PCRE-based regular expressions -mparser-re -- MParser plugin: RE-based regular expressions -mperf -- Bindings to Linux perf's metrics -mpg123 -- MP3 decoding library -mpi -- OCaml binding to the Message Passing Interface (MPI) -mpp -- MPP is both a preprocessor and a meta preprocessor -mpris -- Client library for the MPRIS D-Bus media player interface -mpris-clients -- Client implementations of the MPRIS D-Bus media player interface -mrmime -- Mr. MIME -msat -- Library containing a SAT solver that can be parametrized by a theory -msat-bin -- SAT solver binary based on the msat library -msgpack -- Msgpack library for OCaml -msgpck -- Fast MessagePack (http://msgpack.org) library -msgpck-repr -- Fast MessagePack (http://msgpack.org) library -- ocplib-json-typed interface -mssql -- Async SQL Server client using FreeTDS -mstruct -- A mutable interface to Cstruct buffers -mtime 1.4.0 Monotonic wall-clock time for OCaml -mtl -- A Monad Transformers Library for OCaml -mugen -- Universe levels and universe polymorphism -mula -- ML's Universal Levenshtein Automata library -multibase -- Self-describing base encodings -multicodec -- Canonical codec of values and types used by various multiformats -multicore-magic -- Low-level multicore utilities for OCaml -multihash -- Self-describing Hash Functions -multihash-digestif -- Self-describing Hash Functions using Digestif -multipart-form-data -- Parser for multipart/form-data (RFC2388) -multipart_form 0.5.0 Multipart-form: RFC2183, RFC2388 & RFC7578 -multipart_form-cohttp-lwt -- Multipart-form for CoHTTP -multipart_form-lwt 0.5.0 Multipart-form: RFC2183, RFC2388 & RFC7578 -murmur3 -- Bindings for murmur3 hash implementation -mustache -- Mustache logic-less templates in OCaml -mutaml -- A mutation tester for OCaml -mutf8 -- The Modified UTF-8 encoding used by Java and related systems -mvar -- Threadsafe mutable variables for Unix threads -mwt -- Mediumweight thread library for OCaml via Lwt -mybuild -- Collection of ocamlbuild plugins (extprot, atdgen, ragel, etc) and utility to generate version from VCS -mysql -- Bindings to C client library for interacting with Mysql/MariaDB/Percona databases -mysql8 -- OCaml interface for mysql-connector-c -mysql_protocol -- OCaml implementation of the native MySQL/MariaDB Protocol with the Bitstring library -n_ary -- A library for N-ary datatypes and operations. -naboris -- Simple http server -nacc -- Not Another Compiler Compiler -namespaces -- Turn directories into OCaml modules (deprecated) -nanoid -- Nano ID implementation for OCaml -nanosvg -- Simple SVG parser and rasterizer -nanosvg_text -- Text rendering for NanoSVG text nodes -nbd -- Network Block Device (NBD) protocol implementation -nbd-tool -- Network Block Device (NBD) protocol implementation -nbd-unix -- Network Block Device (NBD) protocol implementation -netchannel -- Network device for reading and writing Ethernet frames via then Xen netfront/netback protocol -netlink -- Bindings to the Netlink Protocol Library Suite (libnl) -netsnmp -- An interface to the Net-SNMP client library -nice_parser -- Nice parsers without the boilerplate -nlopt -- OCaml bindings to the NLOpt optimization library -nlopt-ocaml -- This is a transition package, nlopt-ocaml is now named nlopt -nlp -- Natural Language Processing tools for OCaml -nmea -- Nmea parser -noCanren -- Translator from subset of OCaml to OCanren -nocoiner -- A Commitment Scheme library for Coin Flipping/Tossing algorithms and sort -nocrypto -- Simpler crypto -node_of_ocaml -- An OCaml ppx to require node modules -non_empty_list -- A non empty list library for OCaml -nonstd -- Non-standard mini-library -nosetup -- An `.ocamlinit` helper to `#require` packages in an OCaml toplevels -not-ocamlfind -- A small frontend for ocamlfind that adds a few useful commands -note -- Declarative events and signals for OCaml -nottui -- UI toolkit for the terminal built on top of Notty and Lwd -nottui-lwt -- Run Nottui UIs in Lwt -nottui-pretty -- A pretty-printer based on PPrint rendering UIs -notty -- Declaring terminals -notty_async -- An Async driver for Notty -np -- Fundamental scientific computing with Numpy for OCaml -nproc -- Process pool implementation for OCaml. -npy -- Numpy npy file format reading/writing. -nsq -- A client library for the NSQ messaging platform -num 1.4 The legacy Num library for arbitrary-precision integer and rational arithmetic -numalib -- Interface to Linux NUMA API -numeric_string -- A comparison function for strings that sorts numeric fragments of strings according to their numeric value, so that e.g. "abc2" < "abc10". -nuscr -- A tool to manipulate and validate Scribble-style multiparty protocols -OCADml -- Types and functions for building CAD packages in OCaml -OCanren -- Implementation of miniKanren relational (logic) EDSL -OCanren-ppx -- Implementation of miniKanren relational (logic) EDSL: PPX extensions -OSCADml -- OCaml DSL for 3D solid modelling in OpenSCAD -oasis -- Tooling for building OCaml libraries and applications -oasis2debian -- Create and maintain Debian package for an OASIS package -oasis2opam -- Tool to convert OASIS metadata to OPAM package descriptions -obandit -- Ocaml Multi-Armed Bandits -obelisk -- Pretty-printing for Menhir files -objsize -- Small library to compute sizes of OCaml heap values -obuild -- simple package build system for OCaml -obuilder -- Run build scripts for CI -obuilder-spec -- Build specification format -obus -- Pure Ocaml implementation of the D-Bus protocol -obytelib -- OCaml bytecode library tools to read, write and evaluate OCaml bytecode files -oc45 -- Pure OCaml implementation of the C4.5 algorithm. -ocal -- An improved Unix `cal` utility -ocaml 4.14.1 The OCaml compiler (virtual package) -ocaml-base-compiler 4.14.1 Official release 4.14.1 -ocaml-basics -- Implements common functionnal patterns / abstractions -ocaml-buddy -- Bindings for the Buddy BDD library. -ocaml-canvas -- The OCaml-Canvas library -ocaml-compiler-libs v0.12.4 OCaml compiler libraries repackaged -ocaml-config 2 OCaml Switch Configuration -ocaml-embed-file -- Files contents as module constants -ocaml-expat -- Write XML-Parsers using the SAX method -ocaml-freestanding -- Freestanding OCaml runtime -ocaml-http -- Library freely inspired from Perl's HTTP::Daemon module -ocaml-in-python -- Effortless Python bindings for OCaml modules -ocaml-inifiles -- An ini file parser -ocaml-lsp-server -- LSP Server for OCaml -ocaml-lua -- Lua bindings -ocaml-makefile -- Generic Makefile for building OCaml projects -ocaml-manual -- The OCaml system manual -ocaml-markdown -- This is a transition package, ocaml-markdown is now named markdown. -ocaml-migrate-parsetree 2.4.0 Convert OCaml parsetrees between different versions -ocaml-monadic -- A PPX extension to provide an OCaml-friendly monadic syntax -ocaml-options-vanilla 1 Ensure that OCaml is compiled with no special options enabled -ocaml-print-intf -- Display human-readable OCaml interface from a compiled .cmi -ocaml-probes -- USDT probes for OCaml: command line tool -ocaml-protoc -- Protobuf compiler for OCaml -ocaml-protoc-plugin -- Plugin for protoc protobuf compiler to generate ocaml definitions from a .proto file -ocaml-protoc-yojson -- JSON Runtime based on Yojson library for `ocaml-protoc` generated code -ocaml-r -- Objective Caml bindings for the R interpreter -ocaml-sat-solvers -- An abstraction layer for integrating SAT Solvers into OCaml -ocaml-secondary-compiler -- OCaml 4.08.1 Secondary Switch Compiler -ocaml-solo5 -- Freestanding OCaml compiler -ocaml-src -- Compiler sources -ocaml-syntax-shims 1.0.0 Backport new syntax to older OCaml versions -ocaml-system -- The OCaml compiler (system version, from outside of opam) -ocaml-systemd -- OCaml module for native access to the systemd facilities -ocaml-top -- The OCaml interactive editor for education -ocaml-twt -- The Whitespace Thing, a layout preprocessor for OCaml code -ocaml-vdom -- This is a transition package, ocaml-vdom is now named vdom. Use the vdom package instead -ocaml-version 3.6.2 Manipulate, parse and generate OCaml compiler version strings -ocaml-xdg-basedir -- This is a transition package, ocaml-xdg-basedir is now named xdg-basedir. Use the xdg-basedir package instead -ocaml_db_model -- An Ocaml library and utility for creating modules out of thin air that describe database tables and types, with functions for running queries and commands. Aka database modelling -ocaml_intrinsics v0.16.0 Intrinsics -ocaml_pgsql_model -- An Ocaml library and utility for creating modules out of thin air that describe database tables and types, with functions for running queries and commands; Aka database modelling -ocaml_plugin -- Automatically build and dynlink OCaml source files -ocamlbrowser -- OCamlBrowser Library Explorer -ocamlbuild 0.14.2 OCamlbuild is a build system with builtin rules to easily build most OCaml projects -ocamlbuild-atdgen -- Atdgen plugin for OCamlbuild -ocamlbuild-pkg -- An ocamlbuild plugin that helps packaging softwares. -ocamlbuild-protoc -- ocaml-protoc plugin for Ocamlbuild -ocamlc-loc 3.11.1 Parse ocaml compiler output into structured form -ocamlclean -- Reduce size of OCaml bytecode files by dead-code removing -ocamlcodoc -- Extract test code from doc-comments -ocamldap -- Transitional package for ldap (renaming) -ocamldiff -- OCamldiff is a small OCaml library providing functions to parse and display diff results -ocamldot -- Parsing and printing graphviz files in OCaml -ocamldsort -- Sorts a set of OCaml source files according to their dependencies -ocamlfind 1.9.6 A library manager for OCaml -ocamlfind-lint -- Simple tool performing checks on installed findlib META files -ocamlfind-secondary -- Adds support for ocaml-secondary-compiler to ocamlfind -ocamlformat 0.26.1 Auto-formatter for OCaml code -ocamlformat-lib 0.26.1 OCaml Code Formatter -ocamlformat-rpc -- Auto-formatter for OCaml code (RPC mode) -ocamlformat-rpc-lib 0.26.1 Auto-formatter for OCaml code (RPC mode) -ocamlfuse -- OCaml bindings for FUSE (Filesystem in UserSpacE) -ocamlgraph 2.1.0 A generic graph library for OCaml -ocamlify -- Include files in OCaml code -ocamline -- Command line interface for user input -ocamlmod -- Generate OCaml modules from source files -ocamlnet -- Internet protocols (HTTP, CGI, e-mail etc.) and helper data structures -ocamlog -- Simple Logger for OCaml -ocamlregextkit -- A regular expression toolkit for OCaml -ocamlrss -- Library providing functions to parse and print RSS 2.0 files -ocamlscript -- Tool which compiles OCaml scripts into native code -ocamlsdl -- Interface between OCaml and SDL -ocamlsdl2 -- Interface to the SDL2 library -ocamlsdl2-image -- Interface to the SDL2_image library -ocamlsdl2-ttf -- Interface to the SDL2_ttf library -ocamlwc -- Count lines in OCaml source code -ocamlyices -- Yices SMT solver binding -ocapic -- Development tools to run OCaml programs on PIC microcontrollers -ocb -- SVG badge generator -ocb-stubblr -- OCamlbuild plugin for C stubs -ocephes -- Bindings to special math functions from the Cephes library -ocf -- OCaml library to read and write configuration files in JSON syntax -ocf_ppx -- Preprocessor for Ocf library -ockt -- OCaml library for parsing ckt files into hashtables -oclock -- Oclock: Precise POSIX clock for OCaml -ocluster -- Distribute build jobs to workers -ocluster-api -- Cap'n Proto API for OCluster -ocluster-worker -- OCluster library for defining workers -ocolor -- Print with style in your terminal using Format's semantic tags -ocp-browser -- Console browser for the documentation of installed OCaml libraries -ocp-indent 1.8.1 A simple tool to indent OCaml programs -ocp-indent-nlfork -- ocp-indent library, "newline tokens" fork -ocp-index -- Lightweight completion and documentation browsing for OCaml libraries -ocp-ocamlres 0.4 Manipulation, injection and extraction of embedded resources -ocp-pack-split -- ocp-pack and ocp-split -ocp-reloc -- Relocation of OCaml bytecode executables -ocp-search -- The ocp-search tool to index/search source packages -ocp_reveal -- OCaml bindings for Reveal.js, an HTML presentation framework -ocplib-endian 1.2 Optimised functions to read and write int16/32/64 from strings and bigarrays -ocplib-json-typed -- Type-aware JSON and JSON schema utilities -ocplib-json-typed-browser -- Json_repr interface over JavaScript's objects -ocplib-json-typed-bson -- A Json_repr compatible implementation of the JSON compatible subset of BSON -ocplib-simplex 0.5 A library implementing a simplex algorithm, in a functional style, for solving systems of linear inequalities and optimizing linear objective functions -ocplib_stuff -- Basic stuff used by some OCP libraries and tools -ocsfml -- Binding to the C++ SFML gaming library. -ocsigen-i18n -- I18n made easy for web sites written with eliom -ocsigen-ppx-rpc -- This PPX adds a syntax for RPCs for Eliom and Ocsigen Start -ocsigen-start -- An Eliom application skeleton ready to use to build your own application with users, (pre)registration, notifications, etc -ocsigen-toolkit -- Reusable UI components for Eliom applications (client only, or client-server) -ocsigenserver -- A full-featured and extensible Web server -ocsipersist -- Persistent key/value storage (for Ocsigen) using multiple backends -ocsipersist-dbm -- Persistent key/value storage (for Ocsigen) using DBM -ocsipersist-lib -- Persistent key/value storage (for Ocsigen) - support library -ocsipersist-pgsql -- Persistent key/value storage (for Ocsigen) using PostgreSQL -ocsipersist-sqlite -- Persistent key/value storage (for Ocsigen) using SQLite -octavius -- Ocamldoc comment syntax parser -octez 18.0 Main virtual package for Octez, an implementation of Tezos -octez-accuser-Proxford 18.0 Tezos/Protocol: accuser binary -octez-accuser-PtKathma -- Tezos/Protocol: accuser binary -octez-accuser-PtLimaPt -- Tezos/Protocol: accuser binary -octez-accuser-PtMumbai -- Tezos/Protocol: accuser binary -octez-accuser-PtNairob 18.0 Tezos/Protocol: accuser binary -octez-alcotezt 18.0 Provide the interface of Alcotest for Octez, but with Tezt as backend -octez-baker-Proxford 18.0 Tezos/Protocol: baker binary -octez-baker-PtKathma -- Tezos/Protocol: baker binary -octez-baker-PtLimaPt -- Tezos/Protocol: baker binary -octez-baker-PtMumbai -- Tezos/Protocol: baker binary -octez-baker-PtNairob 18.0 Tezos/Protocol: baker binary -octez-bls12-381-hash -- Implementation of some cryptographic hash primitives using the scalar field of BLS12-381 -octez-bls12-381-polynomial -- Polynomials over BLS12-381 finite field - Temporary vendored version of Octez -octez-bls12-381-signature -- Implementation of BLS signatures for the pairing-friendly curve BLS12-381 -octez-client 18.0 Tezos: `octez-client` binary -octez-codec 18.0 Tezos: `octez-codec` binary to encode and decode values -octez-crawler 18.0 Octez: library to crawl blocks of the L1 chain -octez-dac-client 18.0 Tezos: `octez-dac-client` binary -octez-dac-node 18.0 Tezos: `octez-dac-node` binary -octez-distributed-internal 18.0 Fork of distributed. Use for Octez only -octez-distributed-lwt-internal 18.0 Fork of distributed-lwt. Use for Octez only -octez-injector 18.0 Octez: library for building injectors -octez-l2-libs 18.0 Octez layer2 libraries -octez-libs 18.0 A package that contains multiple base libraries used by the Octez suite -octez-mec -- Modular Experimental Cryptography library -octez-node 18.0 Tezos: `octez-node` binary -octez-node-config 18.0 Octez: `octez-node-config` library -octez-plompiler -- Library to write arithmetic circuits for Plonk -octez-plonk -- Plonk zero-knowledge proving system -octez-polynomial -- Polynomials over finite fields -octez-proto-libs 18.0 Octez protocol libraries -octez-protocol-000-Ps9mPmXa-libs 18.0 Octez protocol 000-Ps9mPmXa libraries -octez-protocol-001-PtCJ7pwo-libs 18.0 Octez protocol 001-PtCJ7pwo libraries -octez-protocol-002-PsYLVpVv-libs 18.0 Octez protocol 002-PsYLVpVv libraries -octez-protocol-003-PsddFKi3-libs 18.0 Octez protocol 003-PsddFKi3 libraries -octez-protocol-004-Pt24m4xi-libs 18.0 Octez protocol 004-Pt24m4xi libraries -octez-protocol-005-PsBabyM1-libs 18.0 Octez protocol 005-PsBabyM1 libraries -octez-protocol-006-PsCARTHA-libs 18.0 Octez protocol 006-PsCARTHA libraries -octez-protocol-007-PsDELPH1-libs 18.0 Octez protocol 007-PsDELPH1 libraries -octez-protocol-008-PtEdo2Zk-libs 18.0 Octez protocol 008-PtEdo2Zk libraries -octez-protocol-009-PsFLoren-libs 18.0 Octez protocol 009-PsFLoren libraries -octez-protocol-010-PtGRANAD-libs 18.0 Octez protocol 010-PtGRANAD libraries -octez-protocol-011-PtHangz2-libs 18.0 Octez protocol 011-PtHangz2 libraries -octez-protocol-012-Psithaca-libs 18.0 Octez protocol 012-Psithaca libraries -octez-protocol-013-PtJakart-libs 18.0 Octez protocol 013-PtJakart libraries -octez-protocol-014-PtKathma-libs 18.0 Octez protocol 014-PtKathma libraries -octez-protocol-015-PtLimaPt-libs 18.0 Octez protocol 015-PtLimaPt libraries -octez-protocol-016-PtMumbai-libs 18.0 Octez protocol 016-PtMumbai libraries -octez-protocol-017-PtNairob-libs 18.0 Octez protocol 017-PtNairob libraries -octez-protocol-018-Proxford-libs 18.0 Octez protocol 018-Proxford libraries -octez-protocol-alpha-libs 18.0 Octez protocol alpha libraries -octez-protocol-compiler 18.0 Tezos: economic-protocol compiler -octez-proxy-server 18.0 Octez: `octez-proxy-server` binary -octez-shell-libs 18.0 Octez shell libraries -octez-signer 18.0 Tezos: `octez-signer` binary -octez-smart-rollup-client-Proxford 18.0 Tezos/Protocol: Smart rollup client -octez-smart-rollup-client-PtMumbai -- Tezos/Protocol: Smart rollup client -octez-smart-rollup-client-PtNairob 18.0 Tezos/Protocol: Smart rollup client -octez-smart-rollup-node -- Octez: library for Smart Rollup node -octez-smart-rollup-node-lib 18.0 Octez: library for Smart Rollup node -octez-smart-rollup-node-Proxford 18.0 Tezos/Protocol: protocol specific Smart rollup node -octez-smart-rollup-node-PtMumbai -- Tezos/Protocol: protocol specific Smart rollup node -octez-smart-rollup-node-PtNairob 18.0 Tezos/Protocol: protocol specific Smart rollup node -octez-smart-rollup-wasm-benchmark-lib -- Smart Rollup WASM benchmark library -octez-smart-rollup-wasm-debugger 18.0 Tezos: Debugger for the smart rollups’ WASM kernels -octez-tx-rollup-client-PtKathma -- Tezos/Protocol: `octez-tx-rollup-client-alpha` client binary -octez-tx-rollup-client-PtLimaPt -- Tezos/Protocol: `octez-tx-rollup-client-alpha` client binary -octez-tx-rollup-node-PtKathma -- Tezos/Protocol: Transaction Rollup node binary -octez-tx-rollup-node-PtLimaPt -- Tezos/Protocol: Transaction Rollup node binary -octez-validator -- Tezos: `octez-validator` binary for external validation of blocks -octez-version 18.0 Tezos: version value generated from Git -ocurl -- Bindings to libcurl -ocveralls -- Generate JSON for http://coveralls.io from bisect code coverage data (deprecated). -odate -- Date & Duration Library -odbc -- Interface to various ODBC drivers -odds -- Dice formula library -odep -- Dependency graphs for OCaml modules, libraries and packages -odepack -- Binding to ODEPACK -odig 0.0.9 Lookup documentation of installed OCaml packages -odnnr -- Regressor using a Deep Neural Network -odoc 2.3.0 OCaml Documentation Generator -odoc-depgraph -- Custom OCamldoc generator to insert clickable dependency graphs in generated html page -odoc-parser 2.3.0 Parser for ocaml documentation comments -of_json -- A friendly applicative interface for Jsonaf. -offheap -- Copies OCaml objects out of the OCaml heap -ofx -- OCaml parser for OFX files -ogg -- Bindings to libogg -ogre -- Open Generic REpresentation NoSQL Database -ojo -- CLI tool to watch for change in the specified files -ojs -- Runtime Library for gen_js_api generated libraries -ojs-base -- Base library for developing OCaml web apps based on websockets and js_of_ocaml -ojs_base -- Base library for developing OCaml web apps based on websockets and js_of_ocaml -ojs_base_all -- Virtual package to install all ojs_base packages -ojs_base_ppx -- PPx extension for the Ojs_base library -ojs_ed -- Using file editor in ojs_base applications, common part -ojs_filetree -- Using filetrees in ojs_base applications, common part -ojs_list -- Using lists in ojs_base applications, common part -olinq -- LINQ inspired queries on in-memory data -ollvm -- ollvm library offers an interface to manipulate LLVM IR in pure OCaml. -ollvm-tapir -- a fork of ollvm with added LLVM-Tapir support -olmi -- Olmi provide functor to generate monadic combinators with a minimal interface -omake -- Build system designed for scalability and portability -omd -- A Markdown frontend in pure OCaml -ometrics -- OCaml analysis in a merge request changes -omigrate -- Database migrations for Reason and OCaml -oml -- Math Library -omlr -- Multiple Linear Regression model -omod -- Lookup and load installed OCaml modules -omtl -- OCaml Minimalist Testing Library -oneffs -- One-file filesystem is a filesystem for storing a single unnamed file -oniguruma -- Bindings to the Oniguruma regular expression library -oolc -- An Ocaml implementation of Open Location Code. -opaca -- A friendly OCaml project scaffolding tool -opal -- Self-contained monadic parser combinators for OCaml -opam-0install -- Opam solver using 0install backend -opam-0install-cudf -- Opam solver using 0install backend using the CUDF interface -opam-bin -- The opam-bin tool is a simple framework to use `opam` with binary packages -opam-build -- An opam plugin to build projects -opam-bundle -- A tool that creates stand-alone source bundles from opam packages -opam-check-npm-deps -- An opam plugin to check for npm depexts inside the node_modules folder -opam-client -- Client library for opam 2.2 -opam-compiler -- Plugin to create switches using custom compilers -opam-core 2.1.5 Core library for opam 2.1 -opam-custom-install -- An opam plugin to install a package using a custom command -opam-depext -- Install OS distribution packages -opam-devel -- Bootstrapped development binary for opam 2.2 -opam-dune-lint -- Ensure dune and opam dependencies are consistent -opam-ed -- Command-line edition tool for handling the opam file syntax -opam-file-format -- Parser and printer for the opam file syntax -opam-format -- Format library for opam 2.2 -opam-graph -- Graphing dependencies of opam packages -opam-grep -- An opam plugin that greps anything in the sources of every opam packages -opam-installer -- Installation of files to a prefix, following opam conventions -opam-lib -- The OPAM library -opam-lock -- Locking of development package definition dependency versions -opam-monorepo -- Assemble and manage fully vendored Dune repositories -opam-package-upgrade -- Upgrades opam package definition files to the latest format -opam-publish -- A tool to ease contributions to opam repositories -opam-repository -- Repository library for opam 2.2 -opam-solver -- Solver library for opam 2.2 -opam-spin -- Opam plugin for Spin, the OCaml project generator -opam-state -- State library for opam 2.2 -opam-test -- An opam plugin to test projects -opam_bin_lib -- The opam-bin tool is a simple framework to use `opam` with binary packages -opamconfig -- Virtual package owning parameters of opam installation. -opamfu -- Functions over OPAM Universes -opasswd -- OCaml bindings to the glibc passwd file and shadow password file interface -open -- Conveniently open files such as PDFs in their default applications. -openai -- OCaml OpenAI binding -openapi -- Openapi documentation generation for Opium -openapi_router -- Http server agnostic Openapi documentation generation -opencc -- Bindings for OpenCC (v1) - Open Chinese Convert -opencc0 -- Bindings for OpenCC (v0) - Open Chinese Convert -opencc1 -- Bindings for OpenCC (v1) - Open Chinese Convert -opencc1_1 -- Bindings for OpenCC (v1.1) - Open Chinese Convert -openQASM -- Parser for OpenQASM (Open Quantum Assembly Language) -openstellina -- A http client for Stellina smart telescope by Vaonis -opentelemetry -- Instrumentation for https://opentelemetry.io -opentelemetry-client-cohttp-lwt -- Collector client for opentelemetry, using cohttp + lwt -opentelemetry-client-ocurl -- Collector client for opentelemetry, using http + ezcurl -opentelemetry-cohttp-lwt -- Opentelemetry tracing for Cohttp HTTP servers -opentelemetry-lwt -- Lwt-compatible instrumentation for https://opentelemetry.io -operf-micro -- Simple tool for benchmarking the OCaml compiler -opine -- Python AST unparse implementation in OCaml -opium -- OCaml web framework -opium-graphql -- Run GraphQL servers with Opium -opium-testing -- Testing library for Opium -opium_kernel -- Sinatra like web toolkit based on Lwt + Cohttp -oplot -- Mathematical plotter library for ocaml -oplsr -- OCaml wrapper for the R 'pls' package -opomodoro -- A simple Pomodoro timer -optal -- A new language for optimization -opti -- DSL to generate fast incremental C code from declarative specifications -optimization1d -- Find extrema of 1D functions -optiml-transport -- Solve optimal transportation problems using the network simplex algorithm -optint 0.3.0 Efficient integer types on 64-bit architectures -opus -- Bindings to libopus -oqamldebug -- Graphical front-end to ocamldebug -oraft -- Raft consensus algorithm implemented in OCaml -orandforest -- A random forest classifier based on OC4.5. -oranger -- OCaml wrapper for the ranger (C++) random forests implementation -order-i3-xfce -- Order-i3-xfce is a small utility that allow you to keep a synchronized order between i3 tabs and the xfce pannel window buttons plugin -ordering 3.11.1 Element ordering -ordinal -- A language interpreter based on the Forth language -ordinal_abbreviation -- A minimal library for generating ordinal names of integers. -orec -- dynamic open records -orewa -- Async-friendly Redis client -orf -- OCaml Random Forests -orgeat -- Ocaml Random Generation of Arbitrary Types -orm -- The ORM library provides a storage backend to persist ML values. -orocksdb -- ctypes based bindings for rocksdb -orpie -- Curses-based RPN calculator -orrandomForest -- Classification or regression using Random Forests -orsetto -- A library of assorted structured data interchange languages -orsvm_e1071 -- OCaml wrapper to SVM R packages e1071 and svmpath -orun -- Run benchmarks and measure performance -orxgboost -- Gradient boosting for OCaml using the R xgboost package -osbx -- Implementation of SeqBox in OCaml -osc -- OpenSoundControl core library -osc-lwt -- OpenSoundControl Lwt library -osc-unix -- OpenSoundControl Unix library -osdp -- OCaml Interface to SDP solvers -oseq -- Simple list of suspensions, as a composable lazy iterator that behaves like a value -osh -- OCaml web API to generate SVG shields -oskel -- Skeleton generator for OCaml projects -osnap -- OCaml random snapshot testing -ostap -- Parser-combinator library -otf -- otf is a simple Output Test Framework -otfm -- OpenType font decoder for OCaml -otoggl -- Bindings for Toggl API in OCaml -otoml -- TOML parsing, manipulation, and pretty-printing library (1.0.0-compliant) -otr -- Off the record implementation purely in OCaml -ott -- A tool for writing definitions of programming languages and calculi -otto -- Otto is a testing / autograding library -ounit -- This is a transition package, ounit-lwt is now ounit2-lwt -ounit-lwt -- This is a transition package, ounit-lwt is now ounit2-lwt -ounit2 -- OUnit testing framework -ounit2-lwt -- OUnit testing framework -owee -- OCaml library to work with DWARF format -owi -- OCaml toolchain to work with WebAssembly, including and interpreter -owl -- OCaml Scientific and Engineering Computing -owl-base -- OCaml Scientific and Engineering Computing - Base -owl-jupyter -- Owl - Jupyter Wrappter -owl-ode -- Owl's ODE solvers -owl-ode-base -- Owl's ODE solvers -owl-ode-odepack -- Owl's ODE solvers, interface with ODEPACK -owl-ode-sundials -- Owl's ODE solvers, interface with SundialsML -owl-opt -- Owl's Optimisation Module -owl-opt-lbfgs -- Owl's Lbfgs Optimisation Module -owl-plplot -- OCaml Scientific and Engineering Computing -owl-top -- OCaml Scientific and Engineering Computing - Top -owork -- A productivity timer for focusing on work -ozulip -- OCaml bindings to Zulip API -p4pp -- P4PP: Preprocessor for P4 Language -p5scm -- Scheme via camlp5 -pa_comprehension -- Syntax extension for comprehension expressions -pa_monad_custom -- Syntactic Sugar for Monads -pa_ppx -- PPX Rewriters for Ocaml, written using Camlp5 -pa_ppx_hashcons -- A PPX Rewriter for Hashconsing -pa_ppx_migrate -- A PPX Rewriter for Migrating AST types (written using Camlp5) -pa_ppx_parsetree -- A Camlp5-based Quasi-Quotation ppx rewriter for OCaml's AST -pa_ppx_q_ast -- A PPX Rewriter for automating generation of data-conversion code for use with Camlp5's Q_ast -pa_ppx_quotation2extension -- A Camlp5 PPX Rewriter for treating PPX extensions as Camlp5 quotations -pa_ppx_regexp -- A Camlp5 PPX Rewriter for Perl Regexp Workalikes -pa_ppx_static -- A Camlp5 PPX Rewriter for static blocks -pa_ppx_string -- A Camlp5 PPX Rewriter for String Interpolation -pa_ppx_unique -- A PPX Rewriter for Uniqifying ASTs -pa_qualified -- A syntax extension that implements support for fully qualified module references -pa_solution -- A DSL for solving programming contest problems -pa_where -- Backward declaration syntax -packstream -- Packstream parses and serializes Packstream binary format -pacomb -- Parsing library based on combinators and ppx extension to write languages -paf -- HTTP/AF and MirageOS -paf-cohttp -- A CoHTTP client with its HTTP/AF implementation -paf-le -- A CoHTTP client with its HTTP/AF implementation -pam -- OCaml bindings for the Linux-PAM library -pandoc -- Library to write pandoc filters -pandoc-abbreviations -- Pandoc filter to add non-breaking spaces after abbreviations -pandoc-crossref -- Pandoc filter to have LaTeX cross-references -pandoc-include -- Pandoc filter to include other files -pandoc-inspect -- Pandoc filter to inspect pandoc's JSON -papi -- Performance Application Programming Interface (PAPI) bindings -parany 14.0.1 Parallelize any computation -pardi -- Parallel execution of command lines, pardi! -pareto -- GSL powered OCaml statistics library. -pari -- Type-safe wrapper over the PARI library -pari-bindings -- OCaml bindings to the PARI library -parmap -- Minimalistic library allowing to exploit multicore architecture -parse-argv -- Process strings into sets of command-line arguments -parsexp v0.16.0 S-expression parsing library -parsexp_io -- S-expression parsing library (IO functions) -parsley -- Parsley library -patch -- Patch library purely in OCaml -patdiff -- File Diff using the Patience Diff algorithm -path_glob -- Globbing file paths -patience_diff -- Diff library using Bram Cohen's patience diff algorithm -pattern -- Run-time patterns that explain match failures -pb -- Library for describing Protobuf messages -pb-plugin -- Plugin for generating pb protobuf message descriptions -pbkdf 1.2.0 Password based key derivation functions (PBKDF) from PKCS#5 -pbrt -- Runtime library for Protobuf tooling -pbs -- Helper library around PBS/Torque -pcap-format -- Decode and encode PCAP (packet capture) files -pci -- Ctypes bindings to libpci for OCaml -pci-db -- Library to parse and query the pci.ids database of PCI devices -pcre -- Bindings to the Perl Compatibility Regular Expressions library -pcre2 -- Bindings to the Perl Compatibility Regular Expressions library (version 2) -pds -- -pds-reachability -- A PDS reachability query library -pecu 0.6 Encoder/Decoder of Quoted-Printable (RFC2045 & RFC2047) -petrol -- Petrol's an OCaml SQL API made to go FAST -pf-qubes -- QubesOS firewall ruleset handling library -pg_query -- Bindings to libpg_query for parsing PostgreSQL -pgocaml -- Native OCaml interface to PostgreSQL databases -pgocaml_ppx -- PPX extension for PGOCaml -pgsolver -- A collection of tools for generating, manipulating and - most of all - solving parity games -pgx -- Pure-OCaml PostgreSQL client library -pgx_async -- Pgx using Async for IO -pgx_lwt -- Pgx using Lwt for IO -pgx_lwt_mirage -- Pgx using Lwt on Mirage for IO -pgx_lwt_unix -- Pgx using Lwt and Unix libraries for IO -pgx_unix -- PGX using the standard library's Unix module for IO (synchronous) -pgx_value_core -- Pgx_value converters for Core types like Date and Time -pgx_value_ptime -- Pgx_value converters for Ptime types -phantom-algebra -- A strongly-typed tensor library à la GLSL -phashtbl -- Persistent hash table library using dbm under the carpet. -phonetic -- Phonetic algorithm in OCaml -phylogenetics -- Algorithms and datastructures for phylogenetics -piaf -- An HTTP library with HTTP/2 support written entirely in OCaml -picasso 0.4.0 Abstract elements drawing library -piece_rope -- A data structure for efficiently manipulating strings -pilat -- Polynomial invariant generator -piqi -- Protocol Buffers, JSON and XML serialization system for OCaml -piqilib -- The Piqi library -- runtime support for multi-format Protobuf/JSON/XML/Piq data serialization and conversion -pkcs11 -- PKCS#11 OCaml types -pkcs11-cli -- Cmdliner arguments to initialize a PKCS#11 session -pkcs11-driver -- Bindings to the PKCS#11 cryptographic API -pkcs11-rev -- Reverse bindings to pkcs11 -pla -- Pla is a simple library and ppx syntax extension to create composable templates based on verbatim strings -plateau -- Print a table in a single line -plato -- Python Library Adapted To OCaml -plebeia -- Functional storage using Merkle Patricia tree -plist -- Create Apple Plists -plist-xml -- Reading and writing of plist files in the XML format in pure OCaml -plist-xml-lwt -- Reading of plist files in the XML format with Lwt -plotkicadsch -- Utilities to print and compare version of Kicad schematics -plotly -- Binding for Plotly Open Source Graphing Library -plplot -- Bindings for the PLplot library -podge -- Shortcuts and helpers for common tasks in OCaml ecosystem -polka -- Polka: convex polyhedron library by Bertrand Jeannet (now part of apron) -poll -- Portable OCaml interface to macOS/Linux/Windows native IO event notification mechanisms -polling_state_rpc -- An RPC which tracks state on the client and server so it only needs to send diffs across the wire. -polly -- Bindings for the Linux epoll system call -polyglot -- Filters to convert XHTML into polyglot HTML5 -polynomial -- Polynomials over finite fields -pomap -- Partially Ordered Maps for OCaml -popper -- Property-based testing at ease -portaudio -- Bindings for the portaudio library which provides high-level functions for using soundcards -portaudio_c_bindings -- Bindings to the C PortAudio library -portia -- Literate Programming Preprocessor -portmidi -- Bindings to libportmidi -posix-base -- Base module for the posix bindings -posix-bindings -- POSIX bindings -posix-clock -- POSIX clock -posix-getopt -- Bindings for posix getopt/getopt_long -posix-math -- POSIX math -posix-mqueue -- POSIX message queues -posix-semaphore -- POSIX semaphore -posix-signal -- Bindings for the types defined in -posix-socket -- Bindings for posix sockets -posix-socket-unix -- Bindings for posix sockets -posix-time -- POSIX time -posix-time2 -- Bindings for posix time functions -posix-types -- Bindings for the types defined in -posix-uname -- Bindings for posix uname -posixat -- Bindings to the posix *at functions -postgres_async -- OCaml/async implementation of the postgres protocol (i.e., does not use C-bindings to libpq) -postgresql -- Bindings to the PostgreSQL library -pp 1.2.0 Pretty-printing library -pp-binary-ints -- Pretty Printing Binary Integers -pp_loc 2.1.0 Quote and highlight input fragments at a given source location -pprint 20230830 A pretty-printing combinator library and rendering engine -ppx-owl-opt -- Ppx tool for owl-opt -ppx_accessor -- [@@deriving] plugin to generate accessors for use with the Accessor libraries -ppx_assert v0.16.0 Assert-like extension nodes that raise useful errors on failure -ppx_bap -- The set of ppx rewriters for BAP -ppx_base v0.16.0 Base set of ppx rewriters -ppx_bench v0.16.0 Syntax extension for writing in-line benchmarks in ocaml code -ppx_bin_prot v0.16.0 Generation of bin_prot readers and writers from types -ppx_bitstring -- Bitstrings and bitstring matching for OCaml - PPX extension -ppx_blob 0.7.2 Include a file as a string at compile time -ppx_camlrack -- PPX for matching S-Expressions -ppx_catch -- A PPX rewriter to catch exceptions and wrap into options or results -ppx_cold v0.16.0 Expands [@cold] into [@inline never][@specialise never][@local never] -ppx_compare v0.16.0 Generation of comparison functions from types -ppx_compose -- Inlined function composition -ppx_const -- Compile-time "if" statement for conditional inclusion of code -ppx_conv_func -- Deprecated -ppx_counters -- Generate useful code for stats gathering from records of counters -ppx_css -- A ppx that takes in css strings and produces a module for accessing the unique names defined within -ppx_cstruct -- Access C-like structures directly from OCaml -ppx_cstubs -- Preprocessor for easier stub generation with ctypes -ppx_csv_conv -- Generate functions to read/write records in csv format -ppx_custom_printf v0.16.0 Printf-style format-strings for user-defined string conversion -ppx_decimal -- A ppx for decimal literals -ppx_default -- Generate default values for your types -ppx_defer -- Go-like [%defer later]; now syntax -ppx_demo -- PPX that exposes the source code string of an expression/module structure. -ppx_derive_at_runtime -- Define a new ppx deriver by naming a runtime module. -ppx_derivers 1.2.1 Shared [@@deriving] plugin registry -ppx_deriving 5.2.1 Type-driven code generation for OCaml -ppx_deriving_cad -- PPX Deriver for OCADml transformation functions -ppx_deriving_cmdliner -- Cmdliner.Term.t generator -ppx_deriving_encoding -- Ppx deriver for json-encoding -ppx_deriving_hardcaml -- Rewrite OCaml records for use as Hardcaml Interfaces -ppx_deriving_hash -- [@@deriving hash] -ppx_deriving_jsoo -- Ppx deriver for Js_of_ocaml -ppx_deriving_madcast -- Library deriving cast functions based on their types -ppx_deriving_popper -- A ppx deriving sample-functions for Popper -ppx_deriving_protobuf -- A Protocol Buffers codec generator for OCaml -ppx_deriving_protocol -- Migrate to ppx_protocol_conv -ppx_deriving_qcheck -- PPX Deriver for QCheck -ppx_deriving_rpc -- Ppx deriver for ocaml-rpc, a library to deal with RPCs in OCaml -ppx_deriving_scad -- PPX Deriver for Scad_ml transformation functions -ppx_deriving_yaml -- Yaml PPX Deriver -ppx_deriving_yojson -- JSON codec generator for OCaml -ppx_disable_unused_warnings v0.16.0 Expands [@disable_unused_warnings] into [@warning "-20-26-32-33-34-35-36-37-38-39-60-66-67"] -ppx_distr_guards -- Extension to distribute guards over or-patterns -ppx_enumerate v0.16.0 Generate a list containing all values of a finite type -ppx_expect v0.16.0 Cram like framework for OCaml -ppx_factory -- PPX to derive factories and default values -ppx_fail -- Add location to calls to failwiths -ppx_fields_conv v0.16.0 Generation of accessor and iteration functions for ocaml records -ppx_fixed_literal v0.16.0 Simpler notation for fixed point literals -ppx_gen_rec -- A ppx rewriter that transforms a recursive module expression into a `struct` -ppx_getenv -- A sample syntax extension using OCaml's new extension points API -ppx_globalize v0.16.0 A ppx rewriter that generates functions to copy local values to the global heap -ppx_hash v0.16.0 A ppx rewriter that generates hash functions from type expressions and definitions -ppx_here v0.16.0 Expands [%here] into its location -ppx_ignore_instrumentation v0.16.0 Ignore Jane Street specific instrumentation extensions -ppx_import 1.10.0 A syntax extension for importing declarations from interface files -ppx_inline_alcotest -- Inline tests backend for alcotest -ppx_inline_test v0.16.0 Syntax extension for writing in-line tests in ocaml code -ppx_interact -- Opens a REPL in context -ppx_irmin 3.7.2 PPX deriver for Irmin type representations -ppx_jane v0.16.0 Standard Jane Street ppx rewriters -ppx_js_style -- Code style checker for Jane Street Packages -ppx_jsobject_conv -- Ppx plugin for Typeconv to derive conversion from ocaml types to js objects to use with js_of_ocaml -ppx_jsonaf_conv -- [@@deriving] plugin to generate Jsonaf conversion functions -ppx_let v0.16.0 Monadic let-bindings -ppx_log v0.16.0 Ppx_sexp_message-like extension nodes for lazily rendering log messages -ppx_lun -- Optics with lun package and PPX -ppx_make -- [@@deriving make] -ppx_map -- A PPX rewriter to simplify the declaration of maps -ppx_matches -- Small ppx to help check if a value matches a pattern -ppx_meta_conv -- PPX for converting between OCaml values and JSON, Sexp and camlon -ppx_minidebug -- Debug logs for selected functions and let-bindings -ppx_module_timer v0.16.0 Ppx rewriter that records top-level module startup times -ppx_monad -- A Syntax Extension for all Monadic Syntaxes -ppx_monoid -- Syntax extension for building values of monoids -ppx_mysql -- Syntax extension for facilitating usage of MySQL bindings -ppx_optcomp v0.16.0 Optional compilation for OCaml -ppx_optint -- Literals for Optint integers -ppx_optional v0.16.0 Pattern matching on flat options -ppx_parser -- OCaml PPX extension for writing stream parsers -ppx_pattern_bind -- A ppx for writing fast incremental bind nodes in a pattern match -ppx_pipebang v0.16.0 A ppx rewriter that inlines reverse application operators `|>` and `|!` -ppx_protocol_conv -- Ppx for generating serialisation and de-serialisation functions of ocaml types -ppx_protocol_conv_json -- Json driver for Ppx_protocol_conv -ppx_protocol_conv_jsonm -- Jsonm driver for Ppx_protocol_conv -ppx_protocol_conv_msgpack -- MessagePack driver for Ppx_protocol_conv -ppx_protocol_conv_xml_light -- Xml driver for Ppx_protocol_conv -ppx_protocol_conv_xmlm -- Xmlm driver for Ppx_protocol_conv -ppx_protocol_conv_yaml -- Yaml driver for Ppx_protocol_conv -ppx_pyformat -- Ppxlib based string format rewriter inspired by Python string `format` -ppx_python -- [@@deriving] plugin to generate Python conversion functions -ppx_rapper -- Syntax extension for Caqti/PostgreSQL queries -ppx_rapper_async -- Async support for ppx_rapper -ppx_rapper_lwt -- Lwt support for ppx_rapper -ppx_regexp -- Matching Regular Expressions with OCaml Patterns -ppx_repr 0.7.0 PPX deriver for type representations -ppx_seq -- Seq literals ppx for OCaml -ppx_sexp_conv v0.16.0 [@@deriving] plugin to generate S-expression conversion functions -ppx_sexp_message v0.16.0 A ppx rewriter for easy construction of s-expressions -ppx_sexp_value v0.16.0 A ppx rewriter that simplifies building s-expressions from ocaml values -ppx_show -- OCaml PPX deriver for deriving show based on ppxlib -ppx_stable v0.16.0 Stable types conversions generator -ppx_stable_witness v0.16.0 Ppx extension for deriving a witness that a type is intended to be stable. In this context, stable means that the serialization format will never change. This allows programs running at different versions of the code to safely communicate. -ppx_string v0.16.0 Ppx extension for string interpolation -ppx_string_interpolation -- String interpolation PPX preprocessor -ppx_subliner -- [@@deriving subliner] and [%%subliner] for Cmdliner -ppx_system -- A ppx to know host operating system at compile time -ppx_test -- A ppx replacement of pa_ounit -ppx_tools -- Tools for authors of ppx rewriters and other syntactic tools -ppx_traverse_builtins -- Builtins for Ppx_traverse -ppx_ts -- A PPX helps binding to typescript modules -ppx_tydi v0.16.0 Let expressions, inferring pattern type from expression. -ppx_type_directed_value -- Get [@@deriving]-style generation of type-directed values without writing a ppx -ppx_typed_fields -- GADT-based field accessors and utilities -ppx_typerep_conv v0.16.0 Generation of runtime types from type declarations -ppx_units -- Generate unit types for every record field -ppx_update -- PPX library to optimize record updates -ppx_variants_conv v0.16.0 Generation of accessor and iteration functions for ocaml variant types -ppx_viewpattern -- View patterns in OCaml -ppx_xml_conv -- Generate XML conversion functions from records -ppx_yojson -- PPX extension for Yojson literals and patterns -ppx_yojson_conv -- [@@deriving] plugin to generate Yojson conversion functions -ppx_yojson_conv_lib v0.16.0 Runtime lib for ppx_yojson_conv -ppxlib 0.31.0 Standard infrastructure for ppx rewriters -ppxx -- Ppxx: a small extension library for writing PPX preprocessors -pratter -- An extended Pratt parser -prbnmcn-basic-structures 0.0.1 Base package for prbnmcn-* packages -prbnmcn-cgrph -- Incremental computation -prbnmcn-clustering -- Clustering library -prbnmcn-dagger -- Probabilistic programming library -prbnmcn-dagger-gsl -- Probabilistic programming library: GSL-based samplers -prbnmcn-dagger-stats -- Probabilistic programming library: prbnmcn-stats-based samplers -prbnmcn-dagger-test -- Probabilistic programming library: tests -prbnmcn-gnuplot -- Declarative generation of gnuplot scripts -prbnmcn-linalg 0.0.1 Functional vector and matrix manipulation -prbnmcn-mcts -- Monte-Carlo tree search based on UCB1 bandits -prbnmcn-proptest -- Property-based test helpers for prbnmcn packages -prbnmcn-stats 0.0.6 Basic statistics -prbnmcn-ucb1 -- UCB1 algorithm for multi-armed bandits -prc -- Utilities for precision-recall curves -preface -- An opinionated library for function programming (à La Haskell) -prettym 0.0.3 An memory-bounded encoder according to RFC 822 -primes -- A small library for dealing with primes. -pringo 1.3 Pseudo-random, splittable number generators -printbox -- Allows to print nested boxes, lists, arrays, tables in several formats -printbox-html -- Printbox unicode handling -printbox-text -- Text renderer for printbox, using unicode edges -proc-smaps -- Proc-smaps: An ocaml parser of /proc/[pid]/smaps -process -- Easy process control -process_limits -- Setting time and memory limits for your program -processor -- Processor Topology & Affinity for ocaml -producer -- Accumulate results using monadic dependency graphs -profiler-plugin -- Alt-Ergo, an SMT Solver for Software Verification: Profiler Plugin -profiling -- Small library to help profile code -profunctor -- A library providing a signature for simple profunctors and traversal of a record -progress 0.2.1 User-definable progress bars -proj4 -- Bindings to the PROJ.4 projection library -prom -- Types and pretty printer for Prometheus text-based exposition format -prometheus 1.2 Client library for Prometheus monitoring -prometheus-app 1.2 Client library for Prometheus monitoring -prometheus-liquidsoap -- Virtual package installing liquidsoap dependencies for prometheus optional features -promise -- Native implementation of a JS promise binding -promise_jsoo -- Js_of_ocaml bindings to JS Promises with supplemental functions -protocell -- A Protobuf plugin for OCaml -protocol-9p -- An implementation of the 9p protocol in pure OCaml -protocol-9p-tool -- An implementation of the 9p protocol in pure OCaml -protocol-9p-unix -- A Unix implementation of the 9p protocol in pure OCaml -protocol_version_header v0.16.0 Protocol versioning -proverif -- ProVerif: Cryptographic protocol verifier in the symbolic model -proverifdoc -- Documentation for ProVerif, a cryptographic protocol verifier in the symbolic model -prr -- A fork of brr, sans browser-only APIs -psmt2-frontend 0.4.0 The psmt2-frontend project -psq 0.2.1 Functional Priority Search Queues -psyche -- A WASM-friendly lightweight programming language implemented in OCaml -ptime 1.1.0 POSIX time for OCaml -ptmap -- Maps of integers implemented as Patricia trees -ptset -- Sets of integers implemented as Patricia trees -publish -- opam-publish transition package -pulseaudio -- Bindings to Pulseaudio client library -pure-splitmix 0.3 Purely functional splittable PRNG -pvec -- Persistent vectors -pvem -- Polymorphic-Variants-based Error Monad -pxp -- Polymorphic XML Parser -py -- Ctypes bindings to Python 3.5 or greater -pyast -- Python AST -pyml 20220905 OCaml bindings for Python -pyml_bindgen -- Generate pyml bindings from OCaml value specifications -pyre-ast -- Full-fidelity Python parser in OCaml -pythonlib -- A library to help writing wrappers around ocaml code for python -qbf -- QBF solving in OCaml, including bindings to solvers -qcheck -- Compatibility package for qcheck -qcheck-alcotest 0.21.2 Alcotest backend for qcheck -qcheck-core 0.21.2 Core qcheck library -qcheck-lin -- A multicore testing library for OCaml -qcheck-multicoretests-util -- Various utility functions for property-based testing of multicore programs -qcheck-ounit -- OUnit backend for qcheck -qcheck-stm -- State-machine testing library for sequential and parallel model-based tests -qcow -- Support for Qcow2 images -qcow-tool -- A command-line tool for manipulating qcow2-formatted data -qcstm -- A simple state-machine framework for OCaml based on QCheck -qfs -- Bindings to libqfs - client library to access QFS -qinap -- A (very small) monadic parsing library -qiskit -- Qiskit for OCaml -qmp -- OCaml implementation of a Qemu Message Protocol (QMP) client -qrc -- QR code encoder for OCaml -qrencode -- Binding to libqrencode (QR-code encoding library) -qtest -- Lightweight inline test extraction from comments -queenshead -- British pub name generator -quest -- quest - generates C code for testing a C compiler's calling convention -quests -- HTTP/1.1 client library like Python requests -quick_print -- Quick and easy printing for lists, arrays, etc -r2pipe -- Deprecated: use radare2 instead -radamsa -- Radamsa bindings for OCaml -radare2 -- OCaml interface to r2 -randii -- A pure OCaml port of the Random123 counter based random number generator from DEShaw Research -randomconv -- Convert from random byte vectors (Cstruct.t) to random native numbers -randoml -- Generating cryptographically-secure random numbers -range -- Fold on integer range -ranger -- A consecutive range slice library for strings, arrays, etc. -rangeSet -- RangeSet: a library for sets over ordered ranges -rankers -- Vanishing Ranking Kernels (VRK) -rawlink -- Portable library to read and write raw packets -rawlink-lwt -- Portable library to read and write raw packets with Lwt bindings -raygui -- OCaml bindings for raygui -raygun4ocaml -- Client for the Raygun error reporting API -raylib -- OCaml bindings for raylib -rdbg -- RDBG: a reactive programs debugger -rdf -- OCaml library to manipulate RDF graphs; implements SPARQL -rdf_json_ld -- Json-ld -rdf_lwt -- Sparql HTTP with Lwt -rdf_mysql -- Mysql backend for rdf -rdf_postgresql -- Postgresql backend for rdf -rdf_ppx -- Syntax extension for rdf -rdr -- Rdr is a cross-platform binary analysis and reverse engineering tool, utilizing a unique symbol map for global analysis. -re 1.11.0 RE is a regular expression library for OCaml -re2 -- OCaml bindings for RE2, Google's regular expression library -re2_stable -- Re2_stable adds an incomplete but stable serialization of Re2 -re_parser -- Typed parsing using regular expressions. -rea -- Effectful OCaml with Objects and Variants -react -- Declarative events and signals for OCaml -reactiveData -- Declarative events and signals for OCaml -reactjs-jsx-ppx -- ReactJS JSX PPX -readline -- OCaml bindings for GNU readline -reanalyze -- Dead values/types, exception, and termination analysis for OCaml/ReScript -reason -- Reason: Syntax & Toolchain for OCaml -reason-react -- Reason bindings for React.js -reason-react-ppx -- React.js JSX PPX -received -- Received field according RFC5321 -record_builder -- A library which provides traversal of records with an applicative -records -- Dynamic records -reddit_api_async -- Async connection and utility functions for Reddit's API -reddit_api_kernel -- OCaml types for Reddit's API -redirect -- Redirect channels -redis 0.7.1 Redis client -redis-async -- Redis client for Async applications -redis-lwt -- Redis client (lwt interface) -redis-sync -- Redis client (blocking) -reedsolomon -- Reed-Solomon Error Correction CODEC -refl -- PPX deriver for reflection -regenerate -- Regenerate is a tool to generate test-cases for regular expression engines -regex_parser_intf -- Interface shared by Re_parser and Re2.Parser -regular -- Library for regular data types -remu_ts -- External type infer -reparse -- Recursive descent parsing library for ocaml -reparse-lwt -- Reparse Lwt_stream.t input support -reparse-lwt-unix -- Reparse lwt-unix based input support -reparse-unix -- Provides support for parsing files as source of input for reparse library -repr 0.7.0 Dynamic type representations. Provides no stability guarantee -repr-bench -- Benchmarks for the `repr` package -repr-fuzz -- Fuzz tests for the `repr` package -res -- RES - Library for resizable, contiguous datastructures -res_tailwindcss -- PPX validates the tailwindcss class names -rescript-syntax -- ReScript syntax packaged as an opam library -resource-pooling -- Library for pooling resources like connections, threads, or similar -resource_cache -- General resource cache -resp -- Redis serialization protocol library -resp-client -- Redis serialization protocol client library -resp-mirage -- Redis serialization protocol for MirageOS -resp-server -- Redis serialization protocol server -resp-unix -- Redis serialization protocol for Unix -resto 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs -resto-acl 1.2 Access Control Lists for Resto -resto-cohttp 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs -resto-cohttp-client 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs -resto-cohttp-self-serving-client 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs -resto-cohttp-server 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs - server library -resto-directory 1.2 A minimal OCaml library for type-safe HTTP/JSON RPCs -resto-json -- A minimal OCaml library for type-safe HTTP/JSON RPCs -result 1.5 Compatibility Result module -revops -- Reversible operations -rfc1951 -- Implementation of RFC1951 in OCaml -rfc6287 -- OCRA (OATH Challenge-Response Algorithm) implementation in OCaml -rfc7748 -- Edwards Curves X25519 and X448 from RFC 7748 -rfsm -- A toolset for describing and simulating StateChart-like state diagrams -rhythm -- Data Structures and Algorithms implemented in Reason -ringo 1.0.0 Bounded-length collections -ringo-lwt -- Lwt-wrappers for Ringo caches -river -- RSS2 and Atom feed aggregator for OCaml -rlp -- RLP: Recursive Length Prefix Encoding -rml -- ReactiveML: a programming language for implementing interactive systems -rmlbuild -- rmlbuild is a fork of ocamlbuild that handles ReactiveML projets -rock -- Minimalist framework to build extensible HTTP servers and clients -roman -- Manipulate roman numerals (ocaml.org dune/opam tutorial) -root1d -- Find roots of 1D functions -rope -- Ropes (heavyweight strings) -rosa -- String manipulation library -rosetta -- Universal mapper to Unicode -routes -- Typed routing for OCaml applications -rpc -- A library to deal with RPCs in OCaml - meta-package -rpc_parallel -- Type-safe parallel library built on top of Async_rpc -rpclib -- A library to deal with RPCs in OCaml -rpclib-async -- A library to deal with RPCs in OCaml - Async interface -rpclib-html -- A library to deal with RPCs in OCaml - html documentation generator -rpclib-js -- A library to deal with RPCs in OCaml - Bindings for js_of_ocaml -rpclib-lwt -- A library to deal with RPCs in OCaml - Lwt interface -rresult 0.7.0 Result value combinators for OCaml -rsdd -- Bindings for RSDD -rss -- Library to read and write RSS files -rtop -- Reason toplevel -rtree -- A pure OCaml R-Tree implementation -rungen -- Generates dune files to run benchmarks from centralised config -rusage 1.0.0 Bindings to the GETRUSAGE(2) syscall -Snowflake -- Snowflake : A Generic Symbolic Dynamic Programming framework -SZXX -- Streaming ZIP XML XLSX parser -safa -- Symbolic Algorithms for Finite Automata -safemoney -- A type safe money manipulation library -safepass -- Facilities for the safe storage of user passwords -sail -- Sail is a language for describing the instruction semantics of processors -sail_c_backend -- Sail to C translation -sail_coq_backend -- Sail to Coq translation -sail_doc_backend -- Sail documentation generator -sail_latex_backend -- Sail to LaTeX formatting -sail_lem_backend -- Sail to Lem translation -sail_manifest -- Helper tool for compiling Sail -sail_ocaml_backend -- Sail to OCaml translation -sail_output -- Example Sail output plugin -sail_smt_backend -- Sail to C translation -salsa20 -- Salsa20 family of encryption functions, in pure OCaml -salsa20-core -- The Salsa20 core functions, in OCaml -samplerate -- Samplerate audio conversion library -sanddb -- A simple immutable database for the masses -sarek -- GPGPU kernel DSL for OCaml -satML-plugin -- Alt-Ergo, an SMT Solver for Software Verification: satML Plugin -sattools -- Ctypes and DIMACs interfaces to minisat, picosat and cryptominisat -saturn -- Parallelism-safe data structures for multicore OCaml -saturn_lockfree -- Lock-free data structures for multicore OCaml -satyrographos -- A package manager for SATySFi -sawja -- Sawja provides a high level representation of Java bytecode programs and static analysis tools -scad_ml -- OCaml DSL for 3D solid modelling in OpenSCAD -scfg -- OCaml library and executable to work with the scfg configuration file format -scgi -- Simple Common Gateway Interface (SCGI) protocol support for interface with HTTP servers -schroedinger -- Bindings for the schroedinger library to decode video files in Dirac format -scid -- Sierra Chart's Intraday Data File Format library -scipy -- SciPy scientific computing library for OCaml -scrypt -- C bindings and a high level interface to the official scrypt distribution. -scrypt-kdf -- The scrypt Password-Based Key Derivation Function -sd_logic -- Functionality for time-based finite state machine -sdl-liquidsoap -- Virtual package installing liquidsoap dependencies for SDL optional features -search -- Simple, in-memory search library in pure OCaml -searchTree -- A module to easily implement search trees -secp256k1 -- Elliptic curve library secp256k1 wrapper for Ocaml -secp256k1-internal 0.4.0 Bindings to secp256k1 internal functions (generic operations on the curve) -sedlex 3.2 An OCaml lexer generator for Unicode -sek -- An efficient implementation of ephemeral and persistent sequences -sel -- Simple Event Library -semantic_version -- Semantic versioning -semaphore-compat 1.0.1 Compatibility Semaphore module -semver -- Semantic Versioning (semver) library -semver2 -- Semantic version handling for OCaml -sendmail -- Implementation of the sendmail command -sendmail-lwt -- Implementation of the sendmail command over LWT -sendmsg -- π-calculus? In _my_ kernel? -sentry -- Unofficial Async Sentry error monitoring client -seq base Compatibility package for OCaml's standard iterator type starting from 4.07. -seqes 0.2 Seq with monads -sequence -- Simple sequence abstract datatype. -sequencer_table -- A table of [Async.Sequencer]'s, indexed by key -serde -- A serialization framework for OCaml -serde_debug -- A human-friendly format for Serde that helps you debug any data during development -serde_derive -- Derive-macros for the Serde serialization framework -serde_json -- JSON format support for Serde -serde_sexpr -- S-expression format support for Serde -serde_xml -- XML format support for Serde -serial -- Serial communication module -session -- A session manager for your everyday needs -session-cohttp -- A session manager for your everyday needs - Cohttp-specific support -session-cohttp-async -- A session manager for your everyday needs - Cohttp-specific support for Async -session-cohttp-lwt -- A session manager for your everyday needs - Cohttp-specific support for Lwt -session-cookie -- Session handling for OCaml and ReasonML -session-cookie-async -- Session handling for OCaml and ReasonML -session-cookie-lwt -- Session handling for OCaml and ReasonML -session-postgresql -- A session manager for your everyday needs - Postgresql-specific support -session-postgresql-async -- A session manager for your everyday needs - Postgresql-specific support for Async -session-postgresql-lwt -- A session manager for your everyday needs - Postgresql-specific support -session-redis-lwt -- A session manager for your everyday needs - Redis-specific support for Lwt -session-webmachine -- A session manager for your everyday needs - Webmachine-specific support -sessions -- Library to provide session types to allow for static verification of protocols between concurrent computations -setcore -- Pin current process to given core number -setr -- Abstract domain library for sets -sexp -- S-expression swiss knife -sexp_decode -- A library to decode S-expression into structured data -sexp_diff -- Code for computing the diff of two sexps -sexp_diff_kernel -- Code for computing the diff of two sexps -sexp_grammar -- Sexp grammar helpers -sexp_macro -- Sexp macros -sexp_pretty v0.16.0 S-expression pretty-printer -sexp_select -- A library to use CSS-style selectors to traverse sexp trees -sexp_string_quickcheck -- Quickcheck helpers for strings parsing to sexps -sexplib v0.16.0 Library for serializing OCaml values to and from S-expressions -sexplib0 v0.16.0 Library containing the definition of S-expressions and some base converters -sfml -- Bindings to the SFML multimedia library -sgf -- Parser and pretty printer for SGF files -sha -- Binding to the SHA cryptographic functions -shapefile -- A small library to read ESRI shapefiles -shared-block-ring -- A single-consumer single-producer queue on a block device -shared-memory-ring -- Shared memory rings for RPC and bytestream communications -shared-memory-ring-lwt -- Shared memory rings for RPC and bytestream communications using Lwt -shared-secret -- Exceptions are shared secrets -shcaml -- Library for Unix shell programming -shell -- Yet another implementation of fork&exec and related functionality -shexp -- Process library and s-expression based shell -shine -- Fixed-point MP3 encoder -shuttle -- Reasonably performant non-blocking channels for async -shuttle_http -- Async library for HTTP/1.1 servers and clients -shuttle_ssl -- Async_ssl support for shuttle -shuttle_websocket -- Websocket support for HTTP/1.1 servers using Async -sid -- Handle security identfiers -sifun -- Interpreter for SiFun (Simple Functional) Language with three different type systems (supports Higher Rank Polymorphism) -sihl -- The Sihl web framework -sihl-cache -- Cache service implementations for Sihl -sihl-contract -- Sihl serivce interfaces -sihl-core -- The core of the Sihl web framework -sihl-email -- Email service implementations for Sihl -sihl-facade -- Sihl service facade that uses the facade pattern to hide service implementations -sihl-persistence -- Sihl services to deal with data persistence -sihl-queue -- Queue service implementations for Sihl -sihl-session -- Sihl service to deal with sessions -sihl-storage -- Storage service implementations for Sihl -sihl-token -- Token service implementations for Sihl -sihl-type -- Contains Sihl types that are returned by Sihl services -sihl-user -- User service implementations for Sihl -sihl-web -- Sihl HTTP service and middlewares -simlog -- A simple OCaml logging library -simple-diff -- Simple_diff is a pure OCaml diffing algorithm. -simple63 -- Integer compression and decompression module -simple_pam -- Tiny binding around PAM -sklearn -- Scikit-learn machine learning library for OCaml -slacko -- Type-safe binding to the Slack API -slug -- Url safe slug generator -smart-print -- A pretty-printing library in OCaml -smbc -- Experimental model finder/SMT solver for functional programming -smol -- Small Math Ocaml Library -smol-helpers -- Test helpers for smol -smtlib-utils -- Parser for SMTLIB2 -smtp -- SMTP library with Unix and Lwt backends -snappy -- Bindings to snappy - fast compression/decompression library -snoke -- Snóke is a good old Snake game with new ideas -socketcan -- socketcan -sodium -- Binding to libsodium UNAUDITED -sodium-fmt -- Fmt formatters for Sodium -solid -- Library to build SOLID applications -solid_server -- SOLID server under development -solid_tools -- Library to build SOLID tools -solidity-alcotest -- The ocaml-solidity project -solidity-common -- The ocaml-solidity project -solidity-parser -- The ocaml-solidity project -solidity-test -- The ocaml-solidity project -solidity-typechecker -- The ocaml-solidity project -solo5 -- Solo5 sandboxed execution environment -solo5-bindings-hvt -- Solo5 sandboxed execution environment (hvt target) -solo5-bindings-muen -- Solo5 sandboxed execution environment (muen target) -solo5-bindings-spt -- Solo5 sandboxed execution environment (spt target) -solo5-bindings-virtio -- Solo5 sandboxed execution environment (virtio target) -solo5-bindings-xen -- Solo5 sandboxed execution environment (xen target) -solo5-elftool -- OCaml Solo5 elftool for querying solo5 manifests -solo5-kernel-muen -- Solo5 sandboxed execution environment (muen target) -solo5-kernel-ukvm -- Solo5 sandboxed execution environment (ukvm target) -solo5-kernel-virtio -- Solo5 sandboxed execution environment (virtio target) -sortedseq_intersect -- A divide-and-conquer algorithm to intersect sorted sequences -sosa -- Sane OCaml String API -soundtouch -- Bindings for the soundtouch library which provides functions for changing pitch and timestretching audio data -soupault -- Static website generator based on HTML rewriting -spawn v0.15.1 Spawning sub-processes -spdx_licenses -- A library providing a strict SPDX License Expression parser -spectrum -- Library for colour and formatting in the terminal -speex -- Bindings to libspeex -spelll 0.4 Fuzzy string searching, using Levenshtein automaton -spf -- OCaml bindings for libspf2 -spin -- OCaml project generator -spirv -- SPIR-V Compiler Library -splay_tree -- A splay tree implementation -splittable_random v0.16.0 PRNG that can be split into independent streams -spoc -- High-level GPGPU programming library for OCaml -spoc_ppx -- PPX to declare external GPGPU kernels written in CUDA or OpenCL -spoke -- SPAKE+EE implementation in OCaml -spotify-web-api -- OCaml bindings to the Spotify web API -spotlib -- Useful functions for OCaml programming used by @camlspotter -spreadsheet -- Functor for parsing and building spreadsheets. -sqlgg -- SQL Guided (code) Generator -sqlite3 -- SQLite3 bindings for OCaml -sqlite3_utils -- High-level wrapper around ocaml-sqlite3 -squirrel -- The Squirrel Prover is a proof assistant for protocols, based on first-order logic and provides guarantees in the computational model -srs -- OCaml bindings for libsrs2 -srt -- Binding for the Secure, Reliable, Transport protocol library -ssh-agent -- Ssh-agent protocol parser and serialization implementation -ssh-agent-unix -- Ssh-agent protocol parser and serialization implementation for unix platforms -ssl 0.7.0 Bindings for OpenSSL -statverif -- StatVerif: automated verifier for cryptographic protocols with state, based on ProVerif -stb_image -- OCaml bindings to stb_image, a public domain image loader -stb_image_write -- OCaml bindings to stb_image_write, a public domain image writer -stb_truetype -- OCaml bindings to stb_truetype, a public domain font rasterizer -stdcompat 19 Compatibility module for OCaml standard library -stdint 0.7.2 Signed and unsigned integer types having specified widths -stdint-literals -- Small PPX for fixed size integer literals -stdio v0.16.0 Standard IO library for OCaml -stdlib-diff -- Symmetric Diffs for OCaml stdlib and ReasonML -stdlib-random -- Versioned Random module from the OCaml standard library -stdlib-shims 0.3.0 Backport some of the new stdlib features to older compiler -stdune 3.11.1 Dune's unstable standard library -stemmer -- Porter stemming algorithm in pure OCaml -stemming -- Collection of stemmers -stitch -- Refactoring framework -stk -- SDL-based GUI toolkit -stk_iconv -- Bindings to GNU libiconv -stone -- Simple static website generator, useful for a portfolio or documentation pages -stored_reversed -- A library for representing a list temporarily stored in reverse order. -stramon-lib -- Process behavior monitoring library based on strace -streamable -- A collection of types suitable for incremental serialization -streaming -- Fast, safe and composable streaming abstractions -string_dict -- Efficient static string dictionaries -stringCodepointSplitter -- Split a string to a list of strings of a character by the unicode codepoint -stringext 1.6.0 Extra string functions for OCaml -sturgeon -- A toolkit for communicating with Emacs -subscriptions-transport-ws -- Websocket protocol for exchanging GraphQL requests and responses -subtype-refinement -- Refinement types encoded with private types in OCaml -sugar -- Monadic library for error aware expressions -sun -- Take screenshot under Wayland -sundialsml -- Interface to the Sundials suite of numerical solvers -svmwrap -- Wrapper on top of libsvm-tools -swagger -- Swagger 2.0 code generator for OCaml -swhid -- OCaml library to work with Software Heritage identifiers -swhid_compute -- OCaml library to work with Software Heritage identifiers, compute library used in swhid -swhid_core -- OCaml library to work with swhids -swhid_types -- OCaml library to work with Software Heritage identifiers, types library used in swhid -swipl -- Bindings to SWI-Prolog for OCaml -syguslib-utils -- SyGuS Lib parser and utils -symkat -- Symbolic Algorithms for Kleene algebra with Tests (KAT) -syncweb -- Syncweb, Literate Programming meets Unison -syndic -- RSS1, RSS2, Atom and OPML1 parsing -sys-socket -- Ctypes bindings to system-specific low-level socket structure and data-types -sys-socket-unix -- Ctypes bindings to unix-specific low-level socket structure and data-types -syslog -- syslog(3) routines for ocaml (RFC 3164) -syslog-message -- Syslog message parser -syslog-rfc5424 -- Syslog Protocol (RFC5424) parser and pretty-printer -systemverilog -- SystemVerilog for OCaml -TCSLib -- A multi-purpose library for OCaml. -tablecloth-native -- Native OCaml library implementing Tablecloth, a cross-platform standard library for OCaml, Bucklescript and ReasonML -taglib -- Bindings for the taglib library -talaria-bibtex -- A parser for bibtex files -tar 2.6.0 Decode and encode tar format files in pure OCaml -tar-mirage -- Read and write tar format files via MirageOS interfaces -tar-unix 2.6.0 Decode and encode tar format files from Unix -tcalc -- Minimal desktop calculator for timestamps -tcpip -- OCaml TCP/IP networking stack, used in MirageOS -tcx -- OCaml library for parsing and formatting Training Center XML files. -tdigest -- OCaml implementation of the T-Digest algorithm -tdk -- The Decision Kit is a collection of data structures that are useful -telegraml -- Telegram Bot API for OCaml -telltime -- Cli tool for interacting with Daypack-lib components -tensorboard -- -termbox -- Bindings for the termbox library, minimalistic API for creating text-based interfaces -terminal 0.2.1 Basic utilities for interacting with terminals -terminal_size -- Get the dimensions of the terminal -terminus -- A generic client to interact with Rest API -terminus-cohttp -- Terminus with the cohttp-lwt-unix request handler -terminus-hlc -- Terminus with the http-lwt-client request handler -testu01 -- OCaml bindings for TestU01 1.2.3 -text -- Library for dealing with "text", i.e. sequence of unicode characters, in a convenient way -text-tags -- A library for rich formatting using semantics tags -textmate-language -- Tokenizing code with TextMate grammars for syntax highlighting -textrazor -- An OCaml wrapper for the TextRazor API -textutils v0.16.0 Text output utilities -textutils_kernel v0.16.0 Text output utilities -textwrap -- Text wrapping and filling for OCaml -tezos -- Tezos meta package installing all active binaries -tezos-012-Psithaca-test-helpers -- Tezos/Protocol: protocol testing framework -tezos-013-PtJakart-test-helpers -- Tezos/Protocol: protocol testing framework -tezos-014-PtKathma-test-helpers -- Tezos/Protocol: protocol testing framework -tezos-accuser-012-Psithaca -- Tezos/Protocol: accuser binary -tezos-accuser-013-PtJakart -- Tezos/Protocol: accuser binary -tezos-accuser-014-PtKathma -- Tezos/Protocol: accuser binary -tezos-accuser-alpha -- Tezos/Protocol: accuser binary -tezos-alpha-test-helpers -- Tezos/Protocol: protocol testing framework -tezos-baker-012-Psithaca -- Tezos/Protocol: baker binary -tezos-baker-013-PtJakart -- Tezos/Protocol: baker binary -tezos-baker-014-PtKathma -- Tezos/Protocol: baker binary -tezos-baker-alpha -- Tezos/Protocol: baker binary -tezos-baking-012-Psithaca -- Tezos/Protocol: base library for `tezos-baker/accuser` -tezos-baking-012-Psithaca-commands -- Tezos/Protocol: protocol-specific commands for baking -tezos-baking-013-PtJakart -- Tezos/Protocol: base library for `tezos-baker/accuser` -tezos-baking-013-PtJakart-commands -- Tezos/Protocol: protocol-specific commands for baking -tezos-baking-014-PtKathma -- Tezos/Protocol: base library for `tezos-baker/accuser` -tezos-baking-014-PtKathma-commands -- Tezos/Protocol: protocol-specific commands for baking -tezos-baking-015-PtLimaPt -- Tezos/Protocol: base library for `tezos-baker/accuser` -tezos-baking-015-PtLimaPt-commands -- Tezos/Protocol: protocol-specific commands for baking -tezos-baking-016-PtMumbai -- Tezos/Protocol: base library for `tezos-baker/accuser` -tezos-baking-016-PtMumbai-commands -- Tezos/Protocol: protocol-specific commands for baking -tezos-baking-017-PtNairob -- Tezos/Protocol: base library for `tezos-baker/accuser` -tezos-baking-017-PtNairob-commands -- Tezos/Protocol: protocol-specific commands for baking -tezos-baking-alpha -- Tezos/Protocol: base library for `tezos-baker/accuser` -tezos-baking-alpha-commands -- Tezos/Protocol: protocol-specific commands for baking -tezos-base -- Tezos: meta-package and pervasive type definitions for Tezos -tezos-base-test-helpers -- Tezos: Tezos base test helpers -tezos-base58 -- Base58 encoding for Tezos -tezos-benchmark 18.0 Tezos: library for writing benchmarks and performing simple parameter inference -tezos-bls12-381-polynomial -- Polynomials over BLS12-381 finite field -tezos-clic -- Tezos: library of auto-documented command-line-parsing combinators -tezos-client -- Tezos: `tezos-client` binary -tezos-client-000-Ps9mPmXa -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-001-PtCJ7pwo -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-002-PsYLVpVv -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-003-PsddFKi3 -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-004-Pt24m4xi -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-005-PsBabyM1 -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-006-PsCARTHA -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-007-PsDELPH1 -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-008-PtEdo2Zk -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-009-PsFLoren -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-010-PtGRANAD -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-011-PtHangz2 -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-012-Psithaca -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-013-PtJakart -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-014-PtKathma -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-015-PtLimaPt -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-016-PtMumbai -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-017-PtNairob -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-alpha -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-base -- Tezos: common helpers for `tezos-client` -tezos-client-base-unix -- Tezos: common helpers for `tezos-client` (unix-specific fragment) -tezos-client-commands -- Tezos: protocol agnostic commands for `tezos-client` -tezos-client-demo-counter -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-client-genesis -- Tezos/Protocol: protocol specific library for `tezos-client` -tezos-codec -- Tezos: `tezos-codec` binary to encode and decode values -tezos-context -- Tezos: on-disk context abstraction for `octez-node` -tezos-context-hash -- Specification of the Tezos context hash -tezos-context-hash-irmin -- Irmin implementation of the Tezos context hash specification -tezos-context-ops -- Tezos: backend-agnostic operations on contexts -tezos-crypto -- Tezos: library with all the cryptographic primitives used by Tezos -tezos-crypto-dal -- DAL cryptographic primitives -tezos-dac-client-lib 18.0 Tezos: `tezos-dac-client` library -tezos-dac-lib 18.0 Tezos: `tezos-dac` library -tezos-dac-node-lib 18.0 Tezos: `tezos-dac-node` library -tezos-dal-node-lib 18.0 Tezos: `tezos-dal-node` library -tezos-dal-node-services 18.0 Tezos: `tezos-dal-node` RPC services -tezos-embedded-protocol-000-Ps9mPmXa -- Tezos/Protocol: 000-Ps9mPmXa (economic-protocol definition, embedded in `octez-node`) -tezos-embedded-protocol-001-PtCJ7pwo -- Tezos/Protocol: 001_PtCJ7pwo (economic-protocol definition, embedded in `octez-node`) -tezos-embedded-protocol-002-PsYLVpVv -- Tezos/Protocol: 002_PsYLVpVv (economic-protocol definition, embedded in `octez-node`) -tezos-embedded-protocol-003-PsddFKi3 -- Tezos/Protocol: 003_PsddFKi3 (economic-protocol definition, embedded in `octez-node`) -tezos-embedded-protocol-004-Pt24m4xi -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-005-PsBABY5H -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-005-PsBabyM1 -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-006-PsCARTHA -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-007-PsDELPH1 -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-008-PtEdo2Zk -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-008-PtEdoTez -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-009-PsFLoren -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-010-PtGRANAD -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-011-PtHangz2 -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-012-Psithaca -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-013-PtJakart -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-014-PtKathma -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-015-PtLimaPt -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-016-PtMumbai -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-017-PtNairob -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-alpha -- Tezos/Protocol: economic-protocol definition, embedded in `octez-node` -tezos-embedded-protocol-demo-counter -- Tezos/Protocol: demo_counter (economic-protocol definition, embedded in `octez-node`) -tezos-embedded-protocol-demo-noops -- Tezos/Protocol: demo_noops (economic-protocol definition, embedded in `octez-node`) -tezos-embedded-protocol-genesis -- Tezos/Protocol: genesis (economic-protocol definition, embedded in `octez-node`) -tezos-error-monad -- Tezos: error monad -tezos-event-logging -- Tezos event logging library -tezos-event-logging-test-helpers -- Tezos: test helpers for the event logging library -tezos-hacl -- Tezos: thin layer around hacl-star -tezos-hacl-glue -- Tezos: thin layer of glue around hacl-star (virtual package) -tezos-hacl-glue-unix -- Tezos: thin layer of glue around hacl-star (unix implementation) -tezos-injector-013-PtJakart -- Tezos/Protocol: protocol specific library building injectors -tezos-injector-014-PtKathma -- Tezos/Protocol: protocol specific library building injectors -tezos-injector-015-PtLimaPt -- Tezos/Protocol: protocol specific library building injectors -tezos-injector-016-PtMumbai -- Tezos/Protocol: protocol specific library building injectors -tezos-injector-alpha -- Tezos/Protocol: protocol specific library building injectors -tezos-layer2-store -- Tezos: layer2 storage utils -tezos-layer2-utils-016-PtMumbai -- Tezos/Protocol: protocol specific library for Layer 2 utils -tezos-layer2-utils-017-PtNairob -- Tezos/Protocol: protocol specific library for Layer 2 utils -tezos-lazy-containers -- A collection of lazy containers whose contents is fetched from arbitrary backend on-demand -tezos-lmdb -- Legacy Tezos OCaml binding to LMDB (Consider ocaml-lmdb instead) -tezos-lwt-result-stdlib 17.3 Tezos: error-aware stdlib replacement -tezos-micheline -- Tezos: internal AST and parser for the Michelson language -tezos-micheline-rewriting -- Tezos: library for rewriting Micheline expressions -tezos-mockup -- Tezos: library of auto-documented RPCs (mockup mode) -tezos-mockup-commands -- Tezos: library of auto-documented RPCs (commands) -tezos-mockup-proxy -- Tezos: local RPCs -tezos-mockup-registration -- Tezos: protocol registration for the mockup mode -tezos-node -- Tezos: `tezos-node` binary -tezos-p2p -- Tezos: library for a pool of P2P connections -tezos-p2p-services -- Tezos: descriptions of RPCs exported by `tezos-p2p` -tezos-plompiler -- Library to write arithmetic circuits for Plonk -tezos-plonk -- Plonk zero-knowledge proving system -tezos-protocol-000-Ps9mPmXa 18.0 Tezos protocol 000-Ps9mPmXa package -tezos-protocol-001-PtCJ7pwo 18.0 Tezos protocol 001-PtCJ7pwo package -tezos-protocol-002-PsYLVpVv 18.0 Tezos protocol 002-PsYLVpVv package -tezos-protocol-003-PsddFKi3 18.0 Tezos protocol 003-PsddFKi3 package -tezos-protocol-004-Pt24m4xi 18.0 Tezos protocol 004-Pt24m4xi package -tezos-protocol-005-PsBABY5H 18.0 Tezos protocol 005-PsBABY5H package -tezos-protocol-005-PsBabyM1 18.0 Tezos protocol 005-PsBabyM1 package -tezos-protocol-006-PsCARTHA 18.0 Tezos protocol 006-PsCARTHA package -tezos-protocol-007-PsDELPH1 18.0 Tezos protocol 007-PsDELPH1 package -tezos-protocol-008-PtEdo2Zk 18.0 Tezos protocol 008-PtEdo2Zk package -tezos-protocol-008-PtEdoTez 18.0 Tezos protocol 008-PtEdoTez package -tezos-protocol-009-PsFLoren 18.0 Tezos protocol 009-PsFLoren package -tezos-protocol-010-PtGRANAD 18.0 Tezos protocol 010-PtGRANAD package -tezos-protocol-011-PtHangz2 18.0 Tezos protocol 011-PtHangz2 package -tezos-protocol-012-Psithaca 18.0 Tezos protocol 012-Psithaca package -tezos-protocol-013-PtJakart 18.0 Tezos protocol 013-PtJakart package -tezos-protocol-014-PtKathma 18.0 Tezos protocol 014-PtKathma package -tezos-protocol-015-PtLimaPt 18.0 Tezos protocol 015-PtLimaPt package -tezos-protocol-016-PtMumbai 18.0 Tezos protocol 016-PtMumbai package -tezos-protocol-017-PtNairob 18.0 Tezos protocol 017-PtNairob package -tezos-protocol-018-Proxford 18.0 Tezos protocol 018-Proxford package -tezos-protocol-alpha 18.0 Tezos protocol alpha package -tezos-protocol-compiler -- Tezos: economic-protocol compiler -tezos-protocol-demo-counter -- Tezos protocol demo-counter package -tezos-protocol-demo-noops -- Tezos protocol demo-noops package -tezos-protocol-environment -- Interface layer between the protocols and the shell -tezos-protocol-environment-packer -- Tezos: sigs/structs packer for economic protocol environment -tezos-protocol-environment-sigs -- Tezos: restricted typing environment for the economic protocols -tezos-protocol-environment-structs -- Tezos: restricted typing environment for the economic protocols -tezos-protocol-genesis -- Tezos protocol genesis package -tezos-protocol-plugin-007-PsDELPH1 -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-007-PsDELPH1-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-008-PtEdo2Zk -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-008-PtEdo2Zk-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-009-PsFLoren -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-009-PsFLoren-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-010-PtGRANAD -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-010-PtGRANAD-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-011-PtHangz2 -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-011-PtHangz2-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-012-Psithaca -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-012-Psithaca-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-012-Psithaca-tests -- Tezos/Protocol: protocol plugin tests -tezos-protocol-plugin-013-PtJakart -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-013-PtJakart-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-013-PtJakart-tests -- Tezos/Protocol: protocol plugin tests -tezos-protocol-plugin-014-PtKathma -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-014-PtKathma-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-015-PtLimaPt -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-015-PtLimaPt-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-016-PtMumbai -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-016-PtMumbai-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-017-PtNairob -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-017-PtNairob-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-alpha -- Tezos/Protocol: protocol plugin -tezos-protocol-plugin-alpha-registerer -- Tezos/Protocol: protocol plugin registerer -tezos-protocol-plugin-alpha-tests -- Tezos/Protocol: protocol plugin tests -tezos-protocol-updater -- Tezos: economic-protocol dynamic loading for `octez-node` -tezos-proxy -- Tezos: proxy -tezos-proxy-server -- Tezos: `tezos-proxy-server` binary -tezos-proxy-server-config 18.0 Tezos: proxy server configuration -tezos-requester -- Tezos: generic resource fetching service -tezos-rpc -- Tezos: library of auto-documented RPCs (service and hierarchy descriptions) -tezos-rpc-http -- Tezos: library of auto-documented RPCs (http server and client) -tezos-rpc-http-client -- Tezos: library of auto-documented RPCs (http client) -tezos-rpc-http-client-unix -- Tezos: unix implementation of the RPC client -tezos-rpc-http-server -- Tezos: library of auto-documented RPCs (http server) -tezos-rust-libs 1.6 Tezos: all rust dependencies and their dependencies -tezos-sapling -- OCaml library for the Sapling protocol, using librustzcash -tezos-sapling-parameters 1.1.0 Sapling parameters used in Tezos -tezos-scoru-wasm -- Protocol environment dependency providing WASM functionality for SCORU -tezos-scoru-wasm-fast -- WASM functionality for SCORU Fast Execution -tezos-scoru-wasm-helpers -- Helpers for the smart rollup wasm functionality and debugger -tezos-shell -- Tezos: core of `octez-node` (gossip, validation scheduling, mempool, ...) -tezos-shell-context -- Tezos: economic-protocols environment implementation for `octez-node` -tezos-shell-context-test -- Testing the Shell Context -tezos-shell-services -- Tezos: descriptions of RPCs exported by `tezos-shell` -tezos-shell-services-test-helpers -- Tezos: Tezos shell_services test helpers -tezos-signer -- Tezos: `tezos-signer` binary -tezos-signer-backends -- Tezos: remote-signature backends for `tezos-client` -tezos-signer-services -- Tezos: descriptions of RPCs exported by `tezos-signer` -tezos-smart-rollup-016-PtMumbai -- Tezos/Protocol: protocol specific library of helpers for `tezos-smart-rollup` -tezos-smart-rollup-017-PtNairob -- Tezos/Protocol: protocol specific library of helpers for `tezos-smart-rollup` -tezos-smart-rollup-alpha -- Tezos/Protocol: protocol specific library of helpers for `tezos-smart-rollup` -tezos-smart-rollup-layer2-016-PtMumbai -- Tezos/Protocol: protocol specific library for `tezos-smart-rollup` -tezos-smart-rollup-layer2-017-PtNairob -- Tezos/Protocol: protocol specific library for `tezos-smart-rollup` -tezos-stdlib -- Tezos: yet-another local-extension of the OCaml standard library -tezos-stdlib-unix -- Tezos: yet-another local-extension of the OCaml standard library (unix-specific fragment) -tezos-store -- Tezos: store for `octez-node` -tezos-test-helpers -- Tezos-agnostic test helpers -tezos-test-helpers-extra -- Test helpers dependent on tezos-base -tezos-test-services -- Tezos: Alcotest-based test services -tezos-tree-encoding -- A general-purpose library to encode arbitrary data in Merkle trees -tezos-tx-rollup-013-PtJakart -- Tezos/Protocol: protocol specific library for `tezos-tx-rollup` -tezos-tx-rollup-014-PtKathma -- Tezos/Protocol: protocol specific library for `tezos-tx-rollup` -tezos-tx-rollup-015-PtLimaPt -- Tezos/Protocol: protocol specific library for `tezos-tx-rollup` -tezos-tx-rollup-alpha -- Tezos/Protocol: protocol specific library for `tezos-tx-rollup` -tezos-tx-rollup-client-013-PtJakart -- Tezos/Protocol: `tezos-tx-rollup-client-alpha` client binary -tezos-tx-rollup-client-014-PtKathma -- Tezos/Protocol: `tezos-tx-rollup-client-alpha` client binary -tezos-tx-rollup-client-alpha -- Tezos/Protocol: `tezos-tx-rollup-client-alpha` client binary -tezos-tx-rollup-node-013-PtJakart -- Tezos/Protocol: Transaction Rollup node binary -tezos-tx-rollup-node-014-PtKathma -- Tezos/Protocol: Transaction Rollup node binary -tezos-tx-rollup-node-alpha -- Tezos/Protocol: Transaction Rollup node binary -tezos-validation -- Tezos: library for block validation -tezos-validator -- Tezos: `tezos-validator` binary for external validation of blocks -tezos-version -- Tezos: version information generated from Git -tezos-wasmer -- Wasmer bindings for SCORU WASM -tezos-webassembly-interpreter -- WebAssembly reference interpreter with tweaks for Tezos -tezos-webassembly-interpreter-extra -- Additional modules from the WebAssembly REPL used in testing -tezos-workers -- Tezos: worker library -tezt 3.1.1 Test framework for unit tests, integration tests, and regression tests -tezt-performance-regression -- Performance regression test framework based on Tezt -tezt-tezos 18.0 Octez test framework based on Tezt -tgls 0.8.6 Thin bindings to OpenGL {3,4} and OpenGL ES {2,3} for OCaml -theora -- Bindings to libtheora -thread-table -- A lock-free thread-safe integer keyed hash table -thrift -- OCaml bindings for the Apache Thrift RPC system -tidy -- Bindings for libtidy5 -- HTML/XML syntax checker and reformatter -tidy_email -- An OCaml library that simplifies connecting to email services -tidy_email_mailgun -- An OCaml library that simplifies connecting to Mailgun's REST API -tidy_email_sendgrid -- An OCaml library that simplifies connecting to Sendgrid's REST API -tidy_email_smtp -- An OCaml library that simplifies connecting to SMTP servers -tilde_f -- Provides a let-syntax for continuation-passing style. -time_now v0.16.0 Reports the current time -timed -- Timed references for imperative state -timedesc -- OCaml date time handling library -timedesc-json -- Timedesc JSON backend -timedesc-sexp -- Timedesc Sexp backend -timedesc-tzdb -- Virtual library for Timedesc time zone database backends -timedesc-tzlocal -- Virtual library for Timedesc local time zone detection backends -timedesc-tzlocal-js -- JS implementation for timedesc-tzlocal -timere -- OCaml date time reasoning library -timere-parse -- OCaml date time and duration natural language parsing library -timezone v0.16.0 Time-zone handling -timmy -- Time and calendar library -timmy-jsoo -- Js_of_ocaml bindings for Timmy -timmy-unix -- Unix clock implementation for Timmy -tiny_httpd -- Minimal HTTP server using good old threads -tiny_httpd_camlzip -- Interface to camlzip for tiny_httpd -tiny_json -- A small Json library from OCAMLTTER -tip-parser -- Parser for https://tip-org.github.io/format.html -tjr_simple_earley -- An implementation of an Earley-like algorithm, designed for simplicity. -tldr -- An ocaml tldr client -tls 0.17.1 Transport Layer Security purely in OCaml -tls-async -- Transport Layer Security purely in OCaml, Async layer -tls-liquidsoap -- Virtual package install liquidosap dependencies for TLS optional features -tls-lwt 0.17.1 Transport Layer Security purely in OCaml, Lwt layer -tls-mirage -- Transport Layer Security purely in OCaml, MirageOS layer -toc -- A generator of table of contents for Github Markdown files -tofn -- Typed ordered fuzzy numbers -togglelog -- A ppx for compile-time-optional logging -toml -- Library for TOML with a parser, a serializer and a printer -toml-cconv -- Interface between cconv and toml -toml_cconv -- Interface between cconv and toml -tophide -- Hides toplevel values whose name starts with an underscore -topiary -- A formatter for OCaml based on the Topiary universal formatting engine -topkg 1.0.7 The transitory OCaml software packager -topkg-care -- The transitory OCaml software packager -topkg-jbuilder -- Helpers for using topkg with jbuilder -toplevel_backend -- Shared backend for setting up toplevels -toplevel_expect_test -- Expectation tests for the OCaml toplevel -topojson -- A pure OCaml library for working with the TopoJSON format -topological_sort -- Topological sort algorithm -torch -- Torch bindings for OCaml -touist -- The solver for the Touist language -tplib -- TPLib: Tropical Polyhedra Library -tptp -- Library for reading and writing FOF and CNF formulas in TPTP format -tqdm -- OCaml library for progress bars -trace -- A stub for tracing/observability, agnostic in how data is collected -trace-tef -- A simple backend for trace, emitting Catapult/TEF JSON into a file -tracing -- Tracing library -tracy-client -- Client bindings to the Tracy profiler (v0.9.1) -traildb -- OCaml bindings for TrailDB. -traits -- Common traits for generic functionality -trampoline -- A trampoline library enabling deep recursions that don't fit into stack memory -transept -- Generalized parser combinator library -traverse -- Traversable data structures with applicative functors -travesty -- Traversable containers, monad extensions, and more -travis-opam -- Scripts for OCaml projects -trax -- Stack-independent exception tracing -tree_layout -- Algorithms to layout trees in a pretty manner -treeprint -- Printing combinator library with automatic parenthese -trexio -- Binding for the TREXIO Input/Output library -trie -- Strict impure trie tree -tsdl 1.0.0 Thin bindings to SDL for OCaml -tsdl-image -- SDL2_Image bindings to go with Tsdl -tsdl-mixer -- SDL2_Mixer bindings to go with Tsdl -tsdl-ttf -- SDL2_Ttf bindings to go with Tsdl -tsort -- Easy to use and user-friendly topological sort -ttweetnacl -- Thin bindings to TweetNaCl cryptography for OCaml -tuareg -- OCaml mode for GNU Emacs -tube -- Typesafe abstraction on top of Lwt_io channels -tuntap -- OCaml library for handling TUN/TAP devices -twostep -- HOTP and TOTP algorithms for 2-step verification (for OCaml) -tyabt -- Strongly typed many-sorted abstract binding trees (ABTs) -type_conv -- Library for building type-driven syntax extensions -typebeat -- Agnostic parser of the `Content-Type` in OCaml -typerep v0.16.0 Typerep is a library for runtime types -typeset -- An embedded DSL for defining source code pretty printers -tyre -- Typed Regular Expressions -tyxml 4.6.0 A library for building correct HTML and SVG documents -tyxml-jsx -- JSX syntax to write TyXML documents -tyxml-lwd -- Make reactive webpages in Js_of_ocaml using Tyxml and Lwd -tyxml-ppx -- PPX to write TyXML documents with the HTML syntax -tyxml-syntax -- Common layer for the JSX and PPX syntaxes for Tyxml -u2f -- Universal Second Factor (U2F) implementation in OCaml -ubase -- Remove diacritics from latin utf8 strings -ubpf -- OCaml bindings for userspace eBPF VM -ucaml -- Translate OCaml code into C code -uchar -- Compatibility library for OCaml's Uchar module -uecc -- Bindings for ECDH and ECDSA for 8-bit, 32-bit, and 64-bit processors -uint -- Deprecated: An unsigned integer library -ulex -- lexer generator for Unicode and OCaml -ulex-camlp5 -- A lexer generator for Unicode (backported to camlp5) -ulid -- ULIDs for OCaml -um-abt -- An OCaml library implementing unifiable abstract binding trees (UABTs) -unidecode -- Convert unicode strings into its ASCII representation -unionFind -- Implementations of the union-find data structure -unisim_archisec -- UNISIM-VP DBA decoder -unison -- File-synchronization tool for Unix and Windows -universo -- A tool for Dedukti to play with universes -unix-dirent -- ocaml-unix-dirent provides access to the features exposed in dirent.h -unix-errno -- Unix errno types, maps, and support -unix-sys-resource -- Unix sys/resource.h types and bindings (getrlimit, setrlimit, and friends) -unix-sys-stat -- ocaml-unix-sys-stat provides access to the features exposed in sys/stat.h -unix-time -- Unix time.h types, maps, and support -unix-type-representations -- Functions that expose the underlying types of some abstract types in the Unix module -unix-unistd -- Host-independent unistd.h bindings -unstrctrd 0.3 Unstructured parser -uri 4.4.0 An RFC3986 URI/URL parsing library -uri-bench -- Benchmarking package for ocaml-uri -uri-re -- An RFC3986 URI/URL parsing library -uri-sexp 4.4.0 An RFC3986 URI/URL parsing library -uring -- OCaml bindings for Linux io_uring -uritemplate -- OCaml implementation of URI templates (RFC6570) -usb -- OCaml bindings for libusb-1.0 -user-agent-parser -- OCaml implementation of the user agent parse rules of uap-core -user-setup -- Helper for the configuration of editors for the use of OCaml tools -username_kernel -- An identifier for a user -uspf -- SPF implementation in OCaml -uspf-lwt -- SPF implementation in OCaml (with LWT) -uspf-unix -- SPF implementation in OCaml -utop -- Universal toplevel for OCaml -uucd 15.1.0 Unicode character database decoder for OCaml -uucp 15.1.0 Unicode character properties for OCaml -uuidm 0.9.8 Universally unique identifiers (UUIDs) for OCaml -uunf 15.1.0 Unicode text normalization for OCaml -uuseg 15.1.0 Unicode text segmentation for OCaml -uutf 1.0.3 Non-blocking streaming Unicode codec for OCaml -uuuu -- Mapper of ISO-8859-* to Unicode -valentine -- Validate HTML from command line -validator -- Create a record validator via composable sub-validators -variantslib v0.16.0 Part of Jane Street's Core library -varint -- A simple varint implementation modeled after the one found in Go's standard library. -varray -- Resizable arrays with fast insertion/deletion -vcaml -- OCaml bindings for the Neovim API -vcardgen -- Simple OCaml library for generating VCards per RFC-6350 -vchan -- Xen Vchan implementation -vchan-unix -- Xen Vchan implementation -vchan-xen -- Xen Vchan implementation -vdom -- DOM and VDOM for OCaml -vec -- Fast, safe mutable dynamic arrays -vecosek -- -vecosek-engine -- -vecosek-scene -- -vector 1.0.0 Resizable Arrays -vector3 1.0.0 Module for 3D vectors (implemented as records of x, y and z floats) -vendredi -- Tool for generating dune projects which vendor given packages for the purpose of testing that their dependencies are vendor-friendly -vercel -- A custom runtime for Vercel.com (Now v2) written in OCaml -vg 0.9.4 Declarative 2D vector graphics for OCaml -vhd-format -- Pure OCaml library to read/write VHD format data -vhd-format-lwt -- Lwt interface to read/write VHD format data -vhdlib -- Bindings to libvhd -virtual_dom -- OCaml bindings for the virtual-dom library -visitors -- An OCaml syntax extension for generating visitor classes -vlq -- A simple library for encoding variable-length quantities -vlt -- A variant of Bolt logging tool -voaacenc -- Bindings for the voaacenc library to encode audio files in AAC format -vocal -- VOCaL -- The Verified OCaml Library -volt -- Volt is a variant of Bolt OCaml Logging Tool -voqc -- A verified optimizer for quantum circuits (VOQC) -vorbis -- Bindings to libvorbis -vpt -- Vantage point tree implementation in OCaml -vscoq-language-server -- VSCoq language server -vue-jsoo -- Binding of Vue_js -vue-ppx -- Ppx to make Vue.js application -wall -- Realtime Vector Graphics with OpenGL -wamp -- Web Application Messaging Protocol (WAMP) library — Core library -wamp-msgpck -- Web Application Messaging Protocol (WAMP) library — Msgpck support -wamp-yojson -- Web Application Messaging Protocol (WAMP) library — Yojson support -wasm -- Library to read and write WebAssembly (Wasm) files and manipulate their AST -wasmer -- OCaml bindings for Wasmer -wasmtime -- Wasmtime bindings for OCaml -wayland -- Pure OCaml Wayland protocol library -waylaunch -- Waylaunch is a program launcher for Wayland -wcs-lib -- SDK for Watson Conversation Service -webauthn -- WebAuthn - authenticating users to services using public key cryptography -webbrowser 0.6.1 Open and reload URIs in browsers from OCaml -weberizer -- Compile HTML templates into OCaml modules -webidl -- Web IDL parser -webmachine -- A REST toolkit for OCaml -websocket -- Websocket library -websocket-async -- Websocket library (Async) -websocket-lwt -- Websocket library (Lwt) -websocket-lwt-unix -- Websocket library (Lwt) -websocketaf -- Websocket implementation for use with http/af -websocketml -- A simple websocket library for OCaml with no dependency -webtest -- An in-browser js_of_ocaml testing framework - core library -webtest-js -- An in-browser js_of_ocaml testing framework - js_of_ocaml integration -weevil -- Tezos: `weevil` binary - a tool for debugging Michelson code -why3 -- Why3 environment for deductive program verification -why3-coq -- Why3 environment for deductive program verification -why3-ide -- Why3 environment for deductive program verification -wikitext -- Wikitext parser -win-error -- Manipulate Windows system errors -win-eventlog -- Log via the Windows event log from OCaml programs -wiringpi -- WiringPi for OCaml, low level Raspberry Pi hardware access -ws-server -- WebSocket server -wseg -- A word identification system -wtf8 -- Encoder and decoder for WTF-8 -wtr -- Well Typed Router -wtr-ppx -- Ppx to create routers -wu-manber-fuzzy-search -- Wu-Manber approximate string matching -wyrd -- Text-based front-end to Remind, a sophisticated calendar and alarm program -x509 0.16.5 Public Key Infrastructure (RFC 5280, PKCS) purely in OCaml -xapi-backtrace -- A simple library for recording and managing backtraces -xapi-inventory -- Library for accessing the xapi toolstack inventory file -xapi-rrd -- RRD library for use with xapi -xapi-stdext-date -- Xapi's standard library extension, Dates -xapi-stdext-encodings -- Xapi's standard library extension, Encodings -xapi-stdext-pervasives -- Xapi's standard library extension, Pervasives -xapi-stdext-std -- Xapi's standard library extension, Stdlib -xapi-stdext-threads -- Xapi's standard library extension, Threads -xapi-stdext-unix -- Xapi's standard library extension, Unix -xapi-stdext-zerocheck -- Xapi's standard library extension, Zerocheck -xcursor -- A pure implementation of Xcursor in OCaml -xdg 3.11.1 XDG Base Directory Specification -xdg-basedir -- XDG basedir location for data/cache/configuration files -xen-evtchn -- Xen event channel interface for MirageOS -xen-evtchn-unix -- Xen event channel interface for Linux -xen-gnt -- Xen grant table bindings for OCaml -xen-gnt-unix -- Xen grant table bindings for OCaml -xenstore -- Xenstore protocol in pure OCaml -xenstore_transport -- Low-level libraries for connecting to a xenstore service on a xen host -xmelly -- Simplest way to do simple parsing of simple XML files in OCaml -xml-light -- Xml-Light is a minimal XML parser & printer for OCaml -xmldiff -- Computing and applying diffs on XML trees -xmldiff_js -- Using Xmldiff on DOM -xmlm 1.4.0 Streaming XML codec for OCaml -xmlplaylist -- Library to parse various file playlists in XML format -xoshiro -- Xoshiro PRNGs as drop-in replacements for Stdlib.Random -xtmpl -- Xml templating library -xtmpl_js -- Xml templating library, javascript library -xtmpl_ppx -- Xml templating library, ppx extension -xxhash -- Bindings for xxHash, an extremely fast hash algorithm -yajl -- Bindings to the YAJL streaming JSON library -yaml 3.1.0 Parse and generate YAML 1.1/1.2 files -yaml-sexp -- Parse and generate YAML 1.1 files -yices2 -- Yices2 SMT solver binding -yices2_bindings -- Ocaml bindings for yices2 -yojson 2.1.1 Yojson is an optimized parsing and printing library for the JSON format -yojson-bench -- Run Yojson benchmarks -yurt -- An HTTP framework for OCaml -yuscii -- Mapper of UTF-7 to Unicode -yuujinchou -- Name pattern combinators -z3 -- Z3 solver -z3_tptp -- TPTP front end for Z3 solver -zanuda -- OCaml linter experiment -zar -- Formally verified sampling from discrete probability distributions -zarith 1.12 Implements arithmetic and logical operations over arbitrary-precision integers -zarith-freestanding -- Implements arithmetic and logical operations over arbitrary-precision integers -zarith-xen -- Implements arithmetic and logical operations over arbitrary-precision integers -zarith_stubs_js v0.16.0 Javascripts stubs for the Zarith library -zed -- Abstract engine for text edition in OCaml -zeit -- -zelus -- A synchronous language with ODEs -zelus-gtk -- Zelus GTK library -zenon -- An Extensible Automated Theorem Prover Producing Checkable Proofs -zipperposition -- A fully automatic theorem prover for typed higher-order and beyond -zipperposition-tools -- Support tools for Zipperposition -zlib -- Bindings to the zlib compression library -zlist -- Lazy lists for OCaml -zmq -- OCaml bindings for ZeroMQ 4.x -zmq-async -- Async-aware bindings to ZMQ -zmq-lwt -- Lwt-aware bindings to ZMQ -zstandard -- OCaml bindings to Zstandard -zstd -- Bindings to zstd compression library -zxcvbn -- Bindings for the zxcvbn password strength estimation library diff --git a/sherlodoc.opam b/sherlodoc.opam index 63134b8f76..c3b6757124 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -1,5 +1,6 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" +version: "0.2" synopsis: "Search engine for OCaml documentation" maintainer: ["art.wendling@gmail.com"] authors: ["Arthur Wendling" "Emile Trotignon"] From 648c75631dcbabff83324abd382b2eb20aad9204 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 6 Feb 2024 14:47:04 +0100 Subject: [PATCH 272/285] tests link in docstrings (#22) tests link in docstrings Co-authored-by: Emile Trotignon --- cli/search.ml | 80 +++++++++++++++++++++++++---- test/cram/link_in_docstring.t/a.mli | 6 +++ test/cram/link_in_docstring.t/run.t | 12 +++++ 3 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 test/cram/link_in_docstring.t/a.mli create mode 100644 test/cram/link_in_docstring.t/run.t diff --git a/cli/search.ml b/cli/search.ml index 46a5263277..820b3181cf 100644 --- a/cli/search.ml +++ b/cli/search.ml @@ -18,7 +18,7 @@ let string_of_kind = | Field _ -> "field" | Val _ -> "val" -let print_result ~print_cost ~no_rhs (elt : Db.Entry.t) = +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 let typedecl_params = (match elt.kind with @@ -34,9 +34,20 @@ let print_result ~print_cost ~no_rhs (elt : Db.Entry.t) = | Some _ when no_rhs -> () | Some rhs -> Format.fprintf h "%s" (Unescape.string rhs) in - Format.printf "%s%s %s%s%a@." cost kind typedecl_params name pp_rhs elt.rhs + let docstring = if print_docstring then "\n" ^ elt.doc_html else "" in + Format.printf "%s%s %s%s%a%s@." cost kind typedecl_params name pp_rhs elt.rhs docstring -let search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query ~time query = +let search + ~print_cost + ~static_sort + ~limit + ~db + ~no_rhs + ~pretty_query + ~time + ~print_docstring + query + = let query = Query.{ query; packages = []; limit } in if pretty_query then print_endline (Query.pretty query) ; let t0 = Unix.gettimeofday () in @@ -45,16 +56,42 @@ let search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query ~time query match r with | [] -> print_endline "[No results]" | _ :: _ as results -> - List.iter (print_result ~print_cost ~no_rhs) results ; + List.iter (print_result ~print_cost ~print_docstring ~no_rhs) results ; flush stdout ; if time then Format.printf "Search in %f@." (t1 -. t0) -let rec search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~time ~db = +let rec search_loop + ~print_cost + ~no_rhs + ~pretty_query + ~static_sort + ~limit + ~time + ~print_docstring + ~db + = Printf.printf "%ssearch>%s %!" "\027[0;36m" "\027[0;0m" ; match Stdlib.input_line stdin with | query -> - search ~print_cost ~static_sort ~limit ~db ~no_rhs ~pretty_query ~time query ; - search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~time ~db + search + ~print_cost + ~static_sort + ~limit + ~db + ~no_rhs + ~pretty_query + ~time + ~print_docstring + query ; + search_loop + ~print_cost + ~no_rhs + ~pretty_query + ~static_sort + ~limit + ~time + ~print_docstring + ~db | exception End_of_file -> Printf.printf "\n%!" let search @@ -65,6 +102,7 @@ let search limit pretty_query time + print_docstring db_format db_filename = @@ -73,9 +111,26 @@ let search match query with | None -> print_endline header ; - search_loop ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~time ~db + search_loop + ~print_cost + ~no_rhs + ~pretty_query + ~static_sort + ~limit + ~time + ~print_docstring + ~db | Some query -> - search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~time ~db query + search + ~print_cost + ~no_rhs + ~pretty_query + ~static_sort + ~limit + ~time + ~print_docstring + ~db + query open Cmdliner @@ -111,6 +166,10 @@ let pretty_query = let doc = "Prints the query itself as it was parsed" in Arg.(value & flag & info [ "pretty-query" ] ~doc) +let print_docstring = + let doc = "Print the HTML of the docstring of the results" in + Arg.(value & flag & info [ "print-docstring-html" ] ~doc) + let term = Term.( const search @@ -120,4 +179,5 @@ let term = $ static_sort $ limit $ pretty_query - $ print_time) + $ print_time + $ print_docstring) diff --git a/test/cram/link_in_docstring.t/a.mli b/test/cram/link_in_docstring.t/a.mli new file mode 100644 index 0000000000..e0fd4ff968 --- /dev/null +++ b/test/cram/link_in_docstring.t/a.mli @@ -0,0 +1,6 @@ + +(** This is a docstring with a {{:https://sherlocode.com}link} *) +val foo : int + +(** This is a docstring with a ref to {!foo} *) +val bar : int \ No newline at end of file diff --git a/test/cram/link_in_docstring.t/run.t b/test/cram/link_in_docstring.t/run.t new file mode 100644 index 0000000000..365f686593 --- /dev/null +++ b/test/cram/link_in_docstring.t/run.t @@ -0,0 +1,12 @@ + $ ocamlc -c a.mli -bin-annot -I . + $ odoc compile -I . a.cmti + $ odoc link -I . a.odoc + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=marshal + $ sherlodoc index $(find . -name '*.odocl') + $ sherlodoc search --print-docstring "foo" + val A.foo : int +

This is a docstring with a link

+ $ sherlodoc search --print-docstring "bar" + val A.bar : int +

This is a docstring with a ref to foo

From 80ded5e5e5fceb78e9ce2d397b63e6843f737205 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 6 Feb 2024 15:46:48 +0100 Subject: [PATCH 273/285] remove weird warnings --- test/cram/base_benchmark.t | 4 ++-- test/cram/base_cli.t | 4 ++-- test/cram/base_odocls.t | 8 ++++++++ test/cram/base_web.t | 4 ++-- test/cram/multi_package.t | 6 +++--- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/test/cram/base_benchmark.t b/test/cram/base_benchmark.t index 960ca5d776..efbc168d07 100644 --- a/test/cram/base_benchmark.t +++ b/test/cram/base_benchmark.t @@ -1,4 +1,4 @@ This test will fail, it is not deterministic. Please just check that the values are not crazy and discard the changes - $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl' | sort) - $ sherlodoc index --format=js --db=db.js $ODOCLS > /dev/null + $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl' | grep -v "__") + $ sherlodoc index --format=js --db=db.js $ODOCLS diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index 2def58d996..f7cea65640 100644 --- a/test/cram/base_cli.t +++ b/test/cram/base_cli.t @@ -1,7 +1,7 @@ - $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') + $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl' | grep -v "__") $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal - $ sherlodoc index --index-docstring=false $ODOCLS > /dev/null + $ sherlodoc index --index-docstring=false $ODOCLS $ sherlodoc search --print-cost --limit 100 "S_poly" 200 sig Base.Map.S_poly 200 sig Base.Set.S_poly diff --git a/test/cram/base_odocls.t b/test/cram/base_odocls.t index 6214582519..42197104fd 100644 --- a/test/cram/base_odocls.t +++ b/test/cram/base_odocls.t @@ -1,3 +1,11 @@ + $ find ../docs/odoc/base/ -name '*.odocl' -exec basename '{}' ';' | grep -v "__" | sort + base.odocl + base_internalhash_types.odocl + caml.odocl + md5_lib.odocl + page-index.odocl + shadow_stdlib.odocl + $ find ../docs/odoc/base/ -name '*.odocl' -exec basename '{}' ';' | sort base.odocl base__.odocl diff --git a/test/cram/base_web.t b/test/cram/base_web.t index 448ddd4c33..c6ea9ddf56 100644 --- a/test/cram/base_web.t +++ b/test/cram/base_web.t @@ -1,8 +1,8 @@ - $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl' | sort) + $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl' | grep -v "__" | sort) $ cat $ODOCLS > megaodocl $ du -sh megaodocl 13M megaodocl - $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $ODOCLS > /dev/null + $ sherlodoc index --index-docstring=true --index-name=true --type-search=true --format=js --db=db.js $ODOCLS $ gzip -k db.js diff --git a/test/cram/multi_package.t b/test/cram/multi_package.t index f8f5d5f7c4..e0dd47ce3b 100644 --- a/test/cram/multi_package.t +++ b/test/cram/multi_package.t @@ -1,9 +1,9 @@ - $ ODOCLS=$(find ../docs/odoc/ -name '*.odocl' | sort) + $ ODOCLS=$(find ../docs/odoc/ -name '*.odocl' | grep -v "__" | sort) $ echo "$ODOCLS" | awk 'END { print NR }' - 142 + 6 $ export SHERLODOC_DB=db.bin $ export SHERLODOC_FORMAT=marshal - $ sherlodoc index --index-docstring=false $ODOCLS > /dev/null + $ sherlodoc index --index-docstring=false $ODOCLS $ sherlodoc search --print-cost --limit 100 "S_poly" 200 sig Base.Map.S_poly 200 sig Base.Set.S_poly From d222c61e351a81ae5c84e4034648551cdcb8e4c5 Mon Sep 17 00:00:00 2001 From: Emile Trotignon Date: Tue, 6 Feb 2024 16:34:25 +0100 Subject: [PATCH 274/285] update readme with dune trick --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 240aaca154..542e4e4ef2 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ $ opam install ancient $ export SHERLODOC_DB=/tmp/sherlodoc.ancient # index all odoc files generated by odig for your current switch: -$ sherlodoc index $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc -name '*.odocl') +$ sherlodoc index $(find $OPAM_SWITCH_PREFIX/var/cache/odig/odoc -name '*.odocl' | grep -v __) ``` Enjoy searching from the command-line or run the webserver: @@ -70,7 +70,7 @@ Otherwise, manual integration with odoc requires to add to every call of `odoc h ```bash $ sherlodoc index --db=_build/default/_doc/_html/YOUR_LIB/db.js \ - $(find _build/default/_doc/_odocls/YOUR_LIB -name '*.odocl') + $(find _build/default/_doc/_odocls/YOUR_LIB -name '*.odocl' | grep -v __) $ sherlodoc js > _build/default/_doc/_html/sherlodoc.js ``` From 184fc921a4dd19c4a402d8450024e909595082ca Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Fri, 4 Oct 2024 17:07:02 +0200 Subject: [PATCH 275/285] Fix unvendorable [%blob] path The path relative to the project root makes sherlodoc impossible to vendor. Use a relative path instead. --- cli/main.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/main.ml b/cli/main.ml index 32799c2539..445af97f3c 100644 --- a/cli/main.ml +++ b/cli/main.ml @@ -69,7 +69,7 @@ let cmd_jsoo = in let emit_js_dep filename = let close, h = if filename = "" then false, stdout else true, open_out filename in - output_string h [%blob "jsoo/sherlodoc.js"] ; + output_string h [%blob "../jsoo/sherlodoc.js"] ; if close then close_out h in Cmd.v info Term.(const emit_js_dep $ target) From 555a4f5be558ddb67dba9b55fa86455823fefff7 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Mon, 9 Dec 2024 15:24:44 +0100 Subject: [PATCH 276/285] Compatibility with ocaml/odoc#1177 "Fewer conversions between Names and strings" --- index/typename.ml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index/typename.ml b/index/typename.ml index 3f052927e4..c22bae92df 100644 --- a/index/typename.ml +++ b/index/typename.ml @@ -25,7 +25,11 @@ let show_type_name_verbose h : Path.Type.t -> _ = function | `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) let to_string t = Format.asprintf "%a" show_type_name_verbose t From 271f3b936f7755a40db80583e6d598bedd078b6d Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Mon, 9 Dec 2024 15:26:15 +0100 Subject: [PATCH 277/285] Compatibility with ocaml/odoc#1081 "Overhaul of module-type-of and shadowing" --- index/typename.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index/typename.ml b/index/typename.ml index c22bae92df..d42c4d5e16 100644 --- a/index/typename.ml +++ b/index/typename.ml @@ -19,7 +19,7 @@ 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)) | `Identifier (path, _hidden) -> @@ -31,5 +31,6 @@ let show_type_name_verbose h : Path.Type.t -> _ = function "%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 From 5c2e7dbb5b4e0abb1d662fcbcd84d4d5fc509cf1 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Mon, 9 Dec 2024 15:28:19 +0100 Subject: [PATCH 278/285] Compatibility with ocaml/odoc#1242 "Remove core types and exceptions from identifiers" --- index/load_doc.ml | 4 ++-- index/typename.ml | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/index/load_doc.ml b/index/load_doc.ml index 3aa9602578..76a1035040 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -142,7 +142,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 _ @@ -185,7 +185,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 ; diff --git a/index/typename.ml b/index/typename.ml index d42c4d5e16..5d3af2b3a7 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 ".") @@ -21,7 +20,12 @@ and show_signature h sig_ = 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 From 358dc497dc9497560c1ea1be3abefcaefba71ce3 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Mon, 9 Dec 2024 15:29:43 +0100 Subject: [PATCH 279/285] Add pretty-printer for entries --- db/dune | 3 ++- db/entry.ml | 11 +++++++++++ db/entry.mli | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/db/dune b/db/dune index 2f917f09e4..e3cb6f4260 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 17c9c1c901..561bf3bdd3 100644 --- a/db/entry.ml +++ b/db/entry.ml @@ -54,6 +54,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 4cc1904ea2..b9f65c0845 100644 --- a/db/entry.mli +++ b/db/entry.mli @@ -38,6 +38,8 @@ type t = ; pkg : Package.t } +val pp : t Fmt.t + val v : name:string -> kind:Kind.t From 8f903c74f4dc1ebbb6257b1beac505bee35570cc Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Mon, 9 Dec 2024 15:32:01 +0100 Subject: [PATCH 280/285] Compatibility with Odoc 3 Several changes: - Entries are now defined in the `odoc_index` library, - Entries can have new kinds (pages, source, ...) - Indexes have the form of "skeletons of entries", that can be folded. - Indexes can be created by odoc with the `odoc compile-index` command, and then consumed by sherlodoc. These changes come from: - ocaml/odoc#1228 - ocaml/odoc#1232 - ocaml/odoc#1233 - ocaml/odoc#1244 - ocaml/odoc#1250 - ocaml/odoc#1251 --- cli/search.ml | 2 ++ db/entry.ml | 6 ++++-- db/entry.mli | 4 +++- index/index.ml | 39 ++++++++++++++++++-------------------- index/load_doc.ml | 23 ++++++++++++---------- index/load_doc.mli | 2 +- jsoo/main.ml | 2 ++ jsoo/odoc_html_frontend.ml | 1 + test/cram/cli.t/run.t | 3 ++- 9 files changed, 46 insertions(+), 36 deletions(-) diff --git a/cli/search.ml b/cli/search.ml index 820b3181cf..f306d0691a 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/entry.ml b/db/entry.ml index 561bf3bdd3..1e9e7e0d83 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 diff --git a/db/entry.mli b/db/entry.mli index b9f65c0845..a88319b0f8 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 diff --git a/index/index.ml b/index/index.ml index 10c017b6e9..a43c24d0b0 100644 --- a/index/index.ml +++ b/index/index.ml @@ -3,17 +3,13 @@ let index_file register filename = | 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 + let page p = register [ Odoc_index.Skeleton.from_page p ] in + let unit u = register [ Odoc_index.Skeleton.from_unit u ] in + let occ o = register o in + (match Odoc_odoc.Indexing.handle_file ~page ~unit ~occ 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 +25,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 +106,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 76a1035040..1a0b9705e0 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 @@ -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 @@ -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 4012b9bf04..a2a11126ad 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/jsoo/main.ml b/jsoo/main.ml index d14fb2296e..1f7315ea1e 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 c24c6ba2f8..9496d0d289 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/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index 93d2faf3da..a1b8c7bce7 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" From 2f88fa71f0eeb9ad19bb28b73fb0ff60a6e00748 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Mon, 9 Dec 2024 15:47:44 +0100 Subject: [PATCH 281/285] Do not rely on odoc's `handle_file` This function was used only in sherlodoc, it makes sense to be here. --- index/index.ml | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/index/index.ml b/index/index.ml index a43c24d0b0..28f1a327f8 100644 --- a/index/index.ml +++ b/index/index.ml @@ -1,12 +1,29 @@ +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 = register [ Odoc_index.Skeleton.from_page p ] in - let unit u = register [ Odoc_index.Skeleton.from_unit u ] in - let occ o = register o in - (match Odoc_odoc.Indexing.handle_file ~page ~unit ~occ file with + (match handle_file register file with | Ok result -> result | Error (`Msg msg) -> Format.printf "Odoc warning or error %a: %s@." Fpath.pp file msg) From 41316e5c42ec5a2515bc4406f2321e2f1bd52746 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Mon, 9 Dec 2024 17:38:38 +0100 Subject: [PATCH 282/285] Promote tests changed from odoc 3 indexing In particular, odoc 3 fixed a bug where "hidden" modules were still indexed. This is why e.g. `Base.StringLabels` is removed from the tests output. --- test/cram/base_cli.t | 2 +- test/cram/multi_package.t | 6 +++--- test/cram/prefix_favouritism.t | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/cram/base_cli.t b/test/cram/base_cli.t index f7cea65640..011a36a90d 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/multi_package.t b/test/cram/multi_package.t index e0dd47ce3b..884961a990 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 f9db8ed7a2..1b98e182a7 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: From b1dc7a738ba5102e387859dffb995c9407774b80 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Mon, 9 Dec 2024 17:52:45 +0100 Subject: [PATCH 283/285] Promote test from odoc 3 indexing Odoc 3 also fixed the way extension constructor are handled. Before, a "type" would be added, with ID the first constructor, making things rather strange from the user eg as in the (now fixed) example: ``` type Main.MyExtension ``` displayed for ``` type extensible_type += MyExtension ``` This is now fixed. A test for the definition of the extensible type is also added. --- test/cram/cli.t/run.t | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/cram/cli.t/run.t b/test/cram/cli.t/run.t index a1b8c7bce7..c5e31762dc 100644 --- a/test/cram/cli.t/run.t +++ b/test/cram/cli.t/run.t @@ -60,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 @@ -68,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 From 451f0197792836d6e5e2ad3679a040d31f4dd30e Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Mon, 9 Dec 2024 18:20:32 +0100 Subject: [PATCH 284/285] Raise lower bound on odoc following update to odoc 3 --- dune-project | 2 +- sherlodoc.opam | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dune-project b/dune-project index 6b85aa6fc1..d5df3c2bfb 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/sherlodoc.opam b/sherlodoc.opam index c3b6757124..46be9538fc 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"} From e4d74a63e4d886689dde42567219c61d888d8bf4 Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Tue, 10 Dec 2024 15:47:16 +0100 Subject: [PATCH 285/285] Set Dune rules and Opam dependencies --- dune | 2 ++ dune-project | 4 +++ odoc-parser.opam | 14 ++++++++++- src/driver/dune | 3 ++- vendor/sherlodoc/cli/dune | 2 +- vendor/sherlodoc/dune-project | 46 ----------------------------------- 6 files changed, 22 insertions(+), 49 deletions(-) delete mode 100644 vendor/sherlodoc/dune-project diff --git a/dune b/dune index 3a7000ca50..e80a0fbd32 100644 --- a/dune +++ b/dune @@ -23,3 +23,5 @@ (progn (bash "diff doc/driver.mld doc/driver.mld.corrected >&2 || true") (cat doc/driver-benchmarks.json)))) + +(vendored_dirs vendor) diff --git a/dune-project b/dune-project index 12643f8d30..ea608d6a68 100644 --- a/dune-project +++ b/dune-project @@ -29,3 +29,7 @@ (cram enable) (using mdx 0.3) + +; Sherlodoc +(using menhir 2.1) +(using directory-targets 0.1) diff --git a/odoc-parser.opam b/odoc-parser.opam index b167c9a85d..6abb74886d 100644 --- a/odoc-parser.opam +++ b/odoc-parser.opam @@ -16,10 +16,22 @@ depends: [ "dune" {>= "3.7"} "ocaml" {>= "4.02.0" & < "5.4"} "astring" - "result" + "result" {>= "1.5"} "camlp-streams" "ppx_expect" {with-test} ("ocaml" {< "4.04.1" & with-test} | "sexplib0" {with-test}) + # Dependencies for sherlodoc: + "base64" {>= "3.5.1"} + "bigstringaf" {>= "0.9.1"} + "js_of_ocaml" {>= "5.6.0"} + "brr" {>= "0.0.6"} + "cmdliner" {>= "1.2.0"} + "decompress" {>= "1.5.3"} + "fpath" {>= "0.7.3"} + "lwt" {>= "5.7.0"} + "menhir" {>= "20230608"} + "ppx_blob" {>= "0.7.2"} + "tyxml" {>= "4.6.0"} ] build: [ ["dune" "subst"] {dev} diff --git a/src/driver/dune b/src/driver/dune index 774a169808..90a28022dd 100644 --- a/src/driver/dune +++ b/src/driver/dune @@ -3,7 +3,8 @@ (package odoc-driver) (link_deps (package odoc) - (package odoc-md)) + (package odoc-md) + %{bin:sherlodoc}) (preprocess (pps ppx_sexp_conv)) (libraries diff --git a/vendor/sherlodoc/cli/dune b/vendor/sherlodoc/cli/dune index 2b1d3ffa9a..2ed6a7b570 100644 --- a/vendor/sherlodoc/cli/dune +++ b/vendor/sherlodoc/cli/dune @@ -3,7 +3,7 @@ (executable (name main) (public_name sherlodoc) - (package sherlodoc) + (package odoc-driver) (libraries cmdliner index diff --git a/vendor/sherlodoc/dune-project b/vendor/sherlodoc/dune-project deleted file mode 100644 index d5df3c2bfb..0000000000 --- a/vendor/sherlodoc/dune-project +++ /dev/null @@ -1,46 +0,0 @@ -(lang dune 3.5) - -(cram enable) - -(using menhir 2.1) - -(generate_opam_files true) - -(name sherlodoc) - -(version 0.2) - -(source (github art-w/sherlodoc)) - -(authors "Arthur Wendling" "Emile Trotignon") - -(maintainers "art.wendling@gmail.com") - -(license MIT) - -(using directory-targets 0.1) - -(package - (name sherlodoc) - (synopsis "Search engine for OCaml documentation") - (depends - (ocaml (>= 4.0.8)) - (odoc (>= 3.0.0)) - (base64 (>= 3.5.1)) - (bigstringaf (>= 0.9.1)) - (js_of_ocaml (>= 5.6.0)) - (brr (>= 0.0.6)) - (cmdliner (>= 1.2.0)) - (decompress (>= 1.5.3)) - (fpath (>= 0.7.3)) - (lwt (>= 5.7.0)) - (menhir (>= 20230608)) - (ppx_blob (>= 0.7.2)) - (tyxml (>= 4.6.0)) - (result (>= 1.5)) - (odig :with-test) - (base (and :with-test (= v0.16.3))) - (alcotest :with-test)) - (depopts - (dream (>= 1.0.0~alpha5)) - (ancient (>= 0.9.1))))