From a00a1abb42dfe4c4cc58ce88210229bc423cb0a8 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Wed, 27 Nov 2024 17:45:46 +0100 Subject: [PATCH] Sidebar: Add the global sidebar to implementation pages --- src/driver/compile.ml | 12 ++++++++++-- src/driver/odoc.ml | 9 ++++++--- src/driver/odoc.mli | 1 + src/html/generator.ml | 17 +++++++++++++---- src/html/html_fragment_json.ml | 27 +++++++++++++++------------ src/html/html_fragment_json.mli | 1 + src/html/html_page.ml | 7 ++++--- src/html/html_page.mli | 1 + src/html_support_files/odoc.css | 10 +++++++++- src/odoc/bin/main.ml | 11 +++++++---- src/odoc/rendering.ml | 8 ++++++-- src/odoc/rendering.mli | 1 + 12 files changed, 74 insertions(+), 31 deletions(-) diff --git a/src/driver/compile.ml b/src/driver/compile.ml index a1159769a3..b25c952d42 100644 --- a/src/driver/compile.ml +++ b/src/driver/compile.ml @@ -300,9 +300,17 @@ let html_generate ~occurrence_file output_dir linked = match l.kind with | `Intf { hidden = true; _ } -> () | `Impl { src_path; _ } -> - Odoc.html_generate_source ~search_uris:[] ~output_dir ~input_file + let search_uris, sidebar = + match l.index with + | None -> (None, None) + | Some index -> + let db_path, sidebar = compile_index index in + let search_uris = [ db_path; Sherlodoc.js_file ] in + (Some search_uris, sidebar) + in + Odoc.html_generate_source ?search_uris ?sidebar ~output_dir ~input_file ~source:src_path (); - Odoc.html_generate_source ~search_uris:[] ~output_dir ~input_file + Odoc.html_generate_source ?search_uris ?sidebar ~output_dir ~input_file ~source:src_path ~as_json:true (); Atomic.incr Stats.stats.generated_units | `Asset -> diff --git a/src/driver/odoc.ml b/src/driver/odoc.ml index c2c8d29bf5..244206628a 100644 --- a/src/driver/odoc.ml +++ b/src/driver/odoc.ml @@ -230,18 +230,21 @@ let html_generate_asset ~output_dir ?(ignore_output = false) ~input_file:file in ignore @@ Cmd_outputs.submit log desc cmd None -let html_generate_source ~output_dir ?(ignore_output = false) ~source +let html_generate_source ~output_dir ?(ignore_output = false) ~source ?sidebar ?(search_uris = []) ?(as_json = false) ~input_file:file () = let open Cmd in let file = v "--impl" % p file in + let sidebar = + match sidebar with None -> empty | Some idx -> v "--sidebar" % p idx + in let search_uris = List.fold_left (fun acc filename -> acc % "--search-uri" % p filename) empty search_uris in let cmd = - !odoc % "html-generate-source" %% file % p source %% search_uris % "-o" - % output_dir + !odoc % "html-generate-source" %% file %% sidebar % p source %% search_uris + % "-o" % output_dir in let cmd = if as_json then cmd % "--as-json" else cmd in diff --git a/src/driver/odoc.mli b/src/driver/odoc.mli index 8c7c55c08c..73b3b5936a 100644 --- a/src/driver/odoc.mli +++ b/src/driver/odoc.mli @@ -80,6 +80,7 @@ val html_generate_source : output_dir:string -> ?ignore_output:bool -> source:Fpath.t -> + ?sidebar:Fpath.t -> ?search_uris:Fpath.t list -> ?as_json:bool -> input_file:Fpath.t -> diff --git a/src/html/generator.ml b/src/html/generator.ml index 2eaf198a65..9b0ef2f1ec 100644 --- a/src/html/generator.ml +++ b/src/html/generator.ml @@ -567,9 +567,16 @@ module Page = struct Html_page.make ~sidebar ~config ~header ~toc ~breadcrumbs ~url ~uses_katex content subpages - and source_page ~config sp = + and source_page ~config ~sidebar sp = let { Source_page.url; contents } = sp in let resolve = Link.Current sp.url in + let sidebar = + match sidebar with + | None -> None + | Some sidebar -> + let sidebar = Odoc_document.Sidebar.to_block sidebar url in + (Some (block ~config ~resolve sidebar) :> any Html.elt list option) + in let title = url.Url.Path.name and doc = Html_source.html_of_doc ~config ~resolve contents in let breadcrumbs = Breadcrumbs.gen_breadcrumbs ~config ~url in @@ -577,13 +584,15 @@ module Page = struct items ~config ~resolve (Doctree.PageTitle.render_src_title sp) in if Config.as_json config then - Html_fragment_json.make_src ~config ~url ~breadcrumbs [ doc ] - else Html_page.make_src ~breadcrumbs ~header ~config ~url title [ doc ] + Html_fragment_json.make_src ~config ~url ~breadcrumbs ~sidebar [ doc ] + else + Html_page.make_src ~breadcrumbs ~header ~config ~url ~sidebar title + [ doc ] end let render ~config ~sidebar = function | Document.Page page -> [ Page.page ~config ~sidebar page ] - | Source_page src -> [ Page.source_page ~config src ] + | Source_page src -> [ Page.source_page ~config ~sidebar src ] let filepath ~config url = Link.Path.as_filename ~config url diff --git a/src/html/html_fragment_json.ml b/src/html/html_fragment_json.ml index 3fe6a9bdbb..8ef843594a 100644 --- a/src/html/html_fragment_json.ml +++ b/src/html/html_fragment_json.ml @@ -30,6 +30,15 @@ let json_of_toc (toc : Types.toc list) : Json.json = let toc_json_list = toc |> List.map section in `Array toc_json_list +let json_of_html config h = + let htmlpp = Html.pp_elt ~indent:(Config.indent config) () in + String.concat "" (List.map (Format.asprintf "%a" htmlpp) h) + +let json_of_sidebar config sidebar = + match sidebar with + | None -> `Null + | Some sidebar -> `String (json_of_html config sidebar) + let make ~config ~preamble ~url ~breadcrumbs ~sidebar ~toc ~uses_katex ~source_anchor content children = let filename = Link.Path.as_filename ~config url in @@ -38,15 +47,7 @@ let make ~config ~preamble ~url ~breadcrumbs ~sidebar ~toc ~uses_katex let source_anchor = match source_anchor with Some url -> `String url | None -> `Null in - let json_of_html h = - let htmlpp = Html.pp_elt ~indent:(Config.indent config) () in - String.concat "" (List.map (Format.asprintf "%a" htmlpp) h) - in - let global_toc = - match sidebar with - | None -> `Null - | Some sidebar -> `String (json_of_html sidebar) - in + let global_toc = json_of_sidebar config sidebar in let content ppf = Format.pp_print_string ppf (json_to_string @@ -58,17 +59,18 @@ let make ~config ~preamble ~url ~breadcrumbs ~sidebar ~toc ~uses_katex ("toc", json_of_toc toc); ("global_toc", global_toc); ("source_anchor", source_anchor); - ("preamble", `String (json_of_html preamble)); - ("content", `String (json_of_html content)); + ("preamble", `String (json_of_html config preamble)); + ("content", `String (json_of_html config content)); ])) in { Odoc_document.Renderer.filename; content; children; path = url } -let make_src ~config ~url ~breadcrumbs content = +let make_src ~config ~url ~breadcrumbs ~sidebar content = let filename = Link.Path.as_filename ~config url in let filename = Fpath.add_ext ".json" filename in let htmlpp = Html.pp_elt ~indent:(Config.indent config) () in let json_to_string json = Json.to_string json in + let global_toc = json_of_sidebar config sidebar in let content ppf = Format.pp_print_string ppf (json_to_string @@ -76,6 +78,7 @@ let make_src ~config ~url ~breadcrumbs content = [ ("type", `String "source"); ("breadcrumbs", json_of_breadcrumbs breadcrumbs); + ("global_toc", global_toc); ( "content", `String (String.concat "" diff --git a/src/html/html_fragment_json.mli b/src/html/html_fragment_json.mli index eda81b53c0..d3e0527e8d 100644 --- a/src/html/html_fragment_json.mli +++ b/src/html/html_fragment_json.mli @@ -17,5 +17,6 @@ val make_src : config:Config.t -> url:Odoc_document.Url.Path.t -> breadcrumbs:Types.breadcrumb list -> + sidebar:Html_types.div_content Html.elt list option -> Html_types.div_content Html.elt list -> Odoc_document.Renderer.page diff --git a/src/html/html_page.ml b/src/html/html_page.ml index 54f02f727d..0c6adedb4f 100644 --- a/src/html/html_page.ml +++ b/src/html/html_page.ml @@ -258,7 +258,7 @@ let path_of_module_of_source ppf url = Format.fprintf ppf " (%s)" (String.concat "." path) | None -> () -let src_page_creator ~breadcrumbs ~config ~url ~header name content = +let src_page_creator ~breadcrumbs ~config ~url ~header ~sidebar name content = let head : Html_types.head Html.elt = let title_string = Format.asprintf "Source: %s%a" name path_of_module_of_source url @@ -269,6 +269,7 @@ let src_page_creator ~breadcrumbs ~config ~url ~header name content = let body = html_of_breadcrumbs breadcrumbs @ [ Html.header ~a:[ Html.a_class [ "odoc-preamble" ] ] header ] + @ sidebars ~global_toc:sidebar ~local_toc:[] @ content in (* We never indent as there is a bug in tyxml and it would break lines inside @@ -284,9 +285,9 @@ let src_page_creator ~breadcrumbs ~config ~url ~header name content = in content -let make_src ~config ~url ~breadcrumbs ~header title content = +let make_src ~config ~url ~breadcrumbs ~header ~sidebar title content = let filename = Link.Path.as_filename ~config url in let content = - src_page_creator ~breadcrumbs ~config ~url ~header title content + src_page_creator ~breadcrumbs ~config ~url ~header ~sidebar title content in { Odoc_document.Renderer.filename; content; children = []; path = url } diff --git a/src/html/html_page.mli b/src/html/html_page.mli index b085675793..f327091447 100644 --- a/src/html/html_page.mli +++ b/src/html/html_page.mli @@ -40,6 +40,7 @@ val make_src : url:Odoc_document.Url.Path.t -> breadcrumbs:Types.breadcrumb list -> header:Html_types.flow5_without_header_footer Html.elt list -> + sidebar:Html_types.div_content Html.elt list option -> string -> Html_types.div_content Html.elt list -> Odoc_document.Renderer.page diff --git a/src/html_support_files/odoc.css b/src/html_support_files/odoc.css index 8915755faa..b5b63b3e7f 100644 --- a/src/html_support_files/odoc.css +++ b/src/html_support_files/odoc.css @@ -340,7 +340,14 @@ nav.odoc-nav:has(+ .odoc-search:focus-within) { } body.odoc-src { - margin-right: calc(10vw + 20ex); + display: grid; + grid-template-columns: min-content 1fr; + grid-template-areas: + "search-bar nav " + "toc-global preamble" + "toc-global content "; + column-gap: 4ex; + grid-template-rows: auto auto 1fr; } .odoc-content { @@ -1362,6 +1369,7 @@ body.odoc:has( .odoc-search) .odoc-toc { .source_container { display: flex; + grid-area: content; } .source_line_column { diff --git a/src/odoc/bin/main.ml b/src/odoc/bin/main.ml index 7c5239b694..10e612d056 100644 --- a/src/odoc/bin/main.ml +++ b/src/odoc/bin/main.ml @@ -849,7 +849,7 @@ end = struct Arg.( value & opt (some convert_fpath) None - & info [ "sidebar" ] ~doc ~docv:"FILE.odoc-index") + & info [ "sidebar" ] ~doc ~docv:"FILE.odoc-sidebar") let cmd = let syntax = @@ -876,9 +876,10 @@ end = struct module Generate_source = struct let generate extra output_dir syntax extra_suffix input_file - warnings_options source_file = + warnings_options source_file sidebar = Rendering.generate_source_odoc ~renderer:R.renderer ~warnings_options - ~syntax ~output:output_dir ~extra_suffix ~source_file extra input_file + ~syntax ~output:output_dir ~extra_suffix ~source_file ~sidebar extra + input_file let input_odocl = let doc = "Linked implementation file." in @@ -903,10 +904,12 @@ end = struct & opt (pconv convert_syntax) Odoc_document.Renderer.OCaml @@ info ~docv:"SYNTAX" ~doc ~env [ "syntax" ]) in + let sidebar = Generate.sidebar in Term.( const handle_error $ (const generate $ R.extra_args $ dst ~create:true () $ syntax - $ extra_suffix $ input_odocl $ warnings_options $ source_file)) + $ extra_suffix $ input_odocl $ warnings_options $ source_file $ sidebar + )) let info ~docs = let doc = diff --git a/src/odoc/rendering.ml b/src/odoc/rendering.ml index a1652f8d76..bda6a47188 100644 --- a/src/odoc/rendering.ml +++ b/src/odoc/rendering.ml @@ -93,14 +93,18 @@ let documents_of_implementation ~warnings_options:_ ~syntax impl source_file = Error (`Msg "The implementation unit was not compiled with --source-id.") let generate_source_odoc ~syntax ~warnings_options ~renderer ~output - ~source_file ~extra_suffix extra file = + ~source_file ~extra_suffix ~sidebar extra file = Odoc_file.load file >>= fun unit -> + (match sidebar with + | None -> Ok None + | Some x -> Odoc_file.load_sidebar x >>= fun sidebar -> Ok (Some sidebar)) + >>= fun sidebar -> match unit.content with | Odoc_file.Impl_content impl -> documents_of_implementation ~warnings_options ~syntax impl source_file >>= fun docs -> List.iter - (render_document renderer ~output ~sidebar:None ~extra_suffix ~extra) + (render_document renderer ~output ~sidebar ~extra_suffix ~extra) docs; Ok () | Page_content _ | Unit_content _ | Asset_content _ -> diff --git a/src/odoc/rendering.mli b/src/odoc/rendering.mli index 1d274d3c76..69c7baa704 100644 --- a/src/odoc/rendering.mli +++ b/src/odoc/rendering.mli @@ -29,6 +29,7 @@ val generate_source_odoc : output:Fs.directory -> source_file:Fpath.t -> extra_suffix:string option -> + sidebar:Fpath.t option -> 'a -> Fpath.t -> (unit, [> msg ]) result