Skip to content

Commit 22e00bf

Browse files
panglesdjonludlam
authored andcommitted
Collect occurrences info
Signed-off-by: Paul-Elliot <[email protected]>
1 parent e8333e3 commit 22e00bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+828
-138
lines changed

doc/driver.mld

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ Compiling a file with [odoc] requires a few arguments: the file to compile, an
135135
optional parent, a list of include paths, a list of children for [.mld] files,
136136
optional parent and name for source implementation, and an output path. Include
137137
paths can be just ['.'], and we can calculate the output file from the input
138-
because all of the files are going into the same directory.
138+
because all of the files are going into the same directory. If we wish to count
139+
occurrences of each identifier, we need to pass the [--count-occurrences] flag.
139140

140141
Linking a file with [odoc] requires the input file and a list of include paths. As
141142
for compile, we will hard-code the include path.
@@ -148,6 +149,9 @@ Using the [--source] argument with an [.odocl] file that was not compiled with
148149
[--source-parent-file] and [--source-name] will result in an error, as will omitting [--source] when generating HTML of an [odocl] that was
149150
compiled with [--source-parent-file] and [--source-name].
150151

152+
To get the number of uses of each identifier, we can use the [count-occurrences]
153+
command.
154+
151155
In all of these, we'll capture [stdout] and [stderr] so we can check it later.
152156

153157
{[
@@ -209,7 +213,7 @@ let add_prefixed_output cmd list prefix lines =
209213
!list
210214
@ Bos.Cmd.to_string cmd :: List.map (fun l -> prefix ^ ": " ^ l) lines
211215

212-
let compile file ?parent ?(output_dir = Fpath.v "./")
216+
let compile file ?(count_occurrences = true) ?parent ?(output_dir = Fpath.v "./")
213217
?(ignore_output = false) ?source_args children =
214218
let output_basename =
215219
let ext = Fpath.get_ext file in
@@ -237,8 +241,9 @@ let compile file ?parent ?(output_dir = Fpath.v "./")
237241
| _ -> Cmd.empty
238242
else Cmd.empty
239243
in
244+
let occ = if count_occurrences then Cmd.v "--count-occurrences" else Cmd.empty in
240245
let cmd =
241-
odoc % "compile" % Fpath.to_string file %% source_args %% cmt_arg
246+
odoc % "compile" % Fpath.to_string file %% source_args %% occ %% cmt_arg
242247
% "-I" % "." % "-o" % p output_file
243248
|> List.fold_right (fun child cmd -> cmd % "--child" % child) children
244249
in
@@ -289,6 +294,11 @@ let support_files () =
289294
let open Cmd in
290295
let cmd = odoc % "support-files" % "-o" % "html/odoc" in
291296
run cmd
297+
298+
let count_occurrences output =
299+
let open Cmd in
300+
let cmd = odoc % "count-occurrences" % "-I" % "." % "-o" % p output in
301+
run cmd
292302
]}
293303

294304

@@ -750,6 +760,7 @@ let compiled = compile_all () in
750760
let linked = link_all compiled in
751761
let () = index_generate () in
752762
let _ = js_index () in
763+
let _ = count_occurrences (Fpath.v "occurrences.txt") in
753764
generate_all linked
754765
]}
755766

src/document/generator.ml

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,18 +252,42 @@ module Make (Syntax : SYNTAX) = struct
252252
let path id = Url.Path.from_identifier id
253253
let url id = Url.from_path (path id)
254254

255+
let to_link documentation implementation =
256+
let documentation =
257+
let open Paths.Path.Resolved in
258+
match documentation with
259+
| Some (`Resolved p) when not (is_hidden (p :> t)) -> (
260+
let id = identifier (p :> t) in
261+
match Url.from_identifier ~stop_before:false id with
262+
| Ok link -> Some link
263+
| _ -> None)
264+
| _ -> None
265+
in
266+
let implementation =
267+
match implementation with
268+
| Some (Odoc_model.Lang.Source_info.Resolved id) -> (
269+
match Url.Anchor.from_identifier (id :> Paths.Identifier.t) with
270+
| Ok url -> Some url
271+
| Error _ -> None)
272+
| _ -> None
273+
in
274+
Some (Source_page.Link { implementation; documentation })
275+
255276
let info_of_info : Lang.Source_info.annotation -> Source_page.info option =
256277
function
257-
| Value id -> (
258-
match Url.Anchor.from_identifier (id :> Paths.Identifier.t) with
259-
| Ok url -> Some (Link url)
260-
| Error _ -> None)
261278
| Definition id -> (
262279
match id.iv with
263280
| `SourceLocation (_, def) -> Some (Anchor (DefName.to_string def))
264281
| `SourceLocationInternal (_, local) ->
265282
Some (Anchor (LocalName.to_string local))
266283
| _ -> None)
284+
| Module { documentation; _ } -> to_link documentation None
285+
| ModuleType { documentation; _ } -> to_link documentation None
286+
| Type { documentation; _ } -> to_link documentation None
287+
| ClassType { documentation; _ } -> to_link documentation None
288+
| Value { documentation; implementation } ->
289+
to_link documentation implementation
290+
| Constructor { documentation; _ } -> to_link documentation None
267291

268292
let source id syntax_info infos source_code =
269293
let url = path id in
@@ -1784,8 +1808,8 @@ module Make (Syntax : SYNTAX) = struct
17841808
in
17851809
let source_anchor =
17861810
match t.source_info with
1787-
| Some src -> Some (Source_page.url src.id)
1788-
| None -> None
1811+
| Some { id = Some id; _ } -> Some (Source_page.url id)
1812+
| _ -> None
17891813
in
17901814
let page = make_expansion_page ~source_anchor url [ unit_doc ] items in
17911815
Document.Page page

src/document/types.ml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,11 @@ end =
183183
Page
184184

185185
and Source_page : sig
186-
type info = Syntax of string | Anchor of string | Link of Url.Anchor.t
186+
type target = {
187+
documentation : Url.Anchor.t option;
188+
implementation : Url.Anchor.t option;
189+
}
190+
type info = Syntax of string | Anchor of string | Link of target
187191

188192
type code = span list
189193
and span = Tagged_code of info * code | Plain_code of string

src/html/html_source.ml

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,31 @@ let html_of_doc ~config ~resolve docs =
2424
let children = List.concat @@ List.map (doc_to_html ~is_in_a) docs in
2525
match info with
2626
| Syntax tok -> [ span ~a:[ a_class [ tok ] ] children ]
27-
| Link anchor ->
28-
let href = Link.href ~config ~resolve anchor in
29-
[ a ~a:[ a_href href ] children ]
27+
| Link { documentation; implementation } -> (
28+
let href_implementation =
29+
Option.map (Link.href ~config ~resolve) implementation
30+
in
31+
let href_documentation =
32+
Option.map (Link.href ~config ~resolve) documentation
33+
in
34+
let body =
35+
match href_implementation with
36+
| Some href -> [ a ~a:[ a_href href ] children ]
37+
| None -> children
38+
in
39+
match href_documentation with
40+
| None -> body
41+
| Some href ->
42+
[
43+
span
44+
~a:[ a_class [ "jump-to-doc-container" ] ]
45+
[
46+
span ~a:[] body;
47+
a
48+
~a:[ a_href href; a_class [ "jump-to-doc" ] ]
49+
[ txt " 📖" ];
50+
];
51+
])
3052
| Anchor lbl -> [ span ~a:[ a_id lbl ] children ])
3153
in
3254
span ~a:[] @@ List.concat @@ List.map (doc_to_html ~is_in_a:false) docs

src/html_support_files/odoc.css

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,14 @@ td.def-doc *:first-child {
12061206
color: #657b83;
12071207
}
12081208

1209+
.jump-to-doc-container:hover .jump-to-doc {
1210+
display: inline;
1211+
}
1212+
1213+
.jump-to-doc {
1214+
display: none;
1215+
}
1216+
12091217
/* Source directories */
12101218

12111219
.odoc-directory::before {
@@ -1390,4 +1398,4 @@ td.def-doc *:first-child {
13901398
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13911399
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13921400
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1393-
---------------------------------------------------------------------------*/
1401+
---------------------------------------------------------------------------*/

src/loader/ident_env.cppo.ml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,9 @@ module Path = struct
718718
`Identifier (find_type env id, false)
719719
with Not_found -> assert false
720720

721+
let read_value_ident env id : Paths.Path.Value.t =
722+
`Identifier (find_value_identifier env id, false)
723+
721724
let read_class_type_ident env id : Paths.Path.ClassType.t =
722725
try
723726
`Identifier (find_class_type env id, false)
@@ -796,6 +799,18 @@ module Path = struct
796799
| Path.Pextra_ty (p,_) -> read_type env p
797800
#endif
798801

802+
let read_value env = function
803+
| Path.Pident id -> read_value_ident env id
804+
#if OCAML_VERSION >= (4,8,0)
805+
| Path.Pdot(p, s) -> `Dot(read_module env p, s)
806+
#else
807+
| Path.Pdot(p, s, _) -> `Dot(read_module env p, s)
808+
#endif
809+
| Path.Papply(_, _) -> assert false
810+
#if OCAML_VERSION >= (5,1,0)
811+
| Path.Pextra_ty _ -> assert false
812+
#endif
813+
799814
end
800815

801816
module Fragment = struct

src/loader/ident_env.cppo.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ module Path : sig
4040
val read_type : t -> Path.t -> Paths.Path.Type.t
4141

4242
val read_class_type : t -> Path.t -> Paths.Path.ClassType.t
43+
44+
val read_value : t -> Path.t -> Paths.Path.Value.t
4345
end
4446

4547
val find_module : t -> Ident.t -> Paths.Path.Module.t

src/loader/implementation.ml

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -147,19 +147,23 @@ module UidHashtbl = Shape.Uid.Tbl
147147

148148
(* Adds the local definitions found in traverse infos to the [loc_to_id] and
149149
[ident_to_id] tables. *)
150-
let populate_local_defs source_id poses loc_to_id ident_to_id =
150+
let populate_local_defs source_id poses loc_to_id ident_to_loc =
151151
List.iter
152152
(function
153153
| Typedtree_traverse.Analysis.Definition id, loc ->
154154
let name =
155155
Odoc_model.Names.LocalName.make_std
156156
(Printf.sprintf "local_%s_%d" (Ident.name id) (counter ()))
157157
in
158-
let identifier =
159-
Odoc_model.Paths.Identifier.Mk.source_location_int (source_id, name)
160-
in
161-
IdentHashtbl.add ident_to_id id identifier;
162-
LocHashtbl.add loc_to_id loc identifier
158+
(match source_id with
159+
Some source_id ->
160+
let identifier =
161+
Odoc_model.Paths.Identifier.Mk.source_location_int (source_id, name)
162+
in
163+
LocHashtbl.add loc_to_id loc identifier
164+
| None -> ()
165+
);
166+
IdentHashtbl.add ident_to_loc id loc;
163167
| _ -> ())
164168
poses
165169

@@ -245,6 +249,7 @@ let anchor_of_identifier id =
245249
(* Adds the global definitions, found in the [uid_to_loc], to the [loc_to_id]
246250
and [uid_to_id] tables. *)
247251
let populate_global_defs env source_id loc_to_id uid_to_loc uid_to_id =
252+
match source_id with None -> () | Some source_id ->
248253
let mk_src_id id =
249254
let name = Odoc_model.Names.DefName.make_std (anchor_of_identifier id) in
250255
(Odoc_model.Paths.Identifier.Mk.source_location (source_id, name)
@@ -278,54 +283,86 @@ let populate_global_defs env source_id loc_to_id uid_to_loc uid_to_id =
278283
| _ -> ()))
279284
uid_to_loc
280285

286+
let (>>=) a b = Option.map b a
287+
281288
(* Extract [Typedtree_traverse] occurrence information and turn them into proper
282289
source infos *)
283-
let process_occurrences poses uid_to_id ident_to_id =
290+
let process_occurrences env poses loc_to_id ident_to_loc =
291+
let open Odoc_model.Lang.Source_info in
292+
let process p find_in_env =
293+
match p with
294+
| Path.Pident id when IdentHashtbl.mem ident_to_loc id -> (
295+
match
296+
LocHashtbl.find_opt loc_to_id (IdentHashtbl.find ident_to_loc id)
297+
with
298+
| None -> None
299+
| Some id ->
300+
let documentation = None and implementation = Some (Resolved id) in
301+
Some { documentation; implementation })
302+
| p -> (
303+
match find_in_env env p with
304+
| path ->
305+
let documentation = Some path
306+
and implementation = Some (Unresolved path) in
307+
Some { documentation; implementation }
308+
| exception _ -> None)
309+
in
284310
List.filter_map
285311
(function
286-
| Typedtree_traverse.Analysis.Value (LocalValue uniq), loc -> (
287-
match IdentHashtbl.find_opt ident_to_id uniq with
288-
| Some anchor ->
289-
Some (Odoc_model.Lang.Source_info.Value anchor, pos_of_loc loc)
290-
| None -> None)
291-
| Value (DefJmp x), loc -> (
292-
match UidHashtbl.find_opt uid_to_id x with
293-
| Some id -> Some (Value id, pos_of_loc loc)
294-
| None -> None)
312+
| Typedtree_traverse.Analysis.Value p, loc ->
313+
process p Ident_env.Path.read_value >>= fun l ->
314+
(Value l, pos_of_loc loc)
315+
| Module p, loc ->
316+
process p Ident_env.Path.read_module >>= fun l ->
317+
(Module l, pos_of_loc loc)
318+
| ClassType p, loc ->
319+
process p Ident_env.Path.read_class_type >>= fun l ->
320+
(ClassType l, pos_of_loc loc)
321+
| ModuleType p, loc ->
322+
process p Ident_env.Path.read_module_type >>= fun l ->
323+
(ModuleType l, pos_of_loc loc)
324+
| Type p, loc ->
325+
process p Ident_env.Path.read_type >>= fun l ->
326+
(Type l, pos_of_loc loc)
327+
| Constructor _p, loc ->
328+
(* process p Ident_env.Path.read_constructor *) None >>= fun l ->
329+
(Constructor l, pos_of_loc loc)
295330
| Definition _, _ -> None)
296331
poses
297332

333+
298334
(* Add definition source info from the [loc_to_id] table *)
299335
let add_definitions loc_to_id occurrences =
300336
LocHashtbl.fold
301337
(fun loc id acc ->
302338
(Odoc_model.Lang.Source_info.Definition id, pos_of_loc loc) :: acc)
303339
loc_to_id occurrences
304340

305-
let read_cmt_infos source_id_opt id cmt_info =
341+
let read_cmt_infos source_id_opt id cmt_info ~count_occurrences =
306342
match Odoc_model.Compat.shape_of_cmt_infos cmt_info with
307343
| Some shape -> (
308344
let uid_to_loc = cmt_info.cmt_uid_to_loc in
309-
match (source_id_opt, cmt_info.cmt_annots) with
310-
| Some source_id, Implementation impl ->
345+
match (source_id_opt, count_occurrences, cmt_info.cmt_annots) with
346+
| (Some _ as source_id), _, Implementation impl
347+
| source_id, true, Implementation impl ->
311348
let env = Env.of_structure id impl in
312349
let traverse_infos =
313-
Typedtree_traverse.of_cmt env uid_to_loc impl |> List.rev
350+
Typedtree_traverse.of_cmt env impl |> List.rev
314351
(* Information are accumulated in a list. We need to have the
315352
first info first in the list, to assign anchors with increasing
316353
numbers, so that adding some content at the end of a file does
317354
not modify the anchors for existing anchors. *)
318355
in
319356
let loc_to_id = LocHashtbl.create 10
320-
and ident_to_id = IdentHashtbl.create 10
357+
and ident_to_loc = IdentHashtbl.create 10
321358
and uid_to_id = UidHashtbl.create 10 in
322359
let () =
323360
(* populate [loc_to_id], [ident_to_id] and [uid_to_id] *)
324-
populate_local_defs source_id traverse_infos loc_to_id ident_to_id;
361+
populate_local_defs source_id traverse_infos loc_to_id ident_to_loc;
325362
populate_global_defs env source_id loc_to_id uid_to_loc uid_to_id
326363
in
327364
let source_infos =
328-
process_occurrences traverse_infos uid_to_id ident_to_id
365+
process_occurrences env traverse_infos loc_to_id ident_to_loc
329366
|> add_definitions loc_to_id
330367
in
331368
( Some (shape, Shape.Uid.Tbl.to_map uid_to_id),
@@ -334,7 +371,7 @@ let read_cmt_infos source_id_opt id cmt_info =
334371
Odoc_model.Lang.Source_info.id = source_id;
335372
infos = source_infos;
336373
} )
337-
| _, _ -> (Some (shape, Odoc_model.Compat.empty_map), None))
374+
| _, _, _ -> (Some (shape, Odoc_model.Compat.empty_map), None))
338375
| None -> (None, None)
339376

340377
#else

src/loader/implementation.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ val read_cmt_infos :
22
Odoc_model.Paths.Identifier.Id.source_page option ->
33
Odoc_model.Paths.Identifier.Id.root_module ->
44
Cmt_format.cmt_infos ->
5+
count_occurrences:bool ->
56
(Odoc_model.Compat.shape
67
* Odoc_model.Paths.Identifier.Id.source_location
78
Odoc_model.Compat.shape_uid_map)

0 commit comments

Comments
 (0)