]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/layout.rs
Auto merge of #85640 - bjorn3:custom_ice_hook, r=jackh726
[rust.git] / src / librustdoc / html / layout.rs
1 use std::path::PathBuf;
2
3 use rustc_data_structures::fx::FxHashMap;
4
5 use crate::externalfiles::ExternalHtml;
6 use crate::html::escape::Escape;
7 use crate::html::format::{Buffer, Print};
8 use crate::html::render::{ensure_trailing_slash, StylePath};
9
10 use serde::Serialize;
11
12 #[derive(Clone, Serialize)]
13 crate struct Layout {
14     crate logo: String,
15     crate favicon: String,
16     crate external_html: ExternalHtml,
17     crate default_settings: FxHashMap<String, String>,
18     crate krate: String,
19     /// The given user css file which allow to customize the generated
20     /// documentation theme.
21     crate css_file_extension: Option<PathBuf>,
22     /// If false, the `select` element to have search filtering by crates on rendered docs
23     /// won't be generated.
24     crate generate_search_filter: bool,
25 }
26
27 #[derive(Serialize)]
28 crate struct Page<'a> {
29     crate title: &'a str,
30     crate css_class: &'a str,
31     crate root_path: &'a str,
32     crate static_root_path: Option<&'a str>,
33     crate description: &'a str,
34     crate keywords: &'a str,
35     crate resource_suffix: &'a str,
36     crate extra_scripts: &'a [&'a str],
37     crate static_extra_scripts: &'a [&'a str],
38 }
39
40 impl<'a> Page<'a> {
41     crate fn get_static_root_path(&self) -> &str {
42         self.static_root_path.unwrap_or(self.root_path)
43     }
44 }
45
46 #[derive(Serialize)]
47 struct PageLayout<'a> {
48     static_root_path: &'a str,
49     page: &'a Page<'a>,
50     layout: &'a Layout,
51     style_files: String,
52     sidebar: String,
53     content: String,
54     krate_with_trailing_slash: String,
55 }
56
57 crate fn render<T: Print, S: Print>(
58     templates: &tera::Tera,
59     layout: &Layout,
60     page: &Page<'_>,
61     sidebar: S,
62     t: T,
63     style_files: &[StylePath],
64 ) -> String {
65     let static_root_path = page.get_static_root_path();
66     let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
67     let style_files = style_files
68         .iter()
69         .filter_map(|t| {
70             if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
71         })
72         .filter_map(|t| if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None })
73         .map(|t| {
74             format!(
75                 r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
76                 Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
77                 if t.1 { "disabled" } else { "" },
78                 if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
79             )
80         })
81         .collect::<String>();
82     let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
83     let sidebar = Buffer::html().to_display(sidebar);
84     let teractx = tera::Context::from_serialize(PageLayout {
85         static_root_path,
86         page,
87         layout,
88         style_files,
89         sidebar,
90         content,
91         krate_with_trailing_slash,
92     })
93     .unwrap();
94     templates.render("page.html", &teractx).unwrap()
95 }
96
97 crate fn redirect(url: &str) -> String {
98     // <script> triggers a redirect before refresh, so this is fine.
99     format!(
100         r##"<!DOCTYPE html>
101 <html lang="en">
102 <head>
103     <meta http-equiv="refresh" content="0;URL={url}">
104     <title>Redirection</title>
105 </head>
106 <body>
107     <p>Redirecting to <a href="{url}">{url}</a>...</p>
108     <script>location.replace("{url}" + location.search + location.hash);</script>
109 </body>
110 </html>"##,
111         url = url,
112     )
113 }