File: main.ml

package info (click to toggle)
ocaml-odoc 3.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 12,104 kB
  • sloc: ml: 59,291; javascript: 2,572; sh: 566; makefile: 31
file content (155 lines) | stat: -rw-r--r-- 4,620 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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
  | Page -> kind_doc
  | Impl -> kind_impl
  | 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 ()