this repo has no description
at main 123 lines 4.2 kB view raw
1module Url = Odoc_document.Url 2 3type link = Relative of string list * string | Absolute of string 4 5(* Translation from Url.Path *) 6module Path = struct 7 let for_printing url = List.map snd @@ Url.Path.to_list url 8 9 let segment_to_string (kind, name) = 10 Format.asprintf "%a%s" Url.Path.pp_disambiguating_prefix kind name 11 12 let is_leaf_page url = url.Url.Path.kind = `LeafPage 13 14 let remap config f = 15 let l = String.concat "/" f in 16 let remaps = 17 List.filter 18 (fun (prefix, _replacement) -> Astring.String.is_prefix ~affix:prefix l) 19 (Config.remap config) 20 in 21 let remaps = 22 List.sort 23 (fun (a, _) (b, _) -> compare (String.length b) (String.length a)) 24 remaps 25 in 26 match remaps with 27 | [] -> None 28 | (prefix, replacement) :: _ -> 29 let len = String.length prefix in 30 let l = String.sub l len (String.length l - len) in 31 Some (replacement ^ l) 32 33 let get_dir_and_file ~config url = 34 let l = Url.Path.to_list url in 35 let is_dir = 36 if Config.flat config then function `Page -> `Always | _ -> `Never 37 else function `LeafPage | `File | `SourcePage -> `Never | _ -> `Always 38 in 39 let dir, file = Url.Path.split ~is_dir l in 40 let dir = List.map segment_to_string dir in 41 let file = 42 match file with 43 | [] -> "index.html" 44 | [ (`LeafPage, name) ] -> name ^ ".html" 45 | [ (`File, name) ] -> name 46 | [ (`SourcePage, name) ] -> name ^ ".html" 47 | xs -> 48 assert (Config.flat config); 49 String.concat "-" (List.map segment_to_string xs) ^ ".html" 50 in 51 (dir, file) 52 53 let for_linking ~config url = 54 let dir, file = get_dir_and_file ~config url in 55 match remap config dir with 56 | None -> Relative (dir, file) 57 | Some x -> Absolute (x ^ "/" ^ file) 58 59 let as_filename ~config (url : Url.Path.t) = 60 let dir, file = get_dir_and_file ~config url in 61 Fpath.(v @@ String.concat Fpath.dir_sep (dir @ [ file ])) 62end 63 64type resolve = Current of Url.Path.t | Base of string 65 66let rec drop_shared_prefix l1 l2 = 67 match (l1, l2) with 68 | l1 :: l1s, l2 :: l2s when l1 = l2 -> drop_shared_prefix l1s l2s 69 | _, _ -> (l1, l2) 70 71let href ~config ~resolve t = 72 let { Url.Anchor.page; anchor; _ } = t in 73 let add_anchor y = match anchor with "" -> y | anchor -> y ^ "#" ^ anchor in 74 let target_loc = Path.for_linking ~config page in 75 76 match target_loc with 77 | Absolute y -> add_anchor y 78 | Relative (dir, file) -> ( 79 let target_loc = dir @ [ file ] in 80 (* If xref_base_uri is defined, do not perform relative URI resolution. *) 81 match resolve with 82 | Base xref_base_uri -> 83 let page = xref_base_uri ^ String.concat "/" target_loc in 84 add_anchor page 85 | Current path -> ( 86 let current_loc = 87 let dir, file = Path.get_dir_and_file ~config path in 88 dir @ [ file ] 89 in 90 91 let current_from_common_ancestor, target_from_common_ancestor = 92 drop_shared_prefix current_loc target_loc 93 in 94 95 let relative_target = 96 match current_from_common_ancestor with 97 | [] -> 98 (* We're already on the right page *) 99 (* If we're already on the right page, the target from our common 100 ancestor can't be anything other than the empty list *) 101 assert (target_from_common_ancestor = []); 102 [] 103 | [ _ ] -> 104 (* We're already in the right dir *) 105 target_from_common_ancestor 106 | l -> 107 (* We need to go up some dirs *) 108 List.map (fun _ -> "..") (List.tl l) 109 @ target_from_common_ancestor 110 in 111 let remove_index_html l = 112 match List.rev l with 113 | "index.html" :: rest -> List.rev ("" :: rest) 114 | _ -> l 115 in 116 let relative_target = 117 if Config.semantic_uris config then 118 remove_index_html relative_target 119 else relative_target 120 in 121 match (relative_target, anchor) with 122 | [], "" -> "#" 123 | page, _ -> add_anchor @@ String.concat "/" page))