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 diff --git a/.ocamlformat b/.ocamlformat index 49b1202627..1db190a13b 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,17 +1,9 @@ -version = 0.24.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/.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/README.md b/README.md index 54c966b354..240aaca154 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,91 @@ **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!) +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: +- 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) + +## Local usage + +First, install sherlodoc and odig: + +```bash +$ opam pin add 'https://github.com/art-w/sherlodoc.git' # optional + +$ opam install sherlodoc odig +``` + +[Odig](https://erratique.ch/software/odig) can generate the odoc documentation of your current switch with: + +```bash +$ odig odoc # followed by `odig doc` to browse your switch documentation +``` + +Which sherlodoc can then index to create a search database: + +```bash +# name your sherlodoc database +$ export SHERLODOC_DB=/tmp/sherlodoc.marshal + +# 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') ``` -$ 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 +Enjoy searching from the command-line or run the webserver: -# 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 +```bash +$ sherlodoc search "map : list" +$ sherlodoc search # interactice cli + +$ opam install dream +$ sherlodoc serve # webserver at http://localhost:1234 ``` + +The different commands support a `--help` argument for more details/options. + +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. + +## Integration with Odoc + +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 +$ opam pin https://github.com/emileTrotignon/dune.git#search-odoc-new + +$ dune build @doc # in your favorite project +``` + +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 index --db=_build/default/_doc/_html/YOUR_LIB/db.js \ + $(find _build/default/_doc/_odocls/YOUR_LIB -name '*.odocl') + +$ sherlodoc js > _build/default/_doc/_html/sherlodoc.js +``` + +## How it works + +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. + +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: + +- 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) + +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). + +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! + +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 new file mode 100644 index 0000000000..2b1d3ffa9a --- /dev/null +++ b/cli/dune @@ -0,0 +1,20 @@ +(ocamllex unescape) + +(executable + (name main) + (public_name sherlodoc) + (package sherlodoc) + (libraries + cmdliner + index + query + db_store + unix + (select + serve.ml + from + (www -> serve.available.ml) + (!www -> serve.unavailable.ml))) + (preprocess + (pps ppx_blob)) + (preprocessor_deps ../jsoo/sherlodoc.js)) diff --git a/cli/main.ml b/cli/main.ml new file mode 100644 index 0000000000..e8856faca9 --- /dev/null +++ b/cli/main.ml @@ -0,0 +1,82 @@ +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 + +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.(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"; "o" ] ~docv:"DB" ~env) + +let db_path = + let env = + let doc = "The database to query" in + Cmd.Env.info "SHERLODOC_DB" ~doc + in + Arg.(required & opt (some file) None & info [ "db" ] ~docv:"DB" ~env) + +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:"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 (with_db Index.term db_filename) + +let cmd_serve = + let doc = "Webserver interface" in + 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_jsoo ] + +let () = exit (Cmd.eval cmd) diff --git a/cli/search.ml b/cli/search.ml new file mode 100644 index 0000000000..46a5263277 --- /dev/null +++ b/cli/search.ml @@ -0,0 +1,123 @@ +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 ~time query = + let query = Query.{ query; packages = []; limit } in + if pretty_query then print_endline (Query.pretty query) ; + 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 ; + 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 = + 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 + | exception End_of_file -> Printf.printf "\n%!" + +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 ~time ~db + | Some query -> + search ~print_cost ~no_rhs ~pretty_query ~static_sort ~limit ~time ~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 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\ + 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 + $ print_time) 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/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..fa2c0ffbab --- /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 diff --git a/cli/unescape.mll b/cli/unescape.mll new file mode 100644 index 0000000000..7f90d97119 --- /dev/null +++ b/cli/unescape.mll @@ -0,0 +1,24 @@ +(* 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 } +| ">" { 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 +} diff --git a/db/db.ml b/db/db.ml index edc4593d2c..94679d5471 100644 --- a/db/db.ml +++ b/db/db.ml @@ -1,127 +1,12 @@ -module Types = Types +module Entry = Entry 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 +module Type_polarity = Type_polarity +module Typexpr = Typexpr +module Occurences = Storage.Occurences +module String_automata = String_automata + +type t = Storage.db = + { db_names : String_automata.t + ; db_pos_types : String_automata.t Occurences.t + ; db_neg_types : String_automata.t Occurences.t + } diff --git a/db/db.mli b/db/db.mli new file mode 100644 index 0000000000..50035ab2ac --- /dev/null +++ b/db/db.mli @@ -0,0 +1,23 @@ +module Entry = Entry +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 : 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. + + [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}. *) diff --git a/db/dune b/db/dune index aade4fbf5e..2f917f09e4 100644 --- a/db/dune +++ b/db/dune @@ -1,3 +1,2 @@ (library - (name db) - (libraries unix ancient tyxml)) + (name db)) diff --git a/db/entry.ml b/db/entry.ml new file mode 100644 index 0000000000..17c9c1c901 --- /dev/null +++ b/db/entry.ml @@ -0,0 +1,148 @@ +let empty_string = String.make 0 '_' + +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 = + | Doc + | Module + | Module_type + | Class + | Class_type + | Method + | 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 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 _ + | Type_extension -> + None +end + +module Package = struct + type t = + { name : string + ; 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 } = "https://ocaml.org/p/" ^ name ^ "/" ^ version +end + +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 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 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 + | 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 + +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 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 + ; kind + ; url = non_empty_string url + ; cost + ; doc_html = non_empty_string doc_html + ; pkg + ; rhs = Option.map non_empty_string rhs + } diff --git a/db/entry.mli b/db/entry.mli new file mode 100644 index 0000000000..4cc1904ea2 --- /dev/null +++ b/db/entry.mli @@ -0,0 +1,54 @@ +module Kind : sig + type t = + | Doc + | Module + | Module_type + | Class + | Class_type + | Method + | 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 : t -> t -> bool + val get_type : t -> Typexpr.t option +end + +module Package : sig + type t = private + { name : string + ; version : string + } + + val v : name:string -> version:string -> t + val link : t -> string +end + +type t = + { name : string + ; rhs : string option + ; url : string + ; kind : Kind.t + ; cost : int + ; doc_html : string + ; pkg : Package.t + } + +val v + : name:string + -> kind:Kind.t + -> cost:int + -> rhs:string option + -> doc_html:string + -> url:string + -> pkg:Package.t + -> unit + -> t + +val link : t -> string +val compare : t -> t -> int +val equal : t -> t -> bool diff --git a/db/storage.ml b/db/storage.ml index a1e4c33915..24a91f6b8f 100644 --- a/db/storage.ml +++ b/db/storage.ml @@ -1,43 +1,16 @@ -let base_addr = 0x100000000000n +module Occurences = Map.Make (Int) -type writer = - { mutable write_shard : int - ; ancient : Ancient.md +type db = + { db_names : String_automata.t + ; db_pos_types : String_automata.t Occurences.t + ; db_neg_types : String_automata.t Occurences.t } -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 } +module type S = sig + type writer -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 } + val open_out : string -> writer + val save : db:writer -> db -> unit + val close_out : writer -> unit + val load : string -> db list +end diff --git a/db/string_automata.ml b/db/string_automata.ml new file mode 100644 index 0000000000..9714acf78a --- /dev/null +++ b/db/string_automata.ml @@ -0,0 +1,140 @@ +type terminals = + | Empty + | Terminals of Entry.t array + | Summary of Entry.t array + +type node = + { start : int + ; len : int + ; size : int + ; terminals : terminals + ; children : node array option + } + +type t = + { str : string + ; 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; _ } = + match t.terminals with + | Empty -> assert false + | Terminals arr | Summary arr -> arr.(0) + +let array_find ~str chr arr = + let rec go i = + if i >= Array.length arr + then None + else begin + let node = arr.(i) in + if chr = str.[node.start - 1] then Some node else go (i + 1) + end + in + go 0 + +let array_find ~str chr = function + | None -> None + | 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 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) + end + in + let i' = go_lcp i j in + i' - i + +let rec find ~str node pattern i = + if i >= String.length pattern + 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 Some { child with start = child.start + n; len = child.len - n } + else if n = child.len + then find ~str child pattern (i + n) + else None + +let find t pattern = + match find_lcp ~str:t.str t.t pattern 0 with + | None -> None + | Some child -> Some { str = t.str; t = child } + +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 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 yield + end + else begin + match node.children with + | None -> () + | Some 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 + skip () ; + match find t pattern with + | None -> () + | Some here -> yield here + end + +let find_star t pattern yield = + let rec go t = function + | [] -> 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 -> () + | Some t -> go t ps + end + +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 new file mode 100644 index 0000000000..9d02e06ebc --- /dev/null +++ b/db/string_automata.mli @@ -0,0 +1,26 @@ +(* 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 + ; size : int + ; terminals : terminals + ; children : node array option + } + +type t = + { str : string + ; t : node + } + +val empty : unit -> node +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/trie.ml b/db/trie.ml deleted file mode 100644 index 1e9ba24f82..0000000000 --- a/db/trie.ml +++ /dev/null @@ -1,85 +0,0 @@ -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/type_polarity.ml b/db/type_polarity.ml new file mode 100644 index 0000000000..47bcec1cbd --- /dev/null +++ b/db/type_polarity.ml @@ -0,0 +1,62 @@ +open Typexpr + +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 + +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 ] + | Arrow (a, b) -> + List.rev_append + (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 = String.lowercase_ascii 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 = + 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 t = + t + |> of_typ ~any_is_poly ~prefix:[] ~sgn:Pos + |> List.map (fun (polarity, path) -> polarity, String.concat " " (List.rev path)) + |> regroup + |> Seq.map (fun ((polarity, path), count) -> path, count, polarity) diff --git a/db/type_polarity.mli b/db/type_polarity.mli new file mode 100644 index 0000000000..e3cb13229a --- /dev/null +++ b/db/type_polarity.mli @@ -0,0 +1,82 @@ +(** 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 +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 = + | Pos + | Neg + + val to_string : t -> string + val not : t -> t +end + +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. + + 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 : 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]. + + - 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 "-"). *) + +val poly : string diff --git a/db/types.ml b/db/types.ml deleted file mode 100644 index 8f98e0deda..0000000000 --- a/db/types.ml +++ /dev/null @@ -1,74 +0,0 @@ -module Elt = struct - type t = - { 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 - } - - 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/db/typexpr.ml b/db/typexpr.ml new file mode 100644 index 0000000000..eb93c17ab5 --- /dev/null +++ b/db/typexpr.ml @@ -0,0 +1,42 @@ +type t = + | Arrow of t * t + | Constr of string * t list + | Tuple of t list + | Poly of string + | Any + | Unhandled + +let tuple = function + | [] -> Any + | [ x ] -> x + | xs -> Tuple xs + +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_parens x + | 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 new file mode 100644 index 0000000000..4c665aadcf --- /dev/null +++ b/db/typexpr.mli @@ -0,0 +1,13 @@ +type t = + | Arrow of t * t + | Constr of string * t list + | Tuple of t list + | Poly of string + | Any + | Unhandled + +val tuple : t list -> t +val size : t -> int +val show : t -> string +val equal : t -> t -> bool +val hash : t -> int diff --git a/dune-project b/dune-project index 34d08e6e8c..5acfe35684 100644 --- a/dune-project +++ b/dune-project @@ -1,21 +1,43 @@ -(lang dune 2.9) +(lang dune 3.5) + +(cram enable) (using menhir 2.1) (generate_opam_files true) + +(name sherlodoc) + (source (github art-w/sherlodoc)) -(authors "Arthur Wendling") + +(authors "Arthur Wendling" "Emile Trotignon") + (maintainers "art.wendling@gmail.com") + (license MIT) + +(using directory-targets 0.1) + (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 "Search engine for OCaml documentation") + (depends + (ocaml (>= 4.0.8)) + (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)) + (fpath (>= 0.7.3)) + (lwt (>= 5.7.0)) + (menhir (>= 20230608)) + (ppx_blob (>= 0.7.2)) + (tyxml (>= 4.6.0)) + (odig :with-test) + (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/cache.ml b/index/cache.ml deleted file mode 100644 index a5fb176b2a..0000000000 --- a/index/cache.ml +++ /dev/null @@ -1,24 +0,0 @@ -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/db_writer.ml b/index/db_writer.ml new file mode 100644 index 0000000000..e847421e35 --- /dev/null +++ b/index/db_writer.ml @@ -0,0 +1,76 @@ +open Db + +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 + } + +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 + { 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 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 + 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 = + let db = !db in + Seq.iter (fun (path, count, polarity) -> store db ~count ~polarity path elt) polarities + +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 new file mode 100644 index 0000000000..746626a5aa --- /dev/null +++ b/index/db_writer.mli @@ -0,0 +1,13 @@ +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 : 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/dune b/index/dune index e75cb5365b..da8f2264db 100644 --- a/index/dune +++ b/index/dune @@ -1,12 +1,11 @@ -(executable +(library (name index) (libraries db + db_store fpath tyxml - opam-core - odoc.loader + odoc.search odoc.model - odoc.xref2 odoc.odoc - str)) + cmdliner)) diff --git a/index/files.ml b/index/files.ml deleted file mode 100644 index a420e17758..0000000000 --- a/index/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/index/index.ml b/index/index.ml index 188a68631c..0da9a9c9a5 100644 --- a/index/index.ml +++ b/index/index.ml @@ -1,33 +1,87 @@ -module Storage = Db.Storage +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) -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)) +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 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 files = + match file_list with + | None -> files + | Some file_list -> + 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 - 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 + let t = Db_writer.export ~summarize:(db_format = `ancient) db in + Storage.save ~db:h t 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) + 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 + +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 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 .odocl file" in + 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/index.mli b/index/index.mli new file mode 100644 index 0000000000..fae8900e05 --- /dev/null +++ b/index/index.mli @@ -0,0 +1 @@ +val term : (Db_store.db_format -> string -> unit) Cmdliner.Term.t diff --git a/index/load_doc.ml b/index/load_doc.ml index e0c5c3f1c6..5cbb9748d0 100644 --- a/index/load_doc.ml +++ b/index/load_doc.ml @@ -1,252 +1,205 @@ -module Types = Db.Types -open Odoc_model +module Entry = Db.Entry +module Db_common = Db 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 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 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 +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.Constructor _ | Entry.Kind.Exception _ | Entry.Kind.Extension_constructor _ + | 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 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 +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 50) + + rhs_cost rhs + + kind_cost kind + + (if cat = `definition then 0 else 100) + + if doc_html <> "" then 0 else cost_doc kind + +let string_of_html = Format.asprintf "%a" (Tyxml.Html.pp_elt ()) + +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 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 - } + 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 - 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) + go 0 + +let register_doc ~db elt doc_txt = + 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_writer.store_word db name elt -let rec item ~pkg ~path_list ~path = +let searchable_type_of_constructor args res = 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) + match args with + | 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 -> + 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_ = + Odoc_model.Lang.TypeExpr.Arrow (None, parent_type, type_) + +let convert_kind ~db (Odoc_search.Entry.{ kind; _ } as entry) = + match kind with + | TypeDecl _ -> Entry.Kind.Type_decl (Odoc_search.Html.typedecl_params_of_entry entry) + | Value { value = _; type_ } -> + let typ = Db_writer.type_of_odoc ~db type_ in + Entry.Kind.Val typ + | Constructor { args; res } -> + 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 = searchable_type_of_record parent_type type_ in + let typ = Db_writer.type_of_odoc ~db typ in + Entry.Kind.Field typ + | Doc _ -> Doc + | Class_type _ -> Class_type + | Method _ -> Method + | Class _ -> Class + | TypeExtension _ -> Type_extension + | Module -> Entry.Kind.Module + | ModuleType -> Module_type + +let register_type_expr ~db elt typ = + 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 = + let open Db.Entry in + match Kind.get_type elt.kind with + | None -> () + | Some typ -> register_type_expr ~db elt typ + +let rec categorize id = + let open Odoc_model.Paths in + match id.Identifier.iv with + | `CoreType _ | `CoreException _ | `Root _ | `Page _ | `LeafPage _ -> `definition + | `ModuleType _ -> `declaration + | `Parameter _ -> `ignore (* redundant with indexed signature *) + | ( `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 _ + | `SourceLocationInternal _ -> + `ignore (* unclear what to do with those *) + +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. *) + categorize (parent :> Odoc_model.Paths.Identifier.Any.t) + | _ -> categorize id + +let register_entry + ~db + ~index_name + ~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 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 - 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) + 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 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 ; + 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 + | Doc _ -> true + | _ -> false 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 + 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 diff --git a/index/load_doc.mli b/index/load_doc.mli new file mode 100644 index 0000000000..df9b8f4189 --- /dev/null +++ b/index/load_doc.mli @@ -0,0 +1,10 @@ +val register_entry + : db:Db_writer.t + -> 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 + the entry [e] in [db]. *) diff --git a/index/pretty.ml b/index/pretty.ml deleted file mode 100644 index 14353570b3..0000000000 --- a/index/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/index/suffix_tree.ml b/index/suffix_tree.ml new file mode 100644 index 0000000000..7e96c8d671 --- /dev/null +++ b/index/suffix_tree.ml @@ -0,0 +1,429 @@ +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 + (* Cache small strings as slices in one bigstring. *) + + 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 + ; mutable contents : string option + } + + 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; contents } substr = + assert (contents = None) ; + 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 +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 + + 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 rec equal xs ys = + match xs, ys with + | [], [] -> true + | 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 +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 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.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 Terminals_cache = Hashtbl.Make (Terminals) +module Seen = Set.Make (Db.Entry) + +let export_terminals ~cache_term ~is_summary ts = + try Terminals_cache.find cache_term ts with + | Not_found -> + 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 + +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 ~summarize ~is_root:false) node.children + in + let children = + List.sort + (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 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 terminals = + if is_summary + then List.of_seq (Seen.to_seq seen) + 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 = + 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" + | 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 + 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 -> + 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; size; terminals; children } + in + let result = { uid = Uid.make (); t = node; min = min_child; seen } in + Hashtbl.add cache key result ; + result + +let export ~summarize { buffer; root = t } = + let str = Buf.contents buffer in + if String.length str = 0 + 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 + 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 new file mode 100644 index 0000000000..0ff6a5a266 --- /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 : summarize:bool -> t -> Db.String_automata.t 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/index/typename.ml b/index/typename.ml new file mode 100644 index 0000000000..3f052927e4 --- /dev/null +++ b/index/typename.ml @@ -0,0 +1,31 @@ +module Path = Odoc_model.Paths.Path +module Identifier = Odoc_model.Paths.Identifier +module TypeName = Odoc_model.Names.TypeName +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 ".") + +and show_signature h sig_ = + match sig_.iv with + | `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 : Path.Type.t -> _ = function + | `Resolved t -> + Format.fprintf h "%a" show_ident_long Path.Resolved.(identifier (t :> t)) + | `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 + +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..c6410ce6ad --- /dev/null +++ b/index/typename.mli @@ -0,0 +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. *) 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/jsoo/dune b/jsoo/dune new file mode 100644 index 0000000000..eb4be501b5 --- /dev/null +++ b/jsoo/dune @@ -0,0 +1,9 @@ +(executable + (name main) + (modes js) + (libraries brr query)) + +(rule + (alias all) + (action + (copy main.bc.js sherlodoc.js))) diff --git a/jsoo/main.ml b/jsoo/main.ml new file mode 100644 index 0000000000..d14fb2296e --- /dev/null +++ b/jsoo/main.ml @@ -0,0 +1,153 @@ +let print_error 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)) + +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 + +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 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 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.(Decompress_browser.inflate @@ call global "sherlodoc_db" [||]) + |> Fut.map (fun str -> [ Marshal.from_string str 0 ]) + +let string_of_kind = + let open Db.Entry.Kind in + let open Odoc_html_frontend in + function + | Db.Entry.Kind.Doc -> kind_doc + | Type_decl _ -> kind_typedecl + | Module -> kind_module + | Exception _ -> kind_exception + | Class_type -> kind_class_type + | Method -> kind_method + | Class -> kind_class + | Type_extension -> kind_extension + | Extension_constructor _ -> kind_extension_constructor + | Module_type -> kind_module_type + | Constructor _ -> kind_constructor + | Field _ -> kind_field + | Val _ -> kind_value + +let search message db = + let query = Jv.get message "data" in + let query = query |> Jv.to_jstr |> Jstr.to_string in + let results = + Query.Blocking.search ~shards:db { Query.query; packages = []; limit = 50 } + in + let _ = + Jv.(apply (get global "postMessage")) + [| Jv.of_list + (fun Db.Entry.{ name; rhs; doc_html; kind; url; _ } -> + let typedecl_params = + match kind with + | Db.Entry.Kind.Type_decl args -> args + | _ -> None + in + let prefix_name, name = + match kind with + | Db.Entry.Kind.Doc -> None, None + | _ -> 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 = + 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 + |] + in + () + +let don't_wait_for fut = Fut.await fut Fun.id + +let search message = + don't_wait_for + @@ + let open Fut.Syntax in + let+ db = db in + search message db + +let main () = + let module J' = Jstr in + let o = Jv.callback ~arity:1 search in + Jv.(set global "onmessage" o) + +let _ = main () diff --git a/jsoo/odoc_html_frontend.ml b/jsoo/odoc_html_frontend.ml new file mode 100644 index 0000000000..c24c6ba2f8 --- /dev/null +++ b/jsoo/odoc_html_frontend.ml @@ -0,0 +1,51 @@ +(* 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 + | None -> [] + | Some "" -> [] + | Some prefix_name -> + [ span ~a:[ a_class [ "prefix-name" ] ] [ txt (prefix_name ^ ".") ] ] + 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 0b3ee71d72..c9f0de2ac0 100644 --- a/query/dune +++ b/query/dune @@ -1,9 +1,9 @@ (library (name query) - (libraries lwt re db)) + (libraries db)) (menhir - (modules parser) + (modules type_parser) (flags --explain)) -(ocamllex lexer) +(ocamllex type_lexer) diff --git a/query/dynamic_cost.ml b/query/dynamic_cost.ml new file mode 100644 index 0000000000..e3fac28a15 --- /dev/null +++ b/query/dynamic_cost.ml @@ -0,0 +1,30 @@ +module Entry = Db.Entry + +type query = + { name : string list + ; type_paths : Type_distance.t option + } + +let of_query { Query_parser.name; typ } = + let type_paths = + match typ with + | `typ t -> Some (Type_distance.paths_of_type t) + | _ -> None + in + { name; type_paths } + +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 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 + | None -> 0 + in + 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 new file mode 100644 index 0000000000..3062473d74 --- /dev/null +++ b/query/name_cost.ml @@ -0,0 +1,63 @@ +let rec prefix_at ~case ~sub i s j = + if i >= String.length sub + then Some case + 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 + 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 + +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 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 [] + +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 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) / 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 + | Some (_, cost') when cost' < cost -> acc + | _ -> Some (i, cost)) + None + (find_all ~sub str) + +let best_matches words str = + 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/parser.mly b/query/parser.mly deleted file mode 100644 index c59275fd97..0000000000 --- a/query/parser.mly +++ /dev/null @@ -1,50 +0,0 @@ -%{ - 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/priority_queue.ml b/query/priority_queue.ml new file mode 100644 index 0000000000..6c38416a0c --- /dev/null +++ b/query/priority_queue.ml @@ -0,0 +1,135 @@ +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 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 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 insert lst = + match lst with + | [] -> [ x ] + | y :: ys -> begin + match minimum y with + | None -> insert ys + | Some min_y when Entry.compare min_elt min_y <= 0 -> x :: lst + | _ -> y :: insert ys + end + in + insert 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 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 -> + 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 search_from 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 search_from (j + step) (step * 2) + in + search_from i 1 + | All (min_elt, _) as t when cond min_elt -> t + | 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 pop_union i = function + | [] -> [] + | x :: xs -> + let x' = pop_until cond x in + if x == x' + then begin + assert (i > 0) ; + x :: xs + end + else insert_sort x' (pop_union (i + 1) xs) + in + let lst = pop_union 0 lst in + union_sorted lst + +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 new file mode 100644 index 0000000000..24f42d41bb --- /dev/null +++ b/query/priority_queue.mli @@ -0,0 +1,10 @@ +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 -> 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 caefcda31f..e683071127 100644 --- a/query/query.ml +++ b/query/query.ml @@ -1,105 +1,116 @@ module Parser = Query_parser -module Succ = Succ -module Sort = Sort +module Dynamic_cost = Dynamic_cost 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 = +module Tree = Db.String_automata + +module Private = struct + module Succ = Succ + + 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 polarities typ = + List.of_seq + @@ Seq.filter + (fun (word, _count, _) -> String.length word > 0) + (Db.Type_polarity.of_typ ~any_is_poly:false typ) + +let find_types ~shard typ = + let polarities = polarities typ in + 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 + 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 + List.rev_append ts acc + end) + st_occ + []) + polarities + +let find_names ~shard names = + let names = List.map String.lowercase_ascii names in + let db_names = Db.(shard.db_names) in + let candidates = List.map - (fun n -> List.rev (Db.list_of_string (String.lowercase_ascii n))) + (fun name -> + match Tree.find db_names name with + | Some trie -> Succ.of_automata trie + | None -> Succ.empty) 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 + 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 + ; packages : string list + ; 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 + +let match_packages ~packages results = + match packages with + | [] -> results + | _ -> Seq.filter (match_packages ~packages) results + +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 + query, match_packages ~packages:params.packages results + +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 new file mode 100644 index 0000000000..f7f7d78ada --- /dev/null +++ b/query/query.mli @@ -0,0 +1,52 @@ +type t = + { query : string + ; packages : string list + ; limit : int + } + +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. + + - [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. *) +end + +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 + module Succ = Succ + + module Type_parser : sig + val of_string : string -> (Db.Typexpr.t, string) result + end +end 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..0283842dac 100644 --- a/query/query_parser.ml +++ b/query/query_parser.ml @@ -1,12 +1,22 @@ -open Query_ast - -type t = string list - -let parse str = Parser.main Lexer.token (Lexing.from_string str) +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 alphanum = function - | 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '\'' -> true - | _ -> false +let type_of_string str = + let str = balance_parens str in + let lexbuf = Lexing.from_string str in + 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) @@ -15,26 +25,26 @@ 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 of_string str = - let str = String.trim str in - 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_typ, query_typ, paths_typ = - 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) - , paths_arrow ~prefix:[] ~sgn:Db.Types.Pos typ ) - | exception _ -> "", [], [] + 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 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 + 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 new file mode 100644 index 0000000000..7c7d1d74a9 --- /dev/null +++ b/query/query_parser.mli @@ -0,0 +1,7 @@ +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/sort.ml b/query/sort.ml deleted file mode 100644 index 2256d81d30..0000000000 --- a/query/sort.ml +++ /dev/null @@ -1,154 +0,0 @@ -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 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 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 - List.sort Elt.compare results diff --git a/query/succ.ml b/query/succ.ml index 9d07a5167a..d258e0450c 100644 --- a/query/succ.ml +++ b/query/succ.ml @@ -1,137 +1,155 @@ -open Db.Types +module Entry = Db.Entry + +type elt = Entry.t type s = - | All | Empty - | Set of Elt_set.t + | All + | Pq of Priority_queue.t | Inter of s * s | Union of s * s type t = - { cardinal : int - ; s : s + { s : s + ; size : int } -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 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.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 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.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 + | _, Empty -> a + | Empty, _ -> b + | x, y when x == y -> a + | 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 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 +let rec join_with fn = function + | [] -> [] + | [ x ] -> [ x ] + | a :: b :: xs -> fn a b :: join_with fn xs -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 +let rec perfect ~default fn = function + | [] -> default + | [ x ] -> x + | xs -> perfect ~default fn (join_with fn xs) + +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 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 = + | 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 = + match t with + | 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 + | First -> pqueue + | Ge elt -> Priority_queue.pop_lt elt pqueue + | Gt elt -> Priority_queue.pop_lte elt pqueue + in + 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 + | 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 + end + | Inter (l, r) -> begin + 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 -and first_opt t = try Some (first t) with Not_found -> None +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 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 - 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) +let first t = succ_loop ~strictness:First t + +let seq_of_dispenser fn = + let rec go () = + match fn () with + | None -> Seq.Nil + | Some x -> Seq.Cons (x, go) in - let next () = Lwt.catch (fun () -> go_gt ()) (fun _ -> Lwt.return None) in - Lwt_stream.from next + go -let to_stream t = to_stream t.s +let to_seq { s = t; _ } = + let state = ref None in + let loop () = + let result = + match !state with + | None -> first t + | Some (previous_elt, t) -> succ_loop ~strictness:(Gt previous_elt) t + in + match result with + | None -> None + | Some (elt, _) -> + state := result ; + Some elt + in + seq_of_dispenser loop diff --git a/query/succ.mli b/query/succ.mli new file mode 100644 index 0000000000..cfd9df7008 --- /dev/null +++ b/query/succ.mli @@ -0,0 +1,14 @@ +(** This module provides a way to get the first n elements of a very large set + without computing the whole list of elements. *) + +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 +val union_of_list : t list -> t +val of_array : Db.Entry.t array -> t 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..11fcf5cf4b --- /dev/null +++ b/query/test/test.ml @@ -0,0 +1,3 @@ +let () = + let open Alcotest in + run "Query" [ "Succ", Test_succ.tests_to_seq; "Type_parser", Test_type_parser.tests ] diff --git a/query/test/test_succ.ml b/query/test/test_succ.ml new file mode 100644 index 0000000000..3650a52f34 --- /dev/null +++ b/query/test/test_succ.ml @@ -0,0 +1,62 @@ +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:"" ~pkg () + +(** This module does the same thing as Succ, but its correctness is obvious + and its performance terrible. *) +module Reference = struct + include Set.Make (Db.Entry) + + let of_array arr = arr |> Array.to_seq |> of_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 = + 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 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 -> 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) + +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 |> 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 = + [ 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..9835dc84e6 --- /dev/null +++ b/query/test/test_type_parser.ml @@ -0,0 +1,38 @@ +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))) + | _ 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 size = + let n_params = 1 + Random.int 3 in + 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 + +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 * 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/top_results.ml b/query/top_results.ml new file mode 100644 index 0000000000..60287b357f --- /dev/null +++ b/query/top_results.ml @@ -0,0 +1,57 @@ +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.score 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 = 10 + +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 + 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 new file mode 100644 index 0000000000..a1533763a8 --- /dev/null +++ b/query/top_results.mli @@ -0,0 +1,9 @@ +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 new file mode 100644 index 0000000000..72e414e7fd --- /dev/null +++ b/query/type_distance.ml @@ -0,0 +1,172 @@ +type step = + | Type of string + | Poly + | Any + | Arrow_left + | Arrow_right + | Product of + { pos : int + ; length : int + } + | Argument of + { pos : int + ; length : int + } + +module Sign = Db.Type_polarity.Sign + +type t = step 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 paths_of_type t = List.map List.rev @@ paths_of_type ~prefix:[] t + +(* *) + +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 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 ~xsgn ~ysgn i j xs ys in + cache.(i).(j) <- r ; + r + end + and go ~xsgn ~ysgn i j xs ys = + match xs, ys with + | [], [] -> 0 + | [], _ -> 0 + | [ 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 + 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 + let pos = Db.Type_polarity.Sign.Pos in + go ~xsgn:pos ~ysgn:pos 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 = List.mapi (fun i x -> x, 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 + (* 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 + (* 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 begin + let rec find = function + | [] -> true + | (cost, j) :: rest -> + 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 continue then find rest else false + in + find arr.(i) + end + in + let _ = go (Array.length used) 0 0 in + !best + +let v ~query_paths ~entry = + let entry_paths = paths_of_type entry in + match entry_paths, query_paths with + | _, [] | [], _ -> 0 + | _ -> + 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 new file mode 100644 index 0000000000..ab97edef37 --- /dev/null +++ b/query/type_distance.mli @@ -0,0 +1,8 @@ +type t + +val paths_of_type : Db.Typexpr.t -> t + +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/query/lexer.mll b/query/type_lexer.mll similarity index 68% rename from query/lexer.mll rename to query/type_lexer.mll index b75f0b619e..e0d197ae85 100644 --- a/query/lexer.mll +++ b/query/type_lexer.mll @@ -1,10 +1,10 @@ { - open Parser + open Type_parser } rule token = parse | ' ' { token lexbuf } -| "-" | "->" { 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 new file mode 100644 index 0000000000..7e4528051d --- /dev/null +++ b/query/type_parser.mly @@ -0,0 +1,60 @@ +(* 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 +%} + +%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 } + ; + +typ: + | t=typ2 { t } + | a=typ2 ARROW b=typ { Arrow (a, b) } + ; + +typ2: + | xs=list1(typ1, STAR) { tuple xs } + ; + +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, []) } + ; + +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/sherlodoc.opam b/sherlodoc.opam index e8c84902cc..6bd90ee2a6 100644 --- a/sherlodoc.opam +++ b/sherlodoc.opam @@ -1,20 +1,33 @@ # 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: [ - "ocaml" {>= "4.14.0"} - "dune" {>= "2.9"} - "ancient" - "dream" - "fpath" - "odoc" {= "2.1.0"} - "opam-core" + "dune" {>= "3.5"} + "ocaml" {>= "4.0.8"} + "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"} + "fpath" {>= "0.7.3"} + "lwt" {>= "5.7.0"} + "menhir" {>= "20230608"} + "ppx_blob" {>= "0.7.2"} "tyxml" {>= "4.6.0"} + "odig" {with-test} + "base" {with-test & = "v0.16.3"} + "alcotest" {with-test} +] +depopts: [ + "dream" {>= "1.0.0~alpha5"} + "ancient" {>= "0.9.1"} ] build: [ ["dune" "subst"] {dev} @@ -25,11 +38,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/store/db_store.default.ml b/store/db_store.default.ml new file mode 100644 index 0000000000..36fb89cb73 --- /dev/null +++ b/store/db_store.default.ml @@ -0,0 +1,12 @@ +type db_format = + [ `ancient + | `marshal + | `js + ] + +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/store/db_store.with_ancient.ml b/store/db_store.with_ancient.ml new file mode 100644 index 0000000000..344dae6eef --- /dev/null +++ b/store/db_store.with_ancient.ml @@ -0,0 +1,12 @@ +type db_format = + [ `ancient + | `marshal + | `js + ] + +let available_backends = [ "ancient", `ancient; "marshal", `marshal; "js", `js ] + +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/store/dune b/store/dune new file mode 100644 index 0000000000..d138d9cc78 --- /dev/null +++ b/store/dune @@ -0,0 +1,27 @@ +(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) + (modules storage_ancient) + (optional) + (libraries db ancient unix)) + +(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/store/storage_ancient.ml b/store/storage_ancient.ml new file mode 100644 index 0000000000..beb07b13c7 --- /dev/null +++ b/store/storage_ancient.ml @@ -0,0 +1,45 @@ +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 + ; 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 : 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 : Db.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/store/storage_ancient.mli b/store/storage_ancient.mli new file mode 100644 index 0000000000..bf1293dcd8 --- /dev/null +++ b/store/storage_ancient.mli @@ -0,0 +1 @@ +include Db.Storage.S diff --git a/store/storage_js.ml b/store/storage_js.ml new file mode 100644 index 0000000000..11f8122438 --- /dev/null +++ b/store/storage_js.ml @@ -0,0 +1,32 @@ +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 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 _ = failwith "js database format is unsupported" diff --git a/store/storage_js.mli b/store/storage_js.mli new file mode 100644 index 0000000000..bf1293dcd8 --- /dev/null +++ b/store/storage_js.mli @@ -0,0 +1 @@ +include Db.Storage.S diff --git a/store/storage_marshal.ml b/store/storage_marshal.ml new file mode 100644 index 0000000000..6f913a0947 --- /dev/null +++ b/store/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/store/storage_marshal.mli b/store/storage_marshal.mli new file mode 100644 index 0000000000..bf1293dcd8 --- /dev/null +++ b/store/storage_marshal.mli @@ -0,0 +1 @@ +include Db.Storage.S 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 new file mode 100644 index 0000000000..4dabb1cedd --- /dev/null +++ b/test/cram/base_cli.t @@ -0,0 +1,296 @@ + $ ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') + $ 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" + 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 + 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" + 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 + + $ 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 + + $ 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 + + $ 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 + $ 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 + +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 + $ 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 diff --git a/test/cram/base_odocls.t b/test/cram/base_odocls.t new file mode 100644 index 0000000000..6214582519 --- /dev/null +++ b/test/cram/base_odocls.t @@ -0,0 +1,143 @@ + $ 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.t/main.mli b/test/cram/cli.t/main.mli new file mode 100644 index 0000000000..9c483d7021 --- /dev/null +++ b/test/cram/cli.t/main.mli @@ -0,0 +1,77 @@ +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 + 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 +(** 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 + +module type Modtype = sig + val v_modtype : foo +end + +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 + +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 + +type long_name_type + +val long_name_value : long_name_type \ No newline at end of file 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..da3c8707df --- /dev/null +++ b/test/cram/cli.t/run.t @@ -0,0 +1,124 @@ + $ 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 + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=marshal + $ sherlodoc index $(find . -name '*.odocl') + $ sherlodoc search "unique_name" + val Main.unique_name : foo + $ sherlodoc search "multiple_hit" + val Main.multiple_hit_1 : foo + 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 + $ sherlodoc search "nesting_priority" + val Main.nesting_priority : foo + val Main.Nest.nesting_priority : foo + $ sherlodoc search "list" + type 'a Main.list + type 'a Main.List.t = 'a list + 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" + 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.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" + 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 ":moo" + val Main.value : moo + val Main.produce : unit -> moo + val Main.produce_2' : unit -> unit -> moo + $ sherlodoc search ":_ -> moo" + val Main.produce : unit -> moo + val Main.produce_2' : unit -> unit -> moo + val Main.value : moo + $ sherlodoc search ":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 search "modtype" + sig Main.Modtype + val Main.Modtype.v_modtype : foo + $ sherlodoc search "S" + mod Main.S_to_S1 + 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 + val Main.List.map : ('a -> 'b) -> 'a t -> 'b t + 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 + $ sherlodoc search "qwertyuiopasdfghjklzxcvbnm" + [No results] + $ sherlodoc search "hidden" + [No results] + $ sherlodoc search ":mo" + val Main.value : moo + 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.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 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 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 + $ sherlodoc search ": 'a bo" + val Main.poly_param : 'a boo + $ sherlodoc search ":extensible_type" + cons Main.MyExtension : moo -> extensible_type + $ 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 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 search ": long_name_type" + val Main.long_name_value : long_name_type + $ sherlodoc search ": long_nam" + val Main.long_name_value : long_name_type + $ 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/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..266a77111a --- /dev/null +++ b/test/cram/cli_poly.t/run.t @@ -0,0 +1,17 @@ + $ 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 + $ export SHERLODOC_DB=db.bin + $ export SHERLODOC_FORMAT=marshal + $ sherlodoc index $(find . -name '*.odocl') +TODO : get a result for the query bellow + $ sherlodoc search ":'a" + val Main.poly_1 : '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/main.mli b/test/cram/cli_small.t/main.mli new file mode 100644 index 0000000000..9e1d7609a7 --- /dev/null +++ b/test/cram/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/cli_small.t/run.t b/test/cram/cli_small.t/run.t new file mode 100644 index 0000000000..22a28216c8 --- /dev/null +++ b/test/cram/cli_small.t/run.t @@ -0,0 +1,14 @@ + $ ocamlc -c main.mli -bin-annot -I . + $ odoc compile -I . main.cmti + $ odoc link -I . main.odoc + $ export SHERLODOC_DB=db.bin + $ 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 + $ sherlodoc search ": (int, 'a) result" + val Main.ok_zero : (int, 'a) result diff --git a/test/cram/dune b/test/cram/dune new file mode 100644 index 0000000000..958bfaa70a --- /dev/null +++ b/test/cram/dune @@ -0,0 +1,2 @@ +(cram + (deps ../docs %{bin:odoc} %{bin:sherlodoc})) 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] + 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..6f95af3239 --- /dev/null +++ b/test/cram/module_type_cost.t/main.mli @@ -0,0 +1,13 @@ +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 + +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 new file mode 100644 index 0000000000..5be645e7fa --- /dev/null +++ b/test/cram/module_type_cost.t/run.t @@ -0,0 +1,19 @@ + $ 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') +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 +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 diff --git a/test/cram/multi_package.t b/test/cram/multi_package.t new file mode 100644 index 0000000000..f93590e749 --- /dev/null +++ b/test/cram/multi_package.t @@ -0,0 +1,352 @@ + $ ODOCLS=$(find ../docs/odoc/ -name '*.odocl' | sort) + $ echo "$ODOCLS" | awk 'END { print NR }' + 142 + $ 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" + 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 + 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" + 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 + + $ 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 + + $ 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 + + $ 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 + $ 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 + +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 + $ 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" + 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 + 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/query_syntax.t b/test/cram/query_syntax.t new file mode 100644 index 0000000000..3eda2f4d94 --- /dev/null +++ b/test/cram/query_syntax.t @@ -0,0 +1,65 @@ +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 + $ export SHERLODOC_FORMAT=marshal + $ export SHERLODOC_DB=db.bin + $ sherlodoc index main.odocl + $ sherlodoc search --pretty-query ": int list option" + : int list option + [No results] + $ export OCAMLRUNPARAM=b + $ sherlodoc search --pretty-query ": _" + : _ + [No results] +Testing incomplete queries + $ sherlodoc search --pretty-query ": ->" + : _ -> _ + [No results] + $ sherlodoc search --pretty-query ": int ->" + : int -> _ + [No results] + $ sherlodoc search --pretty-query ": int *" + : int * _ + [No results] + $ sherlodoc search --pretty-query ": string -> (" + : string -> _ + [No results] + $ sherlodoc search --pretty-query ": (int" + : int + [No results] + $ sherlodoc search --pretty-query ": (int ->" + : int -> _ + [No results] + $ sherlodoc search --pretty-query ": (int *" + : int * _ + [No results] + $ sherlodoc search --pretty-query ": foo bar qux" + : foo bar qux + [No results] + $ sherlodoc search --pretty-query ": ()" + : _ + [No results] + $ sherlodoc search --pretty-query ": )" + : _ + [No results] + $ sherlodoc search --pretty-query ": (int," + : int * _ + [No results] + $ sherlodoc search --pretty-query ": (int,string" + : int * string + [No results] + $ sherlodoc search --pretty-query ": 'a, 'b) result -" + : ('a, 'b) result -> _ + [No results] + $ sherlodoc search --pretty-query ": 'a * 'b) list" + : ('a * 'b) list + [No results] + $ sherlodoc search --pretty-query ": - ,'a * 'b, 'c) result -) - ( -" + : ((_ -> _, 'a * 'b, 'c) result -> _) -> _ -> _ + [No results] +Testing syntax errors + $ sherlodoc search --pretty-query ": )(" + : + [No results] diff --git a/test/cram/simple.t/main.ml b/test/cram/simple.t/main.ml new file mode 100644 index 0000000000..f5eb8813f0 --- /dev/null +++ b/test/cram/simple.t/main.ml @@ -0,0 +1,92 @@ +type t = int +(** A comment *) + +(** {1 this is a title} + + and this is a paragraph + + *) + +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 + +(** 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 + *) +module Trucmuche = struct + let bidule = 4 +end + +include Trucmuche + +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 + +(** 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 diff --git a/test/cram/simple.t/page.mld b/test/cram/simple.t/page.mld new file mode 100644 index 0000000000..a2a2439df7 --- /dev/null +++ b/test/cram/simple.t/page.mld @@ -0,0 +1,12 @@ +{0 A title} + +A paragraph + +{v some verbatim v} + +{[and code]} + +- 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 new file mode 100644 index 0000000000..145698ae28 --- /dev/null +++ b/test/cram/simple.t/run.t @@ -0,0 +1,68 @@ + $ ocamlc -c main.ml -bin-annot -I . + $ 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 + $ mkdir 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 | sort + ./main.odocl + ./page-page.odocl + $ ls | sort + html + main.cmi + main.cmo + main.cmt + main.ml + main.odoc + main.odocl + megaodocl + page-page.odoc + page-page.odocl + page.mld + $ ls html | sort + db.js + fonts + highlight.pack.js + katex.min.css + katex.min.js + odoc.css + odoc_search.js + page + sherlodoc.js + $ ls html/page | sort + 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 + ./html/db.js + ./html/highlight.pack.js + ./html/katex.min.js + ./html/odoc_search.js + ./html/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 + + diff --git a/test/cram/size_bound.t b/test/cram/size_bound.t new file mode 100644 index 0000000000..2d7b2c530f --- /dev/null +++ b/test/cram/size_bound.t @@ -0,0 +1,12 @@ +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 large enough or forbid certain dependency versions +in the opam file. + $ sherlodoc js sherlodoc.js + $ if [ "$(du sherlodoc.js | cut -f 1)" -gt 120000 ]; then + > du sherlodoc.js + > else + > echo "All good! "; + > fi + All good! 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 diff --git a/test/cram_ancient/dune b/test/cram_ancient/dune new file mode 100644 index 0000000000..693a24fd21 --- /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] diff --git a/test/cram_static/base_web.t b/test/cram_static/base_web.t new file mode 100644 index 0000000000..11aa91d44a --- /dev/null +++ b/test/cram_static/base_web.t @@ -0,0 +1,36 @@ + $ export ODOCLS=$(find ../docs/odoc/base/ -name '*.odocl') + $ cat $ODOCLS > 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 + +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 + + $ 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 + 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_static/dune b/test/cram_static/dune new file mode 100644 index 0000000000..54d19fea64 --- /dev/null +++ b/test/cram_static/dune @@ -0,0 +1,6 @@ +(cram + (enabled_if + (and + (= %{version:menhirLib} 20230608) + (= %{ocaml_version} 4.14.1))) + (deps ../docs %{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..966d3f18fe --- /dev/null +++ b/test/cram_static/js_static_size.t @@ -0,0 +1,3 @@ + $ sherlodoc js sherlodoc.js + $ du -sh sherlodoc.js + 92K sherlodoc.js diff --git a/test/dune b/test/dune new file mode 100644 index 0000000000..94a91be7bb --- /dev/null +++ b/test/dune @@ -0,0 +1,10 @@ +(rule + (target + (dir docs)) + (deps + (package base)) + (action + (progn + (run mkdir -p docs) + (run odig odoc --cache-dir=docs --no-pkg-deps --quiet base) + (run rm docs/html/base/_doc-dir)))) 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..3a310562a4 --- /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 $OPAM_SWITCH_PREFIX/var/cache/odig/odoc/$PKG -name "*.odocl") 2> $PKG.stderr > $PKG.stdout +done \ No newline at end of file diff --git a/www/dune b/www/dune index 80cfd2bc17..b8ea93c04f 100644 --- a/www/dune +++ b/www/dune @@ -1,3 +1,12 @@ -(executable +(library (name www) - (libraries cmdliner dream db query)) + (optional) + (libraries lwt 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 8b2b97cb67..df8f9d4f85 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 @@ -107,56 +105,53 @@ 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 = - List.fold_left - (fun acc p -> M.remove p acc) - (load "./static/packages.csv") - [ "Tezos"; "conf" ] +let packages () = parse_str [%blob "www/static/packages.csv"] + +let packages () = + List.fold_left (fun acc p -> M.remove p acc) (packages ()) [ "Tezos"; "conf" ] open Tyxml.Html -let 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 ])) - ])) + (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 ])) + ])) + +let html = lazy (html ()) +let html () = Lazy.force 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 99% rename from static/packages.csv rename to www/static/packages.csv index 8c91066bd1..be30b8b128 100644 --- a/static/packages.csv +++ b/www/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/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 80% rename from static/style.css rename to www/static/style.css index 56c11b1dea..98e5bca588 100644 --- a/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 c864144f0c..c237e37966 100644 --- a/www/ui.ml +++ b/www/ui.ml @@ -4,37 +4,65 @@ 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_link elt = [ a_href (Db.Entry.link elt) ] + +let string_of_kind = + let open Db.Entry.Kind in + function + | Doc -> "doc" + | Type_decl None -> "type" + | Type_decl (Some str) -> "type " ^ str + | Module -> "module" + | Exception _ -> "exception" + | Class_type -> "class" + | Method -> "method" + | Class -> "class" + | Type_extension -> "type" + | Extension_constructor _ -> "constructor" + | Module_type -> "module type" + | Constructor _ -> "constructor" + | Field _ -> "field" + | Val _ -> "val" + +let render_elt elt = + let open Db.Entry in + let link = render_link elt in + let html_txt = Unsafe.data in + let rhs = + match elt.rhs with + | Some rhs -> [ html_txt rhs ] + | None -> [] + in + let kind = string_of_kind elt.kind ^ " " in + 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 + 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 = render_pkg elt @ render_elt 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| @@ -85,12 +113,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 ] ] @@ -98,25 +121,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" ] [] ] @@ -133,24 +150,16 @@ 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" ] ; 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: " @@ -166,6 +175,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 e934b521d9..91032d6be4 100644 --- a/www/www.ml +++ b/www/www.ml @@ -1,58 +1,25 @@ module Storage = Db.Storage -module Succ = Query.Succ -module Sort = Query.Sort - -type params = - { query : string - ; packages : string list - ; 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 - 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 +open Lwt.Syntax -let match_packages ~packages { Db.Elt.pkg = package, _version; _ } = - List.exists (String.equal package) packages +module Query_lwt = Query.Make (struct + type 'a t = 'a Lwt.t -let match_packages ~packages results = - match packages with - | [] -> results - | _ -> Lwt_stream.filter (match_packages ~packages) results + 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 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+ results = Query_lwt.search ~shards params in + let pretty = Query.pretty params in Ui.render ~pretty results let api ~shards params = - if String.trim params.query = "" - then Lwt.return Ui.explain + 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 = @@ -64,11 +31,12 @@ 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 = get_query params + { Query.query = get_query params ; packages = get_packages params ; limit = get_limit params } @@ -82,24 +50,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) + 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 @@ -110,46 +80,46 @@ 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 main db_filename cache_max_age = - let shards = load_shards db_filename in + 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 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 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)) - ; 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") + let+ result = api ~shards params in + string_of_tyxml' result)) + ; 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 ] 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) +let term = Term.(const main $ cache_max_age) diff --git a/www/www.mli b/www/www.mli new file mode 100644 index 0000000000..fae8900e05 --- /dev/null +++ b/www/www.mli @@ -0,0 +1 @@ +val term : (Db_store.db_format -> string -> unit) Cmdliner.Term.t