1 use std::path::PathBuf;
2
3 use rustc_data_structures::fx::FxHashMap;
4
5 use crate::externalfiles::ExternalHtml;
6 use crate::html::format::{Buffer, Print};
7 use crate::html::render::{ensure_trailing_slash, StylePath};
8
9 use askama::Template;
10
11 use super::static_files::{StaticFiles, STATIC_FILES};
12
13 #[derive(Clone)]
14 pub(crate) struct Layout {
15 pub(crate) logo: String,
16 pub(crate) favicon: String,
17 pub(crate) external_html: ExternalHtml,
18 pub(crate) default_settings: FxHashMap<String, String>,
19 pub(crate) krate: String,
20 /// The given user css file which allow to customize the generated
21 /// documentation theme.
22 pub(crate) css_file_extension: Option<PathBuf>,
23 /// If true, then scrape-examples.js will be included in the output HTML file
24 pub(crate) scrape_examples_extension: bool,
25 }
26
27 pub(crate) struct Page<'a> {
28 pub(crate) title: &'a str,
29 pub(crate) css_class: &'a str,
30 pub(crate) root_path: &'a str,
31 pub(crate) static_root_path: Option<&'a str>,
32 pub(crate) description: &'a str,
33 pub(crate) resource_suffix: &'a str,
34 }
35
36 impl<'a> Page<'a> {
get_static_root_path(&self) -> String37 pub(crate) fn get_static_root_path(&self) -> String {
38 match self.static_root_path {
39 Some(s) => s.to_string(),
40 None => format!("{}static.files/", self.root_path),
41 }
42 }
43 }
44
45 #[derive(Template)]
46 #[template(path = "page.html")]
47 struct PageLayout<'a> {
48 static_root_path: String,
49 page: &'a Page<'a>,
50 layout: &'a Layout,
51
52 files: &'static StaticFiles,
53
54 themes: Vec<String>,
55 sidebar: String,
56 content: String,
57 krate_with_trailing_slash: String,
58 rust_channel: &'static str,
59 pub(crate) rustdoc_version: &'a str,
60 }
61
render<T: Print, S: Print>( layout: &Layout, page: &Page<'_>, sidebar: S, t: T, style_files: &[StylePath], ) -> String62 pub(crate) fn render<T: Print, S: Print>(
63 layout: &Layout,
64 page: &Page<'_>,
65 sidebar: S,
66 t: T,
67 style_files: &[StylePath],
68 ) -> String {
69 let static_root_path = page.get_static_root_path();
70 let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
71 let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect();
72 themes.sort();
73
74 let rustdoc_version = rustc_interface::util::version_str!().unwrap_or("unknown version");
75 let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
76 let sidebar = Buffer::html().to_display(sidebar);
77 PageLayout {
78 static_root_path,
79 page,
80 layout,
81 files: &STATIC_FILES,
82 themes,
83 sidebar,
84 content,
85 krate_with_trailing_slash,
86 rust_channel: *crate::clean::utils::DOC_CHANNEL,
87 rustdoc_version,
88 }
89 .render()
90 .unwrap()
91 }
92
redirect(url: &str) -> String93 pub(crate) fn redirect(url: &str) -> String {
94 // <script> triggers a redirect before refresh, so this is fine.
95 format!(
96 r##"<!DOCTYPE html>
97 <html lang="en">
98 <head>
99 <meta http-equiv="refresh" content="0;URL={url}">
100 <title>Redirection</title>
101 </head>
102 <body>
103 <p>Redirecting to <a href="{url}">{url}</a>...</p>
104 <script>location.replace("{url}" + location.search + location.hash);</script>
105 </body>
106 </html>"##,
107 url = url,
108 )
109 }
110