]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/static_files.rs
Rollup merge of #104349 - rustaceanclub:master, r=oli-obk
[rust.git] / src / librustdoc / html / static_files.rs
1 //! Static files bundled with documentation output.
2 //!
3 //! All the static files are included here for centralized access in case anything other than the
4 //! HTML rendering code (say, the theme checker) needs to access one of these files.
5
6 use rustc_data_structures::fx::FxHasher;
7 use std::hash::Hasher;
8 use std::path::{Path, PathBuf};
9 use std::{fmt, str};
10
11 pub(crate) struct StaticFile {
12     pub(crate) filename: PathBuf,
13     pub(crate) bytes: &'static [u8],
14 }
15
16 impl StaticFile {
17     fn new(filename: &str, bytes: &'static [u8]) -> StaticFile {
18         Self { filename: static_filename(filename, bytes), bytes }
19     }
20
21     pub(crate) fn minified(&self) -> Vec<u8> {
22         if self.filename.ends_with(".css") {
23             minifier::css::minify(str::from_utf8(self.bytes).unwrap()).unwrap().to_string().into()
24         } else if self.filename.ends_with(".js") {
25             minifier::js::minify(str::from_utf8(self.bytes).unwrap()).to_string().into()
26         } else {
27             self.bytes.to_owned()
28         }
29     }
30
31     pub(crate) fn output_filename(&self) -> &Path {
32         &self.filename
33     }
34 }
35
36 /// The Display implementation for a StaticFile outputs its filename. This makes it
37 /// convenient to interpolate static files into HTML templates.
38 impl fmt::Display for StaticFile {
39     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40         write!(f, "{}", self.output_filename().display())
41     }
42 }
43
44 /// Insert the provided suffix into a filename just before the extension.
45 pub(crate) fn suffix_path(filename: &str, suffix: &str) -> PathBuf {
46     // We use splitn vs Path::extension here because we might get a filename
47     // like `style.min.css` and we want to process that into
48     // `style-suffix.min.css`.  Path::extension would just return `css`
49     // which would result in `style.min-suffix.css` which isn't what we
50     // want.
51     let (base, ext) = filename.split_once('.').unwrap();
52     let filename = format!("{}{}.{}", base, suffix, ext);
53     filename.into()
54 }
55
56 pub(crate) fn static_filename(filename: &str, contents: &[u8]) -> PathBuf {
57     let filename = filename.rsplit("/").next().unwrap();
58     suffix_path(filename, &static_suffix(contents))
59 }
60
61 fn static_suffix(bytes: &[u8]) -> String {
62     let mut hasher = FxHasher::default();
63     hasher.write(bytes);
64     format!("-{:016x}", hasher.finish())
65 }
66
67 macro_rules! static_files {
68     ($($field:ident => $file_path:literal,)+) => {
69         pub(crate) struct StaticFiles {
70             $(pub $field: StaticFile,)+
71         }
72
73         pub(crate) static STATIC_FILES: std::sync::LazyLock<StaticFiles> = std::sync::LazyLock::new(|| StaticFiles {
74             $($field: StaticFile::new($file_path, include_bytes!($file_path)),)+
75         });
76
77         pub(crate) fn for_each<E>(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<(), E> {
78             for sf in [
79             $(&STATIC_FILES.$field,)+
80             ] {
81                 f(sf)?
82             }
83             Ok(())
84         }
85     }
86 }
87
88 static_files! {
89     rustdoc_css => "static/css/rustdoc.css",
90     settings_css => "static/css/settings.css",
91     noscript_css => "static/css/noscript.css",
92     normalize_css => "static/css/normalize.css",
93     main_js => "static/js/main.js",
94     search_js => "static/js/search.js",
95     settings_js => "static/js/settings.js",
96     source_script_js => "static/js/source-script.js",
97     storage_js => "static/js/storage.js",
98     scrape_examples_js => "static/js/scrape-examples.js",
99     wheel_svg => "static/images/wheel.svg",
100     clipboard_svg => "static/images/clipboard.svg",
101     down_arrow_svg => "static/images/down-arrow.svg",
102     toggle_minus_png => "static/images/toggle-minus.svg",
103     toggle_plus_png => "static/images/toggle-plus.svg",
104     copyright => "static/COPYRIGHT.txt",
105     license_apache => "static/LICENSE-APACHE.txt",
106     license_mit => "static/LICENSE-MIT.txt",
107     rust_logo_svg => "static/images/rust-logo.svg",
108     rust_favicon_svg => "static/images/favicon.svg",
109     rust_favicon_png_16 => "static/images/favicon-16x16.png",
110     rust_favicon_png_32 => "static/images/favicon-32x32.png",
111     theme_light_css => "static/css/themes/light.css",
112     theme_dark_css => "static/css/themes/dark.css",
113     theme_ayu_css => "static/css/themes/ayu.css",
114     fira_sans_regular => "static/fonts/FiraSans-Regular.woff2",
115     fira_sans_medium => "static/fonts/FiraSans-Medium.woff2",
116     fira_sans_license => "static/fonts/FiraSans-LICENSE.txt",
117     source_serif_4_regular => "static/fonts/SourceSerif4-Regular.ttf.woff2",
118     source_serif_4_bold => "static/fonts/SourceSerif4-Bold.ttf.woff2",
119     source_serif_4_italic => "static/fonts/SourceSerif4-It.ttf.woff2",
120     source_serif_4_license => "static/fonts/SourceSerif4-LICENSE.md",
121     source_code_pro_regular => "static/fonts/SourceCodePro-Regular.ttf.woff2",
122     source_code_pro_semibold => "static/fonts/SourceCodePro-Semibold.ttf.woff2",
123     source_code_pro_italic => "static/fonts/SourceCodePro-It.ttf.woff2",
124     source_code_pro_license => "static/fonts/SourceCodePro-LICENSE.txt",
125     nanum_barun_gothic_regular => "static/fonts/NanumBarunGothic.ttf.woff2",
126     nanum_barun_gothic_license => "static/fonts/NanumBarunGothic-LICENSE.txt",
127 }
128
129 pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/js/scrape-examples.js");