Skip to content

Commit 6369516

Browse files
committed
Add the ability to remap identifiers during HTML generation
This is to allow the publishing of 'partial docsets' - the idea being that the driver proceeds as usual up until HTML generation, and at that point only generates HTML pages for the packages you wish to publish on your site, and remap links to other packages to ocaml.org or other site.
1 parent 053c55e commit 6369516

File tree

13 files changed

+137
-65
lines changed

13 files changed

+137
-65
lines changed

src/html/config.ml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ type t = {
44
theme_uri : Types.uri option;
55
support_uri : Types.uri option;
66
search_uris : Types.file_uri list;
7+
remap : (string * string) list;
78
semantic_uris : bool;
89
search_result : bool;
910
(* Used to not render links, for summary in search results *)
@@ -14,7 +15,7 @@ type t = {
1415
}
1516

1617
let v ?(search_result = false) ?theme_uri ?support_uri ?(search_uris = [])
17-
~semantic_uris ~indent ~flat ~open_details ~as_json () =
18+
~semantic_uris ~indent ~flat ~open_details ~as_json ~remap () =
1819
{
1920
semantic_uris;
2021
indent;
@@ -25,6 +26,7 @@ let v ?(search_result = false) ?theme_uri ?support_uri ?(search_uris = [])
2526
search_uris;
2627
as_json;
2728
search_result;
29+
remap;
2830
}
2931

3032
let theme_uri config : Types.uri =
@@ -46,3 +48,5 @@ let open_details config = config.open_details
4648
let as_json config = config.as_json
4749

4850
let search_result config = config.search_result
51+
52+
let remap config = config.remap

src/html/config.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ val v :
1212
flat:bool ->
1313
open_details:bool ->
1414
as_json:bool ->
15+
remap:(string * string) list ->
1516
unit ->
1617
t
1718
(** [search_result] indicates whether this is a summary for a search result. In
@@ -34,3 +35,5 @@ val open_details : t -> bool
3435
val as_json : t -> bool
3536

3637
val search_result : t -> bool
38+
39+
val remap : t -> (string * string) list

src/html/generator.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ let render ~config ~sidebar = function
542542
| Source_page src -> [ Page.source_page ~config src ]
543543

544544
let filepath ~config url =
545-
Link.Path.as_filename ~is_flat:(Config.flat config) url
545+
Link.Path.as_filename ~config url
546546

547547
let doc ~config ~xref_base_uri b =
548548
let resolve = Link.Base xref_base_uri in

src/html/html_fragment_json.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ let json_of_toc (toc : Types.toc list) : Utils.Json.json =
3232

3333
let make ~config ~preamble ~url ~breadcrumbs ~sidebar ~toc ~uses_katex
3434
~source_anchor content children =
35-
let filename = Link.Path.as_filename ~is_flat:(Config.flat config) url in
35+
let filename = Link.Path.as_filename ~config url in
3636
let filename = Fpath.add_ext ".json" filename in
3737
let json_to_string json = Utils.Json.to_string json in
3838
let source_anchor =
@@ -65,7 +65,7 @@ let make ~config ~preamble ~url ~breadcrumbs ~sidebar ~toc ~uses_katex
6565
{ Odoc_document.Renderer.filename; content; children }
6666

6767
let make_src ~config ~url ~breadcrumbs content =
68-
let filename = Link.Path.as_filename ~is_flat:(Config.flat config) url in
68+
let filename = Link.Path.as_filename ~config url in
6969
let filename = Fpath.add_ext ".json" filename in
7070
let htmlpp = Html.pp_elt ~indent:(Config.indent config) () in
7171
let json_to_string json = Utils.Json.to_string json in

src/html/html_page.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ let search_urls = %s;
244244

245245
let make ~config ~url ~header ~breadcrumbs ~sidebar ~toc ~uses_katex content
246246
children =
247-
let filename = Link.Path.as_filename ~is_flat:(Config.flat config) url in
247+
let filename = Link.Path.as_filename ~config url in
248248
let content =
249249
page_creator ~config ~url ~uses_katex ~global_toc:sidebar header breadcrumbs
250250
toc content
@@ -285,7 +285,7 @@ let src_page_creator ~breadcrumbs ~config ~url ~header name content =
285285
content
286286

287287
let make_src ~config ~url ~breadcrumbs ~header title content =
288-
let filename = Link.Path.as_filename ~is_flat:(Config.flat config) url in
288+
let filename = Link.Path.as_filename ~config url in
289289
let content =
290290
src_page_creator ~breadcrumbs ~config ~url ~header title content
291291
in

src/html/link.ml

Lines changed: 75 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module Url = Odoc_document.Url
22

3+
type link = Relative of string list * string | Absolute of string
4+
35
(* Translation from Url.Path *)
46
module Path = struct
57
let for_printing url = List.map snd @@ Url.Path.to_list url
@@ -11,10 +13,23 @@ module Path = struct
1113

1214
let is_leaf_page url = url.Url.Path.kind = `LeafPage
1315

14-
let get_dir_and_file is_flat url =
16+
let remap config f =
17+
let l = String.concat "/" f in
18+
match
19+
List.find_opt
20+
(fun (prefix, _replacement) -> Astring.String.is_prefix ~affix:prefix l)
21+
(Config.remap config)
22+
with
23+
| None -> None
24+
| Some (prefix, replacement) ->
25+
let len = String.length prefix in
26+
let l = String.sub l len (String.length l - len) in
27+
Some (replacement ^ l)
28+
29+
let get_dir_and_file ~config url =
1530
let l = Url.Path.to_list url in
1631
let is_dir =
17-
if is_flat then function `Page -> `Always | _ -> `Never
32+
if Config.flat config then function `Page -> `Always | _ -> `Never
1833
else function `LeafPage | `File | `SourcePage -> `Never | _ -> `Always
1934
in
2035
let dir, file = Url.Path.split ~is_dir l in
@@ -26,19 +41,20 @@ module Path = struct
2641
| [ (`File, name) ] -> name
2742
| [ (`SourcePage, name) ] -> name ^ ".html"
2843
| xs ->
29-
assert is_flat;
44+
assert (Config.flat config);
3045
String.concat "-" (List.map segment_to_string xs) ^ ".html"
3146
in
3247
(dir, file)
3348

34-
let for_linking ~is_flat url =
35-
let dir, file = get_dir_and_file is_flat url in
36-
dir @ [ file ]
49+
let for_linking ~config url =
50+
let dir, file = get_dir_and_file ~config url in
51+
match remap config dir with
52+
| None -> Relative (dir, file)
53+
| Some x -> Absolute (x ^ "/" ^ file)
3754

38-
let as_filename ~is_flat (url : Url.Path.t) =
39-
let url_segs = for_linking ~is_flat url in
40-
let filename = Fpath.(v @@ String.concat Fpath.dir_sep @@ url_segs) in
41-
filename
55+
let as_filename ~config (url : Url.Path.t) =
56+
let dir, file = get_dir_and_file ~config url in
57+
Fpath.(v @@ String.concat Fpath.dir_sep (dir @ [ file ]))
4258
end
4359

4460
type resolve = Current of Url.Path.t | Base of string
@@ -50,46 +66,55 @@ let rec drop_shared_prefix l1 l2 =
5066

5167
let href ~config ~resolve t =
5268
let { Url.Anchor.page; anchor; _ } = t in
69+
let add_anchor y = match anchor with "" -> y | anchor -> y ^ "#" ^ anchor in
70+
let target_loc = Path.for_linking ~config page in
5371

54-
let target_loc = Path.for_linking ~is_flat:(Config.flat config) page in
55-
56-
(* If xref_base_uri is defined, do not perform relative URI resolution. *)
57-
match resolve with
58-
| Base xref_base_uri -> (
59-
let page = xref_base_uri ^ String.concat "/" target_loc in
60-
match anchor with "" -> page | anchor -> page ^ "#" ^ anchor)
61-
| Current path -> (
62-
let current_loc = Path.for_linking ~is_flat:(Config.flat config) path in
72+
match target_loc with
73+
| Absolute y -> add_anchor y
74+
| Relative (dir, file) -> (
75+
let target_loc = dir @ [ file ] in
76+
(* If xref_base_uri is defined, do not perform relative URI resolution. *)
77+
match resolve with
78+
| Base xref_base_uri ->
79+
let page = xref_base_uri ^ String.concat "/" target_loc in
80+
add_anchor page
81+
| Current path -> (
82+
let current_loc =
83+
let dir, file = Path.get_dir_and_file ~config path in
84+
dir @ [ file ]
85+
in
6386

64-
let current_from_common_ancestor, target_from_common_ancestor =
65-
drop_shared_prefix current_loc target_loc
66-
in
87+
let current_from_common_ancestor, target_from_common_ancestor =
88+
drop_shared_prefix current_loc target_loc
89+
in
6790

68-
let relative_target =
69-
match current_from_common_ancestor with
70-
| [] ->
71-
(* We're already on the right page *)
72-
(* If we're already on the right page, the target from our common
73-
ancestor can't be anything other than the empty list *)
74-
assert (target_from_common_ancestor = []);
75-
[]
76-
| [ _ ] ->
77-
(* We're already in the right dir *)
78-
target_from_common_ancestor
79-
| l ->
80-
(* We need to go up some dirs *)
81-
List.map (fun _ -> "..") (List.tl l) @ target_from_common_ancestor
82-
in
83-
let remove_index_html l =
84-
match List.rev l with
85-
| "index.html" :: rest -> List.rev ("" :: rest)
86-
| _ -> l
87-
in
88-
let relative_target =
89-
if Config.semantic_uris config then remove_index_html relative_target
90-
else relative_target
91-
in
92-
match (relative_target, anchor) with
93-
| [], "" -> "#"
94-
| page, "" -> String.concat "/" page
95-
| page, anchor -> String.concat "/" page ^ "#" ^ anchor)
91+
let relative_target =
92+
match current_from_common_ancestor with
93+
| [] ->
94+
(* We're already on the right page *)
95+
(* If we're already on the right page, the target from our common
96+
ancestor can't be anything other than the empty list *)
97+
assert (target_from_common_ancestor = []);
98+
[]
99+
| [ _ ] ->
100+
(* We're already in the right dir *)
101+
target_from_common_ancestor
102+
| l ->
103+
(* We need to go up some dirs *)
104+
List.map (fun _ -> "..") (List.tl l)
105+
@ target_from_common_ancestor
106+
in
107+
let remove_index_html l =
108+
match List.rev l with
109+
| "index.html" :: rest -> List.rev ("" :: rest)
110+
| _ -> l
111+
in
112+
let relative_target =
113+
if Config.semantic_uris config then
114+
remove_index_html relative_target
115+
else relative_target
116+
in
117+
match (relative_target, anchor) with
118+
| [], "" -> "#"
119+
| page, "" -> String.concat "/" page
120+
| page, anchor -> String.concat "/" page ^ "#" ^ anchor))

src/html/link.mli

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,5 @@ module Path : sig
1111

1212
val for_printing : Url.Path.t -> string list
1313

14-
val for_linking : is_flat:bool -> Url.Path.t -> string list
15-
16-
val as_filename : is_flat:bool -> Url.Path.t -> Fpath.t
14+
val as_filename : config:Config.t -> Url.Path.t -> Fpath.t
1715
end

src/odoc/bin/main.ml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,19 +1176,31 @@ module Odoc_html_args = struct
11761176
in
11771177
Arg.(value & flag & info ~doc [ "as-json" ])
11781178

1179+
let remap =
1180+
let convert_remap =
1181+
let parse inp =
1182+
match Astring.String.cut ~sep:":" inp with
1183+
| Some (orig, mapped) -> Ok (orig, mapped)
1184+
| _ -> Error (`Msg "Map must be of the form '<orig>:https://...'")
1185+
and print fmt (orig, mapped) = Format.fprintf fmt "%s:%s" orig mapped in
1186+
Arg.conv (parse, print)
1187+
in
1188+
let doc = "Remap an identifier to an external URL." in
1189+
Arg.(value & opt_all convert_remap [] & info [ "R" ] ~doc)
1190+
11791191
let extra_args =
11801192
let config semantic_uris closed_details indent theme_uri support_uri
1181-
search_uris flat as_json =
1193+
search_uris flat as_json remap =
11821194
let open_details = not closed_details in
11831195
let html_config =
11841196
Odoc_html.Config.v ~theme_uri ~support_uri ~search_uris ~semantic_uris
1185-
~indent ~flat ~open_details ~as_json ()
1197+
~indent ~flat ~open_details ~as_json ~remap ()
11861198
in
11871199
{ Html_page.html_config }
11881200
in
11891201
Term.(
11901202
const config $ semantic_uris $ closed_details $ indent $ theme_uri
1191-
$ support_uri $ search_uri $ flat $ as_json)
1203+
$ support_uri $ search_uri $ flat $ as_json $ remap)
11921204
end
11931205

11941206
module Odoc_html = Make_renderer (Odoc_html_args)

src/odoc/html_fragment.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ let from_mld ~xref_base_uri ~resolver ~output ~warnings_options input =
3737
let page = Odoc_document.Comment.to_ir resolved.content in
3838
let config =
3939
Odoc_html.Config.v ~semantic_uris:false ~indent:false ~flat:false
40-
~open_details:false ~as_json:false ()
40+
~open_details:false ~as_json:false ~remap:[] ()
4141
in
4242
let html = Odoc_html.Generator.doc ~config ~xref_base_uri page in
4343
let oc = open_out (Fs.File.to_string output) in

src/search/html.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ let url { Entry.id; kind; doc = _ } =
2222
| Ok url ->
2323
let config =
2424
Odoc_html.Config.v ~search_result:true ~semantic_uris:false
25-
~indent:false ~flat:false ~open_details:false ~as_json:false ()
25+
~indent:false ~flat:false ~open_details:false ~as_json:false ~remap:[]
26+
()
2627
in
2728
let url = Odoc_html.Link.href ~config ~resolve:(Base "") url in
2829
Result.Ok url
@@ -201,7 +202,7 @@ let names_of_id id =
201202
let of_doc doc =
202203
let config =
203204
Odoc_html.Config.v ~search_result:true ~semantic_uris:false ~indent:false
204-
~flat:false ~open_details:false ~as_json:false ()
205+
~flat:false ~open_details:false ~as_json:false ~remap:[] ()
205206
in
206207
Tyxml.Html.div ~a:[]
207208
@@ Odoc_html.Generator.doc ~config ~xref_base_uri:""

0 commit comments

Comments
 (0)