rustdoc: add hash to filename of toolchain files
All static files used by rustdoc are now stored in static.files/ and include a hash of their contents. They no longer include the contents of the --resource-suffix flag. This clarifies caching semantics. Anything in static.files can use Cache-Control: immutable because any updates will show up as a new URL. Invocation-specific files like crates-NN.js, search-index-NN.js, and sidebar-items-NN.js still get the resource suffix. The --disable-minification flag is removed because it would vary the output of static files based on invocation flags. Instead, for rustdoc development purposes it's preferable to symlink static files to a non-minified copy for quick iteration.
This commit is contained in:
parent
68c836a904
commit
f9e1f6ffdf
18 changed files with 267 additions and 509 deletions
|
@ -239,9 +239,6 @@ pub(crate) struct RenderOptions {
|
||||||
pub(crate) default_settings: FxHashMap<String, String>,
|
pub(crate) default_settings: FxHashMap<String, String>,
|
||||||
/// If present, suffix added to CSS/JavaScript files when referencing them in generated pages.
|
/// If present, suffix added to CSS/JavaScript files when referencing them in generated pages.
|
||||||
pub(crate) resource_suffix: String,
|
pub(crate) resource_suffix: String,
|
||||||
/// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by
|
|
||||||
/// default.
|
|
||||||
pub(crate) enable_minification: bool,
|
|
||||||
/// Whether to create an index page in the root of the output directory. If this is true but
|
/// Whether to create an index page in the root of the output directory. If this is true but
|
||||||
/// `enable_index_page` is None, generate a static listing of crates instead.
|
/// `enable_index_page` is None, generate a static listing of crates instead.
|
||||||
pub(crate) enable_index_page: bool,
|
pub(crate) enable_index_page: bool,
|
||||||
|
@ -416,7 +413,9 @@ impl Options {
|
||||||
|
|
||||||
let to_check = matches.opt_strs("check-theme");
|
let to_check = matches.opt_strs("check-theme");
|
||||||
if !to_check.is_empty() {
|
if !to_check.is_empty() {
|
||||||
let paths = match theme::load_css_paths(static_files::themes::LIGHT) {
|
let paths = match theme::load_css_paths(
|
||||||
|
std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(),
|
||||||
|
) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
diag.struct_err(&e.to_string()).emit();
|
diag.struct_err(&e.to_string()).emit();
|
||||||
|
@ -557,7 +556,9 @@ impl Options {
|
||||||
|
|
||||||
let mut themes = Vec::new();
|
let mut themes = Vec::new();
|
||||||
if matches.opt_present("theme") {
|
if matches.opt_present("theme") {
|
||||||
let paths = match theme::load_css_paths(static_files::themes::LIGHT) {
|
let paths = match theme::load_css_paths(
|
||||||
|
std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(),
|
||||||
|
) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
diag.struct_err(&e.to_string()).emit();
|
diag.struct_err(&e.to_string()).emit();
|
||||||
|
@ -675,7 +676,6 @@ impl Options {
|
||||||
ModuleSorting::Alphabetical
|
ModuleSorting::Alphabetical
|
||||||
};
|
};
|
||||||
let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
|
let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
|
||||||
let enable_minification = !matches.opt_present("disable-minification");
|
|
||||||
let markdown_no_toc = matches.opt_present("markdown-no-toc");
|
let markdown_no_toc = matches.opt_present("markdown-no-toc");
|
||||||
let markdown_css = matches.opt_strs("markdown-css");
|
let markdown_css = matches.opt_strs("markdown-css");
|
||||||
let markdown_playground_url = matches.opt_str("markdown-playground-url");
|
let markdown_playground_url = matches.opt_str("markdown-playground-url");
|
||||||
|
@ -768,7 +768,6 @@ impl Options {
|
||||||
extern_html_root_takes_precedence,
|
extern_html_root_takes_precedence,
|
||||||
default_settings,
|
default_settings,
|
||||||
resource_suffix,
|
resource_suffix,
|
||||||
enable_minification,
|
|
||||||
enable_index_page,
|
enable_index_page,
|
||||||
index_page,
|
index_page,
|
||||||
static_root_path,
|
static_root_path,
|
||||||
|
|
|
@ -2,13 +2,14 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
|
||||||
use crate::error::Error;
|
|
||||||
use crate::externalfiles::ExternalHtml;
|
use crate::externalfiles::ExternalHtml;
|
||||||
use crate::html::format::{Buffer, Print};
|
use crate::html::format::{Buffer, Print};
|
||||||
use crate::html::render::{ensure_trailing_slash, StylePath};
|
use crate::html::render::{ensure_trailing_slash, StylePath};
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
|
||||||
|
use super::static_files::{StaticFiles, STATIC_FILES};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Layout {
|
pub(crate) struct Layout {
|
||||||
pub(crate) logo: String,
|
pub(crate) logo: String,
|
||||||
|
@ -45,6 +46,9 @@ struct PageLayout<'a> {
|
||||||
static_root_path: &'a str,
|
static_root_path: &'a str,
|
||||||
page: &'a Page<'a>,
|
page: &'a Page<'a>,
|
||||||
layout: &'a Layout,
|
layout: &'a Layout,
|
||||||
|
|
||||||
|
files: &'static StaticFiles,
|
||||||
|
|
||||||
themes: Vec<String>,
|
themes: Vec<String>,
|
||||||
sidebar: String,
|
sidebar: String,
|
||||||
content: String,
|
content: String,
|
||||||
|
@ -61,12 +65,9 @@ pub(crate) fn render<T: Print, S: Print>(
|
||||||
) -> String {
|
) -> String {
|
||||||
let static_root_path = page.get_static_root_path();
|
let static_root_path = page.get_static_root_path();
|
||||||
let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
|
let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
|
||||||
let mut themes: Vec<String> = style_files
|
let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect();
|
||||||
.iter()
|
|
||||||
.map(StylePath::basename)
|
|
||||||
.collect::<Result<_, Error>>()
|
|
||||||
.unwrap_or_default();
|
|
||||||
themes.sort();
|
themes.sort();
|
||||||
|
|
||||||
let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
|
let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
|
||||||
let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
|
let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
|
||||||
let sidebar = Buffer::html().to_display(sidebar);
|
let sidebar = Buffer::html().to_display(sidebar);
|
||||||
|
@ -74,6 +75,7 @@ pub(crate) fn render<T: Print, S: Print>(
|
||||||
static_root_path,
|
static_root_path,
|
||||||
page,
|
page,
|
||||||
layout,
|
layout,
|
||||||
|
files: &STATIC_FILES,
|
||||||
themes,
|
themes,
|
||||||
sidebar,
|
sidebar,
|
||||||
content,
|
content,
|
||||||
|
|
|
@ -32,7 +32,7 @@ use crate::html::escape::Escape;
|
||||||
use crate::html::format::{join_with_double_colon, Buffer};
|
use crate::html::format::{join_with_double_colon, Buffer};
|
||||||
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
|
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
|
||||||
use crate::html::url_parts_builder::UrlPartsBuilder;
|
use crate::html::url_parts_builder::UrlPartsBuilder;
|
||||||
use crate::html::{layout, sources};
|
use crate::html::{layout, sources, static_files};
|
||||||
use crate::scrape_examples::AllCallLocations;
|
use crate::scrape_examples::AllCallLocations;
|
||||||
use crate::try_err;
|
use crate::try_err;
|
||||||
|
|
||||||
|
@ -498,7 +498,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let (sender, receiver) = channel();
|
let (sender, receiver) = channel();
|
||||||
let mut scx = SharedContext {
|
let scx = SharedContext {
|
||||||
tcx,
|
tcx,
|
||||||
src_root,
|
src_root,
|
||||||
local_sources,
|
local_sources,
|
||||||
|
@ -521,19 +521,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||||
call_locations,
|
call_locations,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add the default themes to the `Vec` of stylepaths
|
|
||||||
//
|
|
||||||
// Note that these must be added before `sources::render` is called
|
|
||||||
// so that the resulting source pages are styled
|
|
||||||
//
|
|
||||||
// `light.css` is not disabled because it is the stylesheet that stays loaded
|
|
||||||
// by the browser as the theme stylesheet. The theme system (hackily) works by
|
|
||||||
// changing the href to this stylesheet. All other themes are disabled to
|
|
||||||
// prevent rule conflicts
|
|
||||||
scx.style_files.push(StylePath { path: PathBuf::from("light.css") });
|
|
||||||
scx.style_files.push(StylePath { path: PathBuf::from("dark.css") });
|
|
||||||
scx.style_files.push(StylePath { path: PathBuf::from("ayu.css") });
|
|
||||||
|
|
||||||
let dst = output;
|
let dst = output;
|
||||||
scx.ensure_dir(&dst)?;
|
scx.ensure_dir(&dst)?;
|
||||||
|
|
||||||
|
@ -647,10 +634,11 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||||
</section>\
|
</section>\
|
||||||
</noscript>\
|
</noscript>\
|
||||||
<link rel=\"stylesheet\" type=\"text/css\" \
|
<link rel=\"stylesheet\" type=\"text/css\" \
|
||||||
href=\"{root_path}settings{suffix}.css\">\
|
href=\"{static_root_path}{settings_css}\">\
|
||||||
<script defer src=\"{root_path}settings{suffix}.js\"></script>",
|
<script defer src=\"{static_root_path}{settings_js}\"></script>",
|
||||||
root_path = page.static_root_path.unwrap_or(""),
|
static_root_path = page.static_root_path.unwrap_or(""),
|
||||||
suffix = page.resource_suffix,
|
settings_css = static_files::STATIC_FILES.settings_css,
|
||||||
|
settings_js = static_files::STATIC_FILES.settings_js,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
&shared.style_files,
|
&shared.style_files,
|
||||||
|
|
|
@ -30,10 +30,10 @@ use crate::html::format::{
|
||||||
join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause,
|
join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause,
|
||||||
Buffer, Ending, PrintWithSpace,
|
Buffer, Ending, PrintWithSpace,
|
||||||
};
|
};
|
||||||
use crate::html::highlight;
|
|
||||||
use crate::html::layout::Page;
|
use crate::html::layout::Page;
|
||||||
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
|
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
|
||||||
use crate::html::url_parts_builder::UrlPartsBuilder;
|
use crate::html::url_parts_builder::UrlPartsBuilder;
|
||||||
|
use crate::html::{highlight, static_files};
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -52,8 +52,8 @@ struct PathComponent {
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "print_item.html")]
|
#[template(path = "print_item.html")]
|
||||||
struct ItemVars<'a> {
|
struct ItemVars<'a> {
|
||||||
page: &'a Page<'a>,
|
|
||||||
static_root_path: &'a str,
|
static_root_path: &'a str,
|
||||||
|
clipboard_svg: &'static static_files::StaticFile,
|
||||||
typ: &'a str,
|
typ: &'a str,
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
item_type: &'a str,
|
item_type: &'a str,
|
||||||
|
@ -147,8 +147,8 @@ pub(super) fn print_item(
|
||||||
};
|
};
|
||||||
|
|
||||||
let item_vars = ItemVars {
|
let item_vars = ItemVars {
|
||||||
page,
|
|
||||||
static_root_path: page.get_static_root_path(),
|
static_root_path: page.get_static_root_path(),
|
||||||
|
clipboard_svg: &static_files::STATIC_FILES.clipboard_svg,
|
||||||
typ,
|
typ,
|
||||||
name: item.name.as_ref().unwrap().as_str(),
|
name: item.name.as_ref().unwrap().as_str(),
|
||||||
item_type: &item.type_().to_string(),
|
item_type: &item.type_().to_string(),
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::{self, BufReader};
|
use std::io::{self, BufReader};
|
||||||
use std::path::{Component, Path, PathBuf};
|
use std::path::{Component, Path};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::LazyLock as Lazy;
|
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_data_structures::flock;
|
use rustc_data_structures::flock;
|
||||||
|
@ -20,123 +18,19 @@ use crate::error::Error;
|
||||||
use crate::html::{layout, static_files};
|
use crate::html::{layout, static_files};
|
||||||
use crate::{try_err, try_none};
|
use crate::{try_err, try_none};
|
||||||
|
|
||||||
static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
|
/// Rustdoc writes out two kinds of shared files:
|
||||||
map! {
|
/// - Static files, which are embedded in the rustdoc binary and are written with a
|
||||||
"FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR,
|
/// filename that includes a hash of their contents. These will always have a new
|
||||||
"FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM,
|
/// URL if the contents change, so they are safe to cache with the
|
||||||
"FiraSans-LICENSE.txt" => static_files::fira_sans::LICENSE,
|
/// `Cache-Control: immutable` directive. They are written under the static.files/
|
||||||
"SourceSerif4-Regular.ttf.woff2" => static_files::source_serif_4::REGULAR,
|
/// directory and are written when --emit-type is empty (default) or contains
|
||||||
"SourceSerif4-Bold.ttf.woff2" => static_files::source_serif_4::BOLD,
|
/// "toolchain-specific".
|
||||||
"SourceSerif4-It.ttf.woff2" => static_files::source_serif_4::ITALIC,
|
/// - Invocation specific files. These are generated based on the crate(s) being
|
||||||
"SourceSerif4-LICENSE.md" => static_files::source_serif_4::LICENSE,
|
/// documented. Their filenames need to be predictable without knowing their
|
||||||
"SourceCodePro-Regular.ttf.woff2" => static_files::source_code_pro::REGULAR,
|
/// contents, so they do not include a hash in their filename and are not safe to
|
||||||
"SourceCodePro-Semibold.ttf.woff2" => static_files::source_code_pro::SEMIBOLD,
|
/// cache with `Cache-Control: immutable`. They include the contents of the
|
||||||
"SourceCodePro-It.ttf.woff2" => static_files::source_code_pro::ITALIC,
|
/// --resource-suffix flag and are emitted when --emit-type is empty (default)
|
||||||
"SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
|
/// or contains "invocation-specific".
|
||||||
"NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR,
|
|
||||||
"NanumBarunGothic-LICENSE.txt" => static_files::nanum_barun_gothic::LICENSE,
|
|
||||||
"LICENSE-MIT.txt" => static_files::LICENSE_MIT,
|
|
||||||
"LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
|
|
||||||
"COPYRIGHT.txt" => static_files::COPYRIGHT,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
enum SharedResource<'a> {
|
|
||||||
/// This file will never change, no matter what toolchain is used to build it.
|
|
||||||
///
|
|
||||||
/// It does not have a resource suffix.
|
|
||||||
Unversioned { name: &'static str },
|
|
||||||
/// This file may change depending on the toolchain.
|
|
||||||
///
|
|
||||||
/// It has a resource suffix.
|
|
||||||
ToolchainSpecific { basename: &'static str },
|
|
||||||
/// This file may change for any crate within a build, or based on the CLI arguments.
|
|
||||||
///
|
|
||||||
/// This differs from normal invocation-specific files because it has a resource suffix.
|
|
||||||
InvocationSpecific { basename: &'a str },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SharedResource<'_> {
|
|
||||||
fn extension(&self) -> Option<&OsStr> {
|
|
||||||
use SharedResource::*;
|
|
||||||
match self {
|
|
||||||
Unversioned { name }
|
|
||||||
| ToolchainSpecific { basename: name }
|
|
||||||
| InvocationSpecific { basename: name } => Path::new(name).extension(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path(&self, cx: &Context<'_>) -> PathBuf {
|
|
||||||
match self {
|
|
||||||
SharedResource::Unversioned { name } => cx.dst.join(name),
|
|
||||||
SharedResource::ToolchainSpecific { basename } => cx.suffix_path(basename),
|
|
||||||
SharedResource::InvocationSpecific { basename } => cx.suffix_path(basename),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn should_emit(&self, emit: &[EmitType]) -> bool {
|
|
||||||
if emit.is_empty() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
let kind = match self {
|
|
||||||
SharedResource::Unversioned { .. } => EmitType::Unversioned,
|
|
||||||
SharedResource::ToolchainSpecific { .. } => EmitType::Toolchain,
|
|
||||||
SharedResource::InvocationSpecific { .. } => EmitType::InvocationSpecific,
|
|
||||||
};
|
|
||||||
emit.contains(&kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Context<'_> {
|
|
||||||
fn suffix_path(&self, filename: &str) -> PathBuf {
|
|
||||||
// We use splitn vs Path::extension here because we might get a filename
|
|
||||||
// like `style.min.css` and we want to process that into
|
|
||||||
// `style-suffix.min.css`. Path::extension would just return `css`
|
|
||||||
// which would result in `style.min-suffix.css` which isn't what we
|
|
||||||
// want.
|
|
||||||
let (base, ext) = filename.split_once('.').unwrap();
|
|
||||||
let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext);
|
|
||||||
self.dst.join(&filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_shared(
|
|
||||||
&self,
|
|
||||||
resource: SharedResource<'_>,
|
|
||||||
contents: impl 'static + Send + AsRef<[u8]>,
|
|
||||||
emit: &[EmitType],
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
if resource.should_emit(emit) {
|
|
||||||
self.shared.fs.write(resource.path(self), contents)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_minify(
|
|
||||||
&self,
|
|
||||||
resource: SharedResource<'_>,
|
|
||||||
contents: impl 'static + Send + AsRef<str> + AsRef<[u8]>,
|
|
||||||
minify: bool,
|
|
||||||
emit: &[EmitType],
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
if minify {
|
|
||||||
let contents = contents.as_ref();
|
|
||||||
let contents = if resource.extension() == Some(OsStr::new("css")) {
|
|
||||||
minifier::css::minify(contents)
|
|
||||||
.map_err(|e| {
|
|
||||||
Error::new(format!("failed to minify CSS file: {}", e), resource.path(self))
|
|
||||||
})?
|
|
||||||
.to_string()
|
|
||||||
} else {
|
|
||||||
minifier::js::minify(contents).to_string()
|
|
||||||
};
|
|
||||||
self.write_shared(resource, contents, emit)
|
|
||||||
} else {
|
|
||||||
self.write_shared(resource, contents, emit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn write_shared(
|
pub(super) fn write_shared(
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
krate: &Crate,
|
krate: &Crate,
|
||||||
|
@ -149,139 +43,51 @@ pub(super) fn write_shared(
|
||||||
let lock_file = cx.dst.join(".lock");
|
let lock_file = cx.dst.join(".lock");
|
||||||
let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file);
|
let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file);
|
||||||
|
|
||||||
// Minified resources are usually toolchain resources. If they're not, they should use `cx.write_minify` directly.
|
// InvocationSpecific resources should always be dynamic.
|
||||||
fn write_minify(
|
let write_invocation_specific = |p: &str, make_content: &dyn Fn() -> Result<Vec<u8>, Error>| {
|
||||||
basename: &'static str,
|
|
||||||
contents: impl 'static + Send + AsRef<str> + AsRef<[u8]>,
|
|
||||||
cx: &Context<'_>,
|
|
||||||
options: &RenderOptions,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
cx.write_minify(
|
|
||||||
SharedResource::ToolchainSpecific { basename },
|
|
||||||
contents,
|
|
||||||
options.enable_minification,
|
|
||||||
&options.emit,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toolchain resources should never be dynamic.
|
|
||||||
let write_toolchain = |p: &'static _, c: &'static _| {
|
|
||||||
cx.write_shared(SharedResource::ToolchainSpecific { basename: p }, c, &options.emit)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Crate resources should always be dynamic.
|
|
||||||
let write_crate = |p: &_, make_content: &dyn Fn() -> Result<Vec<u8>, Error>| {
|
|
||||||
let content = make_content()?;
|
let content = make_content()?;
|
||||||
cx.write_shared(SharedResource::InvocationSpecific { basename: p }, content, &options.emit)
|
if options.emit.is_empty() || options.emit.contains(&EmitType::InvocationSpecific) {
|
||||||
|
let output_filename = static_files::suffix_path(p, &cx.shared.resource_suffix);
|
||||||
|
cx.shared.fs.write(cx.dst.join(output_filename), content)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Given "foo.svg", return e.g. "url(\"foo1.58.0.svg\")"
|
cx.shared
|
||||||
fn ver_url(cx: &Context<'_>, basename: &'static str) -> String {
|
.fs
|
||||||
format!(
|
.create_dir_all(cx.dst.join("static.files"))
|
||||||
"url(\"{}\")",
|
.map_err(|e| PathError::new(e, "static.files"))?;
|
||||||
SharedResource::ToolchainSpecific { basename }
|
|
||||||
.path(cx)
|
|
||||||
.file_name()
|
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use the AUTOREPLACE mechanism to inject into our static JS and CSS certain
|
|
||||||
// values that are only known at doc build time. Since this mechanism is somewhat
|
|
||||||
// surprising when reading the code, please limit it to rustdoc.css.
|
|
||||||
write_minify(
|
|
||||||
"rustdoc.css",
|
|
||||||
static_files::RUSTDOC_CSS
|
|
||||||
.replace(
|
|
||||||
"/* AUTOREPLACE: */url(\"toggle-minus.svg\")",
|
|
||||||
&ver_url(cx, "toggle-minus.svg"),
|
|
||||||
)
|
|
||||||
.replace("/* AUTOREPLACE: */url(\"toggle-plus.svg\")", &ver_url(cx, "toggle-plus.svg"))
|
|
||||||
.replace("/* AUTOREPLACE: */url(\"down-arrow.svg\")", &ver_url(cx, "down-arrow.svg")),
|
|
||||||
cx,
|
|
||||||
options,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Add all the static files. These may already exist, but we just
|
|
||||||
// overwrite them anyway to make sure that they're fresh and up-to-date.
|
|
||||||
write_minify("settings.css", static_files::SETTINGS_CSS, cx, options)?;
|
|
||||||
write_minify("noscript.css", static_files::NOSCRIPT_CSS, cx, options)?;
|
|
||||||
|
|
||||||
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only
|
|
||||||
// then we'll run over the "official" styles.
|
|
||||||
let mut themes: FxHashSet<String> = FxHashSet::default();
|
|
||||||
|
|
||||||
|
// Handle added third-party themes
|
||||||
for entry in &cx.shared.style_files {
|
for entry in &cx.shared.style_files {
|
||||||
let theme = entry.basename()?;
|
let theme = entry.basename()?;
|
||||||
let extension =
|
let extension =
|
||||||
try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
|
try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
|
||||||
|
|
||||||
// Handle the official themes
|
// Skip the official themes. They are written below as part of STATIC_FILES_LIST.
|
||||||
match theme.as_str() {
|
if matches!(theme.as_str(), "light" | "dark" | "ayu") {
|
||||||
"light" => write_minify("light.css", static_files::themes::LIGHT, cx, options)?,
|
continue;
|
||||||
"dark" => write_minify("dark.css", static_files::themes::DARK, cx, options)?,
|
}
|
||||||
"ayu" => write_minify("ayu.css", static_files::themes::AYU, cx, options)?,
|
|
||||||
_ => {
|
|
||||||
// Handle added third-party themes
|
|
||||||
let filename = format!("{}.{}", theme, extension);
|
|
||||||
write_crate(&filename, &|| Ok(try_err!(fs::read(&entry.path), &entry.path)))?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
themes.insert(theme.to_owned());
|
let bytes = try_err!(fs::read(&entry.path), &entry.path);
|
||||||
}
|
let filename = format!("{}{}.{}", theme, cx.shared.resource_suffix, extension);
|
||||||
|
cx.shared.fs.write(cx.dst.join(filename), bytes)?;
|
||||||
if (*cx.shared).layout.logo.is_empty() {
|
|
||||||
write_toolchain("rust-logo.svg", static_files::RUST_LOGO_SVG)?;
|
|
||||||
}
|
|
||||||
if (*cx.shared).layout.favicon.is_empty() {
|
|
||||||
write_toolchain("favicon.svg", static_files::RUST_FAVICON_SVG)?;
|
|
||||||
write_toolchain("favicon-16x16.png", static_files::RUST_FAVICON_PNG_16)?;
|
|
||||||
write_toolchain("favicon-32x32.png", static_files::RUST_FAVICON_PNG_32)?;
|
|
||||||
}
|
|
||||||
write_toolchain("wheel.svg", static_files::WHEEL_SVG)?;
|
|
||||||
write_toolchain("clipboard.svg", static_files::CLIPBOARD_SVG)?;
|
|
||||||
write_toolchain("down-arrow.svg", static_files::DOWN_ARROW_SVG)?;
|
|
||||||
write_toolchain("toggle-minus.svg", static_files::TOGGLE_MINUS_PNG)?;
|
|
||||||
write_toolchain("toggle-plus.svg", static_files::TOGGLE_PLUS_PNG)?;
|
|
||||||
|
|
||||||
let mut themes: Vec<&String> = themes.iter().collect();
|
|
||||||
themes.sort();
|
|
||||||
|
|
||||||
write_minify("main.js", static_files::MAIN_JS, cx, options)?;
|
|
||||||
write_minify("search.js", static_files::SEARCH_JS, cx, options)?;
|
|
||||||
write_minify("settings.js", static_files::SETTINGS_JS, cx, options)?;
|
|
||||||
|
|
||||||
if cx.include_sources {
|
|
||||||
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT, cx, options)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write_minify("storage.js", static_files::STORAGE_JS, cx, options)?;
|
|
||||||
|
|
||||||
if cx.shared.layout.scrape_examples_extension {
|
|
||||||
cx.write_minify(
|
|
||||||
SharedResource::InvocationSpecific { basename: "scrape-examples.js" },
|
|
||||||
static_files::SCRAPE_EXAMPLES_JS,
|
|
||||||
options.enable_minification,
|
|
||||||
&options.emit,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When the user adds their own CSS files with --extend-css, we write that as an
|
||||||
|
// invocation-specific file (that is, with a resource suffix).
|
||||||
if let Some(ref css) = cx.shared.layout.css_file_extension {
|
if let Some(ref css) = cx.shared.layout.css_file_extension {
|
||||||
let buffer = try_err!(fs::read_to_string(css), css);
|
let buffer = try_err!(fs::read_to_string(css), css);
|
||||||
// This varies based on the invocation, so it can't go through the write_minify wrapper.
|
let path = static_files::suffix_path("theme.css", &cx.shared.resource_suffix);
|
||||||
cx.write_minify(
|
cx.shared.fs.write(cx.dst.join(path), buffer)?;
|
||||||
SharedResource::InvocationSpecific { basename: "theme.css" },
|
|
||||||
buffer,
|
|
||||||
options.enable_minification,
|
|
||||||
&options.emit,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
write_minify("normalize.css", static_files::NORMALIZE_CSS, cx, options)?;
|
|
||||||
for (name, contents) in &*FILES_UNVERSIONED {
|
if options.emit.is_empty() || options.emit.contains(&EmitType::Toolchain) {
|
||||||
cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?;
|
for f in static_files::STATIC_FILES_LIST {
|
||||||
|
let filename = static_files::static_filename(f.filename, f.bytes);
|
||||||
|
cx.shared.fs.write(cx.dst.join(filename), f.minified())?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a file and return all lines that match the `"{crate}":{data},` format,
|
/// Read a file and return all lines that match the `"{crate}":{data},` format,
|
||||||
|
@ -463,7 +269,7 @@ pub(super) fn write_shared(
|
||||||
v.push_str("\\\n}');\ncreateSourceSidebar();\n");
|
v.push_str("\\\n}');\ncreateSourceSidebar();\n");
|
||||||
Ok(v.into_bytes())
|
Ok(v.into_bytes())
|
||||||
};
|
};
|
||||||
write_crate("source-files.js", &make_sources)?;
|
write_invocation_specific("source-files.js", &make_sources)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the search index and crate list.
|
// Update the search index and crate list.
|
||||||
|
@ -477,7 +283,7 @@ pub(super) fn write_shared(
|
||||||
// Sort the indexes by crate so the file will be generated identically even
|
// Sort the indexes by crate so the file will be generated identically even
|
||||||
// with rustdoc running in parallel.
|
// with rustdoc running in parallel.
|
||||||
all_indexes.sort();
|
all_indexes.sort();
|
||||||
write_crate("search-index.js", &|| {
|
write_invocation_specific("search-index.js", &|| {
|
||||||
let mut v = String::from("var searchIndex = JSON.parse('{\\\n");
|
let mut v = String::from("var searchIndex = JSON.parse('{\\\n");
|
||||||
v.push_str(&all_indexes.join(",\\\n"));
|
v.push_str(&all_indexes.join(",\\\n"));
|
||||||
v.push_str(
|
v.push_str(
|
||||||
|
@ -490,7 +296,7 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
|
||||||
Ok(v.into_bytes())
|
Ok(v.into_bytes())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
write_crate("crates.js", &|| {
|
write_invocation_specific("crates.js", &|| {
|
||||||
let krates = krates.iter().map(|k| format!("\"{}\"", k)).join(",");
|
let krates = krates.iter().map(|k| format!("\"{}\"", k)).join(",");
|
||||||
Ok(format!("window.ALL_CRATES = [{}];", krates).into_bytes())
|
Ok(format!("window.ALL_CRATES = [{}];", krates).into_bytes())
|
||||||
})?;
|
})?;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: local('Fira Sans'),
|
src: local('Fira Sans'),
|
||||||
url("FiraSans-Regular.woff2") format("woff2");
|
url("FiraSans-Regular-018c141bf0843ffd.woff2") format("woff2");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
src: local('Fira Sans Medium'),
|
src: local('Fira Sans Medium'),
|
||||||
url("FiraSans-Medium.woff2") format("woff2");
|
url("FiraSans-Medium-8f9a781e4970d388.woff2") format("woff2");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: local('Source Serif 4'),
|
src: local('Source Serif 4'),
|
||||||
url("SourceSerif4-Regular.ttf.woff2") format("woff2");
|
url("SourceSerif4-Regular-1f7d512b176f0f72.ttf.woff2") format("woff2");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: local('Source Serif 4 Italic'),
|
src: local('Source Serif 4 Italic'),
|
||||||
url("SourceSerif4-It.ttf.woff2") format("woff2");
|
url("SourceSerif4-It-d034fe4ef9d0fa00.ttf.woff2") format("woff2");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
src: local('Source Serif 4 Bold'),
|
src: local('Source Serif 4 Bold'),
|
||||||
url("SourceSerif4-Bold.ttf.woff2") format("woff2");
|
url("SourceSerif4-Bold-124a1ca42af929b6.ttf.woff2") format("woff2");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,28 +49,28 @@
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
/* Avoid using locally installed font because bad versions are in circulation:
|
/* Avoid using locally installed font because bad versions are in circulation:
|
||||||
* see https://github.com/rust-lang/rust/issues/24355 */
|
* see https://github.com/rust-lang/rust/issues/24355 */
|
||||||
src: url("SourceCodePro-Regular.ttf.woff2") format("woff2");
|
src: url("SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2") format("woff2");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Source Code Pro';
|
font-family: 'Source Code Pro';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: url("SourceCodePro-It.ttf.woff2") format("woff2");
|
src: url("SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2") format("woff2");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Source Code Pro';
|
font-family: 'Source Code Pro';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
src: url("SourceCodePro-Semibold.ttf.woff2") format("woff2");
|
src: url("SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2") format("woff2");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Avoid using legacy CJK serif fonts in Windows like Batang. */
|
/* Avoid using legacy CJK serif fonts in Windows like Batang. */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'NanumBarunGothic';
|
font-family: 'NanumBarunGothic';
|
||||||
src: url("NanumBarunGothic.ttf.woff2") format("woff2");
|
src: url("NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2") format("woff2");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
|
unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
|
||||||
}
|
}
|
||||||
|
@ -848,7 +848,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
||||||
background-size: 20px;
|
background-size: 20px;
|
||||||
background-position: calc(100% - 2px) 56%;
|
background-position: calc(100% - 2px) 56%;
|
||||||
/* image is black color, themes should apply a "filter" property to change the color */
|
/* image is black color, themes should apply a "filter" property to change the color */
|
||||||
background-image: /* AUTOREPLACE: */url("down-arrow.svg");
|
background-image: url("down-arrow-2d685a4bae708e15.svg");
|
||||||
}
|
}
|
||||||
#crate-search > option {
|
#crate-search > option {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
@ -1625,11 +1625,11 @@ details.rustdoc-toggle[open] > summary.hideme > span {
|
||||||
|
|
||||||
details.rustdoc-toggle[open] > summary::before,
|
details.rustdoc-toggle[open] > summary::before,
|
||||||
details.rustdoc-toggle[open] > summary.hideme::before {
|
details.rustdoc-toggle[open] > summary.hideme::before {
|
||||||
background-image: /* AUTOREPLACE: */url("toggle-minus.svg");
|
background-image: url("toggle-minus-31bbd6e4c77f5c96.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
details.rustdoc-toggle > summary::before {
|
details.rustdoc-toggle > summary::before {
|
||||||
background-image: /* AUTOREPLACE: */url("toggle-plus.svg");
|
background-image: url("toggle-plus-1092eb4930d581b0.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
details.rustdoc-toggle[open] > summary::before,
|
details.rustdoc-toggle[open] > summary::before,
|
||||||
|
|
12
src/librustdoc/html/static/fonts/README.txt
Normal file
12
src/librustdoc/html/static/fonts/README.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
The Nanum Barun Gothic fonts are shipped with rustdoc because the default fonts
|
||||||
|
on many Windows installs render Korean very badly. See:
|
||||||
|
- https://github.com/rust-lang/rust/pull/84048,
|
||||||
|
- https://github.com/rust-lang/rust/issues/84035
|
||||||
|
- https://github.com/rust-lang/rust/pull/90232
|
||||||
|
|
||||||
|
The font files were generated with these commands:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pyftsubset NanumBarunGothic.ttf \
|
||||||
|
--unicodes=U+AC00-D7AF:U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
|
||||||
|
--output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
|
|
@ -183,9 +183,9 @@ function browserSupportsHistoryApi() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function loadCss(cssFileName) {
|
function loadCss(cssUrl) {
|
||||||
const link = document.createElement("link");
|
const link = document.createElement("link");
|
||||||
link.href = resourcePath(cssFileName, ".css");
|
link.href = cssUrl;
|
||||||
link.type = "text/css";
|
link.type = "text/css";
|
||||||
link.rel = "stylesheet";
|
link.rel = "stylesheet";
|
||||||
document.getElementsByTagName("head")[0].appendChild(link);
|
document.getElementsByTagName("head")[0].appendChild(link);
|
||||||
|
@ -208,8 +208,8 @@ function loadCss(cssFileName) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
// Sending request for the CSS and the JS files at the same time so it will
|
// Sending request for the CSS and the JS files at the same time so it will
|
||||||
// hopefully be loaded when the JS will generate the settings content.
|
// hopefully be loaded when the JS will generate the settings content.
|
||||||
loadCss("settings");
|
loadCss(getVar("static-root-path") + getVar("settings-css"));
|
||||||
loadScript(resourcePath("settings", ".js"));
|
loadScript(getVar("static-root-path") + getVar("settings-js"));
|
||||||
};
|
};
|
||||||
|
|
||||||
window.searchState = {
|
window.searchState = {
|
||||||
|
@ -286,7 +286,7 @@ function loadCss(cssFileName) {
|
||||||
function loadSearch() {
|
function loadSearch() {
|
||||||
if (!searchLoaded) {
|
if (!searchLoaded) {
|
||||||
searchLoaded = true;
|
searchLoaded = true;
|
||||||
loadScript(resourcePath("search", ".js"));
|
loadScript(getVar("static-root-path") + getVar("search-js"));
|
||||||
loadScript(resourcePath("search-index", ".js"));
|
loadScript(resourcePath("search-index", ".js"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,9 @@
|
||||||
* @return {HTMLElement}
|
* @return {HTMLElement}
|
||||||
*/
|
*/
|
||||||
function buildSettingsPage() {
|
function buildSettingsPage() {
|
||||||
const themes = getVar("themes").split(",");
|
const theme_names = getVar("themes").split(",").filter(t => t);
|
||||||
|
theme_names.push("light", "dark", "ayu");
|
||||||
|
|
||||||
const settings = [
|
const settings = [
|
||||||
{
|
{
|
||||||
"name": "Use system theme",
|
"name": "Use system theme",
|
||||||
|
@ -165,19 +167,19 @@
|
||||||
"name": "Theme",
|
"name": "Theme",
|
||||||
"js_name": "theme",
|
"js_name": "theme",
|
||||||
"default": "light",
|
"default": "light",
|
||||||
"options": themes,
|
"options": theme_names,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Preferred light theme",
|
"name": "Preferred light theme",
|
||||||
"js_name": "preferred-light-theme",
|
"js_name": "preferred-light-theme",
|
||||||
"default": "light",
|
"default": "light",
|
||||||
"options": themes,
|
"options": theme_names,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Preferred dark theme",
|
"name": "Preferred dark theme",
|
||||||
"js_name": "preferred-dark-theme",
|
"js_name": "preferred-dark-theme",
|
||||||
"default": "dark",
|
"default": "dark",
|
||||||
"options": themes,
|
"options": theme_names,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Auto-hide item contents for large items",
|
"name": "Auto-hide item contents for large items",
|
||||||
|
|
|
@ -126,33 +126,29 @@ function getCurrentValue(name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
|
function switchTheme(styleElem, mainStyleElem, newThemeName, saveTheme) {
|
||||||
const newHref = mainStyleElem.href.replace(
|
|
||||||
/\/rustdoc([^/]*)\.css/, "/" + newTheme + "$1" + ".css");
|
|
||||||
|
|
||||||
// If this new value comes from a system setting or from the previously
|
// If this new value comes from a system setting or from the previously
|
||||||
// saved theme, no need to save it.
|
// saved theme, no need to save it.
|
||||||
if (saveTheme) {
|
if (saveTheme) {
|
||||||
updateLocalStorage("theme", newTheme);
|
updateLocalStorage("theme", newThemeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (styleElem.href === newHref) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let found = false;
|
|
||||||
if (savedHref.length === 0) {
|
if (savedHref.length === 0) {
|
||||||
onEachLazy(document.getElementsByTagName("link"), el => {
|
onEachLazy(document.getElementsByTagName("link"), el => {
|
||||||
savedHref.push(el.href);
|
savedHref.push(el.href);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onEach(savedHref, el => {
|
const newHref = savedHref.find(url => {
|
||||||
if (el === newHref) {
|
const m = url.match(/static\.files\/(.*)-[a-f0-9]{16}\.css$/);
|
||||||
found = true;
|
if (m && m[1] === newThemeName) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const m2 = url.match(/\/([^/]*)\.css$/);
|
||||||
|
if (m2 && m2[1].startsWith(newThemeName)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (found) {
|
if (newHref && newHref !== styleElem.href) {
|
||||||
styleElem.href = newHref;
|
styleElem.href = newHref;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,167 +2,119 @@
|
||||||
//!
|
//!
|
||||||
//! All the static files are included here for centralized access in case anything other than the
|
//! All the static files are included here for centralized access in case anything other than the
|
||||||
//! HTML rendering code (say, the theme checker) needs to access one of these files.
|
//! HTML rendering code (say, the theme checker) needs to access one of these files.
|
||||||
//!
|
|
||||||
//! Note about types: CSS and JavaScript files are included as `&'static str` to allow for the
|
|
||||||
//! minifier to run on them. All other files are included as `&'static [u8]` so they can be
|
|
||||||
//! directly written to a `Write` handle.
|
|
||||||
|
|
||||||
/// The file contents of the main `rustdoc.css` file, responsible for the core layout of the page.
|
use rustc_data_structures::fx::FxHasher;
|
||||||
pub(crate) static RUSTDOC_CSS: &str = include_str!("static/css/rustdoc.css");
|
use std::hash::Hasher;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::{fmt, str};
|
||||||
|
|
||||||
/// The file contents of `settings.css`, responsible for the items on the settings page.
|
pub(crate) struct StaticFile {
|
||||||
pub(crate) static SETTINGS_CSS: &str = include_str!("static/css/settings.css");
|
pub(crate) filename: &'static str,
|
||||||
|
pub(crate) bytes: &'static [u8],
|
||||||
/// The file contents of the `noscript.css` file, used in case JS isn't supported or is disabled.
|
|
||||||
pub(crate) static NOSCRIPT_CSS: &str = include_str!("static/css/noscript.css");
|
|
||||||
|
|
||||||
/// The file contents of `normalize.css`, included to even out standard elements between browser
|
|
||||||
/// implementations.
|
|
||||||
pub(crate) static NORMALIZE_CSS: &str = include_str!("static/css/normalize.css");
|
|
||||||
|
|
||||||
/// The file contents of `main.js`, which contains the core JavaScript used on documentation pages,
|
|
||||||
/// including search behavior and docblock folding, among others.
|
|
||||||
pub(crate) static MAIN_JS: &str = include_str!("static/js/main.js");
|
|
||||||
|
|
||||||
/// The file contents of `search.js`, which contains the search behavior.
|
|
||||||
pub(crate) static SEARCH_JS: &str = include_str!("static/js/search.js");
|
|
||||||
|
|
||||||
/// The file contents of `settings.js`, which contains the JavaScript used to handle the settings
|
|
||||||
/// page.
|
|
||||||
pub(crate) static SETTINGS_JS: &str = include_str!("static/js/settings.js");
|
|
||||||
|
|
||||||
/// The file contents of `storage.js`, which contains functionality related to browser Local
|
|
||||||
/// Storage, used to store documentation settings.
|
|
||||||
pub(crate) static STORAGE_JS: &str = include_str!("static/js/storage.js");
|
|
||||||
|
|
||||||
/// The file contents of `scraped-examples.js`, which contains functionality related to the
|
|
||||||
/// --scrape-examples flag that inserts automatically-found examples of usages of items.
|
|
||||||
pub(crate) static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples.js");
|
|
||||||
|
|
||||||
pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/scrape-examples-help.md");
|
|
||||||
|
|
||||||
/// The file contents of `wheel.svg`, the icon used for the settings button.
|
|
||||||
pub(crate) static WHEEL_SVG: &[u8] = include_bytes!("static/images/wheel.svg");
|
|
||||||
|
|
||||||
/// The file contents of `clipboard.svg`, the icon used for the "copy path" button.
|
|
||||||
pub(crate) static CLIPBOARD_SVG: &[u8] = include_bytes!("static/images/clipboard.svg");
|
|
||||||
|
|
||||||
/// The file contents of `down-arrow.svg`, the icon used for the crate choice combobox.
|
|
||||||
pub(crate) static DOWN_ARROW_SVG: &[u8] = include_bytes!("static/images/down-arrow.svg");
|
|
||||||
|
|
||||||
/// The file contents of `toggle-minus.svg`, the icon used for opened toggles.
|
|
||||||
pub(crate) static TOGGLE_MINUS_PNG: &[u8] = include_bytes!("static/images/toggle-minus.svg");
|
|
||||||
|
|
||||||
/// The file contents of `toggle-plus.svg`, the icon used for closed toggles.
|
|
||||||
pub(crate) static TOGGLE_PLUS_PNG: &[u8] = include_bytes!("static/images/toggle-plus.svg");
|
|
||||||
|
|
||||||
/// The contents of `COPYRIGHT.txt`, the license listing for files distributed with documentation
|
|
||||||
/// output.
|
|
||||||
pub(crate) static COPYRIGHT: &[u8] = include_bytes!("static/COPYRIGHT.txt");
|
|
||||||
|
|
||||||
/// The contents of `LICENSE-APACHE.txt`, the text of the Apache License, version 2.0.
|
|
||||||
pub(crate) static LICENSE_APACHE: &[u8] = include_bytes!("static/LICENSE-APACHE.txt");
|
|
||||||
|
|
||||||
/// The contents of `LICENSE-MIT.txt`, the text of the MIT License.
|
|
||||||
pub(crate) static LICENSE_MIT: &[u8] = include_bytes!("static/LICENSE-MIT.txt");
|
|
||||||
|
|
||||||
/// The contents of `rust-logo.svg`, the default icon of the documentation.
|
|
||||||
pub(crate) static RUST_LOGO_SVG: &[u8] = include_bytes!("static/images/rust-logo.svg");
|
|
||||||
|
|
||||||
/// The default documentation favicons (SVG and PNG fallbacks)
|
|
||||||
pub(crate) static RUST_FAVICON_SVG: &[u8] = include_bytes!("static/images/favicon.svg");
|
|
||||||
pub(crate) static RUST_FAVICON_PNG_16: &[u8] = include_bytes!("static/images/favicon-16x16.png");
|
|
||||||
pub(crate) static RUST_FAVICON_PNG_32: &[u8] = include_bytes!("static/images/favicon-32x32.png");
|
|
||||||
|
|
||||||
/// The built-in themes given to every documentation site.
|
|
||||||
pub(crate) mod themes {
|
|
||||||
/// The "light" theme, selected by default when no setting is available. Used as the basis for
|
|
||||||
/// the `--check-theme` functionality.
|
|
||||||
pub(crate) static LIGHT: &str = include_str!("static/css/themes/light.css");
|
|
||||||
|
|
||||||
/// The "dark" theme.
|
|
||||||
pub(crate) static DARK: &str = include_str!("static/css/themes/dark.css");
|
|
||||||
|
|
||||||
/// The "ayu" theme.
|
|
||||||
pub(crate) static AYU: &str = include_str!("static/css/themes/ayu.css");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Files related to the Fira Sans font.
|
impl StaticFile {
|
||||||
pub(crate) mod fira_sans {
|
pub(crate) fn minified(&self) -> Vec<u8> {
|
||||||
/// The file `FiraSans-Regular.woff2`, the Regular variant of the Fira Sans font in woff2.
|
if self.filename.ends_with(".css") {
|
||||||
pub(crate) static REGULAR: &[u8] = include_bytes!("static/fonts/FiraSans-Regular.woff2");
|
minifier::css::minify(str::from_utf8(self.bytes).unwrap()).unwrap().to_string().into()
|
||||||
|
} else if self.filename.ends_with(".js") {
|
||||||
|
minifier::js::minify(str::from_utf8(self.bytes).unwrap()).to_string().into()
|
||||||
|
} else {
|
||||||
|
self.bytes.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The file `FiraSans-Medium.woff2`, the Medium variant of the Fira Sans font in woff2.
|
pub(crate) fn output_filename(&self) -> PathBuf {
|
||||||
pub(crate) static MEDIUM: &[u8] = include_bytes!("static/fonts/FiraSans-Medium.woff2");
|
static_filename(self.filename, self.bytes)
|
||||||
|
}
|
||||||
/// The file `FiraSans-LICENSE.txt`, the license text for the Fira Sans font.
|
|
||||||
pub(crate) static LICENSE: &[u8] = include_bytes!("static/fonts/FiraSans-LICENSE.txt");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Files related to the Source Serif 4 font.
|
/// The Display implementation for a StaticFile outputs its filename. This makes it
|
||||||
pub(crate) mod source_serif_4 {
|
/// convenient to interpolate static files into HTML templates.
|
||||||
/// The file `SourceSerif4-Regular.ttf.woff2`, the Regular variant of the Source Serif 4 font in
|
impl fmt::Display for StaticFile {
|
||||||
/// woff2.
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
pub(crate) static REGULAR: &[u8] =
|
write!(f, "{}", self.output_filename().display())
|
||||||
include_bytes!("static/fonts/SourceSerif4-Regular.ttf.woff2");
|
}
|
||||||
|
|
||||||
/// The file `SourceSerif4-Bold.ttf.woff2`, the Bold variant of the Source Serif 4 font in
|
|
||||||
/// woff2.
|
|
||||||
pub(crate) static BOLD: &[u8] = include_bytes!("static/fonts/SourceSerif4-Bold.ttf.woff2");
|
|
||||||
|
|
||||||
/// The file `SourceSerif4-It.ttf.woff2`, the Italic variant of the Source Serif 4 font in
|
|
||||||
/// woff2.
|
|
||||||
pub(crate) static ITALIC: &[u8] = include_bytes!("static/fonts/SourceSerif4-It.ttf.woff2");
|
|
||||||
|
|
||||||
/// The file `SourceSerif4-LICENSE.txt`, the license text for the Source Serif 4 font.
|
|
||||||
pub(crate) static LICENSE: &[u8] = include_bytes!("static/fonts/SourceSerif4-LICENSE.md");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Files related to the Source Code Pro font.
|
/// Insert the provided suffix into a filename just before the extension.
|
||||||
pub(crate) mod source_code_pro {
|
pub(crate) fn suffix_path(filename: &str, suffix: &str) -> PathBuf {
|
||||||
/// The file `SourceCodePro-Regular.ttf.woff2`, the Regular variant of the Source Code Pro font
|
// We use splitn vs Path::extension here because we might get a filename
|
||||||
/// in woff2.
|
// like `style.min.css` and we want to process that into
|
||||||
pub(crate) static REGULAR: &[u8] =
|
// `style-suffix.min.css`. Path::extension would just return `css`
|
||||||
include_bytes!("static/fonts/SourceCodePro-Regular.ttf.woff2");
|
// which would result in `style.min-suffix.css` which isn't what we
|
||||||
|
// want.
|
||||||
/// The file `SourceCodePro-Semibold.ttf.woff2`, the Semibold variant of the Source Code Pro
|
let (base, ext) = filename.split_once('.').unwrap();
|
||||||
/// font in woff2.
|
let filename = format!("{}{}.{}", base, suffix, ext);
|
||||||
pub(crate) static SEMIBOLD: &[u8] =
|
filename.into()
|
||||||
include_bytes!("static/fonts/SourceCodePro-Semibold.ttf.woff2");
|
|
||||||
|
|
||||||
/// The file `SourceCodePro-It.ttf.woff2`, the Italic variant of the Source Code Pro font in
|
|
||||||
/// woff2.
|
|
||||||
pub(crate) static ITALIC: &[u8] = include_bytes!("static/fonts/SourceCodePro-It.ttf.woff2");
|
|
||||||
|
|
||||||
/// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font.
|
|
||||||
pub(crate) static LICENSE: &[u8] = include_bytes!("static/fonts/SourceCodePro-LICENSE.txt");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Files related to the Nanum Barun Gothic font.
|
pub(crate) fn static_filename(filename: &str, contents: &[u8]) -> PathBuf {
|
||||||
///
|
let filename = filename.rsplit("/").next().unwrap();
|
||||||
/// These files are used to avoid some legacy CJK serif fonts in Windows.
|
Path::new("static.files").join(suffix_path(filename, &static_suffix(contents)))
|
||||||
///
|
|
||||||
/// Note that the Noto Sans KR font, which was used previously but was not very readable on Windows,
|
|
||||||
/// has been replaced by the Nanum Barun Gothic font. This is due to Windows' implementation of font
|
|
||||||
/// rendering that distorts OpenType fonts too much.
|
|
||||||
///
|
|
||||||
/// The font files were generated with these commands:
|
|
||||||
///
|
|
||||||
/// ```sh
|
|
||||||
/// pyftsubset NanumBarunGothic.ttf \
|
|
||||||
/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
|
|
||||||
/// --output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
|
|
||||||
/// ```
|
|
||||||
pub(crate) mod nanum_barun_gothic {
|
|
||||||
/// The file `NanumBarunGothic.ttf.woff2`, the Regular variant of the Nanum Barun Gothic font.
|
|
||||||
pub(crate) static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
|
|
||||||
|
|
||||||
/// The file `NanumBarunGothic-LICENSE.txt`, the license text of the Nanum Barun Gothic font.
|
|
||||||
pub(crate) static LICENSE: &[u8] = include_bytes!("static/fonts/NanumBarunGothic-LICENSE.txt");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Files related to the sidebar in rustdoc sources.
|
fn static_suffix(bytes: &[u8]) -> String {
|
||||||
pub(crate) mod sidebar {
|
let mut hasher = FxHasher::default();
|
||||||
/// File script to handle sidebar.
|
hasher.write(bytes);
|
||||||
pub(crate) static SOURCE_SCRIPT: &str = include_str!("static/js/source-script.js");
|
format!("-{:016x}", hasher.finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! static_files {
|
||||||
|
($($field:ident => $file_path:literal,)+) => {
|
||||||
|
pub(crate) struct StaticFiles {
|
||||||
|
$(pub $field: StaticFile,)+
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const STATIC_FILES: StaticFiles = StaticFiles {
|
||||||
|
$($field: StaticFile { filename: $file_path, bytes: include_bytes!($file_path) },)+
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) static STATIC_FILES_LIST: &[&'static StaticFile] = &[
|
||||||
|
$(&STATIC_FILES.$field,)+
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static_files! {
|
||||||
|
rustdoc_css => "static/css/rustdoc.css",
|
||||||
|
settings_css => "static/css/settings.css",
|
||||||
|
noscript_css => "static/css/noscript.css",
|
||||||
|
normalize_css => "static/css/normalize.css",
|
||||||
|
main_js => "static/js/main.js",
|
||||||
|
search_js => "static/js/search.js",
|
||||||
|
settings_js => "static/js/settings.js",
|
||||||
|
source_script_js => "static/js/source-script.js",
|
||||||
|
storage_js => "static/js/storage.js",
|
||||||
|
scrape_examples_js => "static/js/scrape-examples.js",
|
||||||
|
wheel_svg => "static/images/wheel.svg",
|
||||||
|
clipboard_svg => "static/images/clipboard.svg",
|
||||||
|
down_arrow_svg => "static/images/down-arrow.svg",
|
||||||
|
toggle_minus_png => "static/images/toggle-minus.svg",
|
||||||
|
toggle_plus_png => "static/images/toggle-plus.svg",
|
||||||
|
copyright => "static/COPYRIGHT.txt",
|
||||||
|
license_apache => "static/LICENSE-APACHE.txt",
|
||||||
|
license_mit => "static/LICENSE-MIT.txt",
|
||||||
|
rust_logo_svg => "static/images/rust-logo.svg",
|
||||||
|
rust_favicon_svg => "static/images/favicon.svg",
|
||||||
|
rust_favicon_png_16 => "static/images/favicon-16x16.png",
|
||||||
|
rust_favicon_png_32 => "static/images/favicon-32x32.png",
|
||||||
|
theme_light_css => "static/css/themes/light.css",
|
||||||
|
theme_dark_css => "static/css/themes/dark.css",
|
||||||
|
theme_ayu_css => "static/css/themes/ayu.css",
|
||||||
|
fira_sans_regular => "static/fonts/FiraSans-Regular.woff2",
|
||||||
|
fira_sans_medium => "static/fonts/FiraSans-Medium.woff2",
|
||||||
|
fira_sans_license => "static/fonts/FiraSans-LICENSE.txt",
|
||||||
|
source_serif_4_regular => "static/fonts/SourceSerif4-Regular.ttf.woff2",
|
||||||
|
source_serif_4_bold => "static/fonts/SourceSerif4-Bold.ttf.woff2",
|
||||||
|
source_serif_4_italic => "static/fonts/SourceSerif4-It.ttf.woff2",
|
||||||
|
source_serif_4_license => "static/fonts/SourceSerif4-LICENSE.md",
|
||||||
|
source_code_pro_regular => "static/fonts/SourceCodePro-Regular.ttf.woff2",
|
||||||
|
source_code_pro_semibold => "static/fonts/SourceCodePro-Semibold.ttf.woff2",
|
||||||
|
source_code_pro_italic => "static/fonts/SourceCodePro-It.ttf.woff2",
|
||||||
|
source_code_pro_license => "static/fonts/SourceCodePro-LICENSE.txt",
|
||||||
|
nanum_barun_gothic_regular => "static/fonts/NanumBarunGothic.ttf.woff2",
|
||||||
|
nanum_barun_gothic_license => "static/fonts/NanumBarunGothic-LICENSE.txt",
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/js/scrape-examples.js");
|
||||||
|
|
|
@ -7,48 +7,44 @@
|
||||||
<meta name="description" content="{{page.description}}"> {#- -#}
|
<meta name="description" content="{{page.description}}"> {#- -#}
|
||||||
<meta name="keywords" content="{{page.keywords}}"> {#- -#}
|
<meta name="keywords" content="{{page.keywords}}"> {#- -#}
|
||||||
<title>{{page.title}}</title> {#- -#}
|
<title>{{page.title}}</title> {#- -#}
|
||||||
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
|
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_regular}}"> {#- -#}
|
||||||
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}FiraSans-Regular.woff2"> {#- -#}
|
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_regular}}"> {#- -#}
|
||||||
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}FiraSans-Medium.woff2"> {#- -#}
|
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_medium}}"> {#- -#}
|
||||||
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
|
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_regular}}"> {#- -#}
|
||||||
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
|
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_bold}}"> {#- -#}
|
||||||
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
|
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_semibold}}"> {#- -#}
|
||||||
<link rel="stylesheet" {# -#}
|
<link rel="stylesheet" {# -#}
|
||||||
href="{{static_root_path|safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
|
href="{{static_root_path|safe}}{{files.normalize_css}}"> {#- -#}
|
||||||
<link rel="stylesheet" {# -#}
|
<link rel="stylesheet" {# -#}
|
||||||
href="{{static_root_path|safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
|
href="{{static_root_path|safe}}{{files.rustdoc_css}}" {# -#}
|
||||||
id="mainThemeStyle"> {#- -#}
|
id="mainThemeStyle"> {#- -#}
|
||||||
|
<link rel="stylesheet" id="themeStyle" href="{{static_root_path|safe}}{{files.theme_light_css}}"> {#- -#}
|
||||||
|
<link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_dark_css}}"> {#- -#}
|
||||||
|
<link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_ayu_css}}"> {#- -#}
|
||||||
{%- for theme in themes -%}
|
{%- for theme in themes -%}
|
||||||
<link rel="stylesheet" {# -#}
|
<link rel="stylesheet" disabled href="{{page.root_path|safe}}{{theme}}{{page.resource_suffix}}.css"> {#- -#}
|
||||||
href="{{static_root_path|safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
|
|
||||||
{%- if theme == "light" -%}
|
|
||||||
id="themeStyle"
|
|
||||||
{%- else -%}
|
|
||||||
disabled
|
|
||||||
{%- endif -%}
|
|
||||||
>
|
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
<script id="default-settings" {# -#}
|
<script id="default-settings" {# -#}
|
||||||
{% for (k, v) in layout.default_settings %}
|
{% for (k, v) in layout.default_settings %}
|
||||||
data-{{k}}="{{v}}"
|
data-{{k}}="{{v}}"
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
></script> {#- -#}
|
></script> {#- -#}
|
||||||
<script src="{{static_root_path|safe}}storage{{page.resource_suffix}}.js"></script> {#- -#}
|
<script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {#- -#}
|
||||||
{%- if page.css_class.contains("crate") -%}
|
{%- if page.css_class.contains("crate") -%}
|
||||||
<script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
|
<script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
|
||||||
{%- else if page.css_class == "source" -%}
|
{%- else if page.css_class == "source" -%}
|
||||||
<script defer src="{{static_root_path|safe}}source-script{{page.resource_suffix}}.js"></script> {#- -#}
|
<script defer src="{{static_root_path|safe}}{{files.source_script_js}}"></script> {#- -#}
|
||||||
<script defer src="{{page.root_path|safe}}source-files{{page.resource_suffix}}.js"></script> {#- -#}
|
<script defer src="{{page.root_path|safe}}source-files{{page.resource_suffix}}.js"></script> {#- -#}
|
||||||
{%- else if !page.css_class.contains("mod") -%}
|
{%- else if !page.css_class.contains("mod") -%}
|
||||||
<script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {#- -#}
|
<script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {#- -#}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
<script defer src="{{static_root_path|safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
|
<script defer src="{{static_root_path|safe}}{{files.main_js}}"></script> {#- -#}
|
||||||
{%- if layout.scrape_examples_extension -%}
|
{%- if layout.scrape_examples_extension -%}
|
||||||
<script defer src="{{page.root_path|safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
|
<script defer src="{{page.root_path|safe}}{{files.scrape_examples_js}}"></script> {#- -#}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
<noscript> {#- -#}
|
<noscript> {#- -#}
|
||||||
<link rel="stylesheet" {# -#}
|
<link rel="stylesheet" {# -#}
|
||||||
href="{{static_root_path|safe}}noscript{{page.resource_suffix}}.css"> {#- -#}
|
href="{{static_root_path|safe}}{{files.noscript_css}}"> {#- -#}
|
||||||
</noscript> {#- -#}
|
</noscript> {#- -#}
|
||||||
{%- if layout.css_file_extension.is_some() -%}
|
{%- if layout.css_file_extension.is_some() -%}
|
||||||
<link rel="stylesheet" {# -#}
|
<link rel="stylesheet" {# -#}
|
||||||
|
@ -58,11 +54,11 @@
|
||||||
<link rel="icon" href="{{layout.favicon}}"> {#- -#}
|
<link rel="icon" href="{{layout.favicon}}"> {#- -#}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
<link rel="alternate icon" type="image/png" {# -#}
|
<link rel="alternate icon" type="image/png" {# -#}
|
||||||
href="{{static_root_path|safe}}favicon-16x16{{page.resource_suffix}}.png"> {#- -#}
|
href="{{static_root_path|safe}}{{files.rust_favicon_png_16}}"> {#- -#}
|
||||||
<link rel="alternate icon" type="image/png" {# -#}
|
<link rel="alternate icon" type="image/png" {# -#}
|
||||||
href="{{static_root_path|safe}}favicon-32x32{{page.resource_suffix}}.png"> {#- -#}
|
href="{{static_root_path|safe}}{{files.rust_favicon_png_32}}"> {#- -#}
|
||||||
<link rel="icon" type="image/svg+xml" {# -#}
|
<link rel="icon" type="image/svg+xml" {# -#}
|
||||||
href="{{static_root_path|safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
|
href="{{static_root_path|safe}}{{files.rust_favicon_svg}}"> {#- -#}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
{{- layout.external_html.in_header|safe -}}
|
{{- layout.external_html.in_header|safe -}}
|
||||||
</head> {#- -#}
|
</head> {#- -#}
|
||||||
|
@ -81,7 +77,7 @@
|
||||||
{%- if !layout.logo.is_empty() -%}
|
{%- if !layout.logo.is_empty() -%}
|
||||||
<img src="{{layout.logo}}" alt="logo"> {#- -#}
|
<img src="{{layout.logo}}" alt="logo"> {#- -#}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
<img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
|
<img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</div> {#- -#}
|
</div> {#- -#}
|
||||||
</a> {#- -#}
|
</a> {#- -#}
|
||||||
|
@ -95,7 +91,7 @@
|
||||||
{%- if !layout.logo.is_empty() %}
|
{%- if !layout.logo.is_empty() %}
|
||||||
<img src="{{layout.logo}}" alt="logo"> {#- -#}
|
<img src="{{layout.logo}}" alt="logo"> {#- -#}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
<img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
|
<img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</div> {#- -#}
|
</div> {#- -#}
|
||||||
</a> {#- -#}
|
</a> {#- -#}
|
||||||
|
@ -110,7 +106,7 @@
|
||||||
{%- if !layout.logo.is_empty() %}
|
{%- if !layout.logo.is_empty() %}
|
||||||
<img src="{{layout.logo}}" alt="logo"> {#- -#}
|
<img src="{{layout.logo}}" alt="logo"> {#- -#}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
<img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
|
<img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</a> {#- -#}
|
</a> {#- -#}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
@ -129,7 +125,7 @@
|
||||||
<div id="settings-menu" tabindex="-1"> {#- -#}
|
<div id="settings-menu" tabindex="-1"> {#- -#}
|
||||||
<a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
|
<a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
|
||||||
<img width="22" height="22" alt="Change settings" {# -#}
|
<img width="22" height="22" alt="Change settings" {# -#}
|
||||||
src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
|
src="{{static_root_path|safe}}{{files.wheel_svg}}"> {#- -#}
|
||||||
</a> {#- -#}
|
</a> {#- -#}
|
||||||
</div> {#- -#}
|
</div> {#- -#}
|
||||||
</form> {#- -#}
|
</form> {#- -#}
|
||||||
|
@ -140,10 +136,14 @@
|
||||||
{{- layout.external_html.after_content|safe -}}
|
{{- layout.external_html.after_content|safe -}}
|
||||||
<div id="rustdoc-vars" {# -#}
|
<div id="rustdoc-vars" {# -#}
|
||||||
data-root-path="{{page.root_path|safe}}" {# -#}
|
data-root-path="{{page.root_path|safe}}" {# -#}
|
||||||
|
data-static-root-path="{{static_root_path|safe}}" {# -#}
|
||||||
data-current-crate="{{layout.krate}}" {# -#}
|
data-current-crate="{{layout.krate}}" {# -#}
|
||||||
data-themes="{{themes|join(",") }}" {# -#}
|
data-themes="{{themes|join(",") }}" {# -#}
|
||||||
data-resource-suffix="{{page.resource_suffix}}" {# -#}
|
data-resource-suffix="{{page.resource_suffix}}" {# -#}
|
||||||
data-rustdoc-version="{{rustdoc_version}}" {# -#}
|
data-rustdoc-version="{{rustdoc_version}}" {# -#}
|
||||||
|
data-search-js="{{files.search_js}}" {# -#}
|
||||||
|
data-settings-js="{{files.settings_js}}" {# -#}
|
||||||
|
data-settings-css="{{files.settings_css}}" {# -#}
|
||||||
> {#- -#}
|
> {#- -#}
|
||||||
</div> {#- -#}
|
</div> {#- -#}
|
||||||
</body> {#- -#}
|
</body> {#- -#}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
<a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
|
<a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
|
||||||
<button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#}
|
<button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#}
|
||||||
<img src="{{static_root_path|safe}}clipboard{{page.resource_suffix}}.svg" {# -#}
|
<img src="{{static_root_path|safe}}{{clipboard_svg}}" {# -#}
|
||||||
width="19" height="18" {# -#}
|
width="19" height="18" {# -#}
|
||||||
alt="Copy item path"> {#- -#}
|
alt="Copy item path"> {#- -#}
|
||||||
</button> {#- -#}
|
</button> {#- -#}
|
||||||
|
|
|
@ -469,9 +469,6 @@ fn opts() -> Vec<RustcOptGroup> {
|
||||||
stable("json", |o| {
|
stable("json", |o| {
|
||||||
o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
|
o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
|
||||||
}),
|
}),
|
||||||
unstable("disable-minification", |o| {
|
|
||||||
o.optflagmulti("", "disable-minification", "Disable minification applied on JS files")
|
|
||||||
}),
|
|
||||||
stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "LINT")),
|
stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "LINT")),
|
||||||
stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "LINT")),
|
stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "LINT")),
|
||||||
stable("force-warn", |o| o.optmulti("", "force-warn", "Set lint force-warn", "LINT")),
|
stable("force-warn", |o| o.optmulti("", "force-warn", "Set lint force-warn", "LINT")),
|
||||||
|
@ -610,6 +607,7 @@ fn opts() -> Vec<RustcOptGroup> {
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
// deprecated / removed options
|
// deprecated / removed options
|
||||||
|
unstable("disable-minification", |o| o.optflagmulti("", "disable-minification", "removed")),
|
||||||
stable("plugin-path", |o| {
|
stable("plugin-path", |o| {
|
||||||
o.optmulti(
|
o.optmulti(
|
||||||
"",
|
"",
|
||||||
|
|
|
@ -23,24 +23,24 @@ invocation-only:
|
||||||
|
|
||||||
toolchain-only:
|
toolchain-only:
|
||||||
$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources --output $(TOOLCHAIN_ONLY) --resource-suffix=-xxx --extend-css z.css x.rs
|
$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources --output $(TOOLCHAIN_ONLY) --resource-suffix=-xxx --extend-css z.css x.rs
|
||||||
[ -e $(TOOLCHAIN_ONLY)/storage-xxx.js ]
|
[ -e $(TOOLCHAIN_ONLY)/static.files/storage-*.js ]
|
||||||
! [ -e $(TOOLCHAIN_ONLY)/SourceSerif4-It.ttf.woff2 ]
|
[ -e $(TOOLCHAIN_ONLY)/static.files/SourceSerif4-It-*.ttf.woff2 ]
|
||||||
! [ -e $(TOOLCHAIN_ONLY)/search-index-xxx.js ]
|
! [ -e $(TOOLCHAIN_ONLY)/search-index-xxx.js ]
|
||||||
! [ -e $(TOOLCHAIN_ONLY)/x/index.html ]
|
! [ -e $(TOOLCHAIN_ONLY)/x/index.html ]
|
||||||
! [ -e $(TOOLCHAIN_ONLY)/theme.css ]
|
! [ -e $(TOOLCHAIN_ONLY)/theme.css ]
|
||||||
|
|
||||||
[ -e $(TOOLCHAIN_ONLY)/main-xxx.js ]
|
[ -e $(TOOLCHAIN_ONLY)/static.files/main-*.js ]
|
||||||
! [ -e $(TOOLCHAIN_ONLY)/y-xxx.css ]
|
! [ -e $(TOOLCHAIN_ONLY)/y-xxx.css ]
|
||||||
|
|
||||||
all-shared:
|
all-shared:
|
||||||
$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources,unversioned-shared-resources --output $(ALL_SHARED) --resource-suffix=-xxx --extend-css z.css x.rs
|
$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources,unversioned-shared-resources --output $(ALL_SHARED) --resource-suffix=-xxx --extend-css z.css x.rs
|
||||||
[ -e $(ALL_SHARED)/storage-xxx.js ]
|
[ -e $(ALL_SHARED)/static.files/storage-*.js ]
|
||||||
[ -e $(ALL_SHARED)/SourceSerif4-It.ttf.woff2 ]
|
[ -e $(ALL_SHARED)/static.files/SourceSerif4-It-*.ttf.woff2 ]
|
||||||
! [ -e $(ALL_SHARED)/search-index-xxx.js ]
|
! [ -e $(ALL_SHARED)/search-index-xxx.js ]
|
||||||
! [ -e $(ALL_SHARED)/settings.html ]
|
! [ -e $(ALL_SHARED)/settings.html ]
|
||||||
! [ -e $(ALL_SHARED)/x ]
|
! [ -e $(ALL_SHARED)/x ]
|
||||||
! [ -e $(ALL_SHARED)/src ]
|
! [ -e $(ALL_SHARED)/src ]
|
||||||
! [ -e $(ALL_SHARED)/theme.css ]
|
! [ -e $(ALL_SHARED)/theme.css ]
|
||||||
|
|
||||||
[ -e $(ALL_SHARED)/main-xxx.js ]
|
[ -e $(ALL_SHARED)/static.files/main-*.js ]
|
||||||
! [ -e $(ALL_SHARED)/y-xxx.css ]
|
! [ -e $(ALL_SHARED)/y-xxx.css ]
|
||||||
|
|
|
@ -115,8 +115,6 @@ Options:
|
||||||
Provide width of the output for truncated error
|
Provide width of the output for truncated error
|
||||||
messages
|
messages
|
||||||
--json CONFIG Configure the structure of JSON diagnostics
|
--json CONFIG Configure the structure of JSON diagnostics
|
||||||
--disable-minification
|
|
||||||
Disable minification applied on JS files
|
|
||||||
-A, --allow LINT Set lint allowed
|
-A, --allow LINT Set lint allowed
|
||||||
-W, --warn LINT Set lint warnings
|
-W, --warn LINT Set lint warnings
|
||||||
--force-warn LINT
|
--force-warn LINT
|
||||||
|
@ -173,6 +171,8 @@ Options:
|
||||||
--scrape-tests Include test code when scraping examples
|
--scrape-tests Include test code when scraping examples
|
||||||
--with-examples path to function call information (for displaying examples in the documentation)
|
--with-examples path to function call information (for displaying examples in the documentation)
|
||||||
|
|
||||||
|
--disable-minification
|
||||||
|
removed
|
||||||
--plugin-path DIR
|
--plugin-path DIR
|
||||||
removed, see issue #44136
|
removed, see issue #44136
|
||||||
<https://github.com/rust-lang/rust/issues/44136> for
|
<https://github.com/rust-lang/rust/issues/44136> for
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
// compile-flags:-Z unstable-options --static-root-path /cache/
|
// compile-flags:-Z unstable-options --static-root-path /cache/
|
||||||
|
|
||||||
// @has static_root_path/struct.SomeStruct.html
|
// @has static_root_path/struct.SomeStruct.html
|
||||||
// @matchesraw - '"/cache/main\.js"'
|
// @matchesraw - '"/cache/static.files/main-'
|
||||||
// @!matchesraw - '"\.\./main\.js"'
|
// @!matchesraw - '"\.\./main'
|
||||||
// @matchesraw - 'data-root-path="\.\./"'
|
// @matchesraw - 'data-root-path="\.\./"'
|
||||||
// @!matchesraw - '"/cache/search-index\.js"'
|
// @!matchesraw - '"/cache/search-index\.js"'
|
||||||
pub struct SomeStruct;
|
pub struct SomeStruct;
|
||||||
|
|
||||||
// @has src/static_root_path/static-root-path.rs.html
|
// @has src/static_root_path/static-root-path.rs.html
|
||||||
// @matchesraw - '"/cache/source-script\.js"'
|
// @matchesraw - '"/cache/static.files/source-script-'
|
||||||
// @!matchesraw - '"\.\./\.\./source-script\.js"'
|
// @!matchesraw - '"\.\./\.\./source-script'
|
||||||
// @matchesraw - '"\.\./\.\./source-files.js"'
|
// @matchesraw - '"\.\./\.\./source-files.js"'
|
||||||
// @!matchesraw - '"/cache/source-files\.js"'
|
// @!matchesraw - '"/cache/source-files\.js"'
|
||||||
|
|
||||||
// @has settings.html
|
// @has settings.html
|
||||||
// @matchesraw - '/cache/settings\.js'
|
// @matchesraw - '/cache/static.files/settings-'
|
||||||
// @!matchesraw - '\./settings\.js'
|
// @!matchesraw - '\../settings'
|
||||||
|
|
|
@ -307,10 +307,13 @@ function runChecks(testFile, doSearch, parseQuery) {
|
||||||
* `parseQuery` function exported from the search module.
|
* `parseQuery` function exported from the search module.
|
||||||
*/
|
*/
|
||||||
function loadSearchJS(doc_folder, resource_suffix) {
|
function loadSearchJS(doc_folder, resource_suffix) {
|
||||||
const searchJs = path.join(doc_folder, "search" + resource_suffix + ".js");
|
|
||||||
const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js");
|
const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js");
|
||||||
const searchIndex = require(searchIndexJs);
|
const searchIndex = require(searchIndexJs);
|
||||||
const searchModule = require(searchJs);
|
|
||||||
|
const staticFiles = path.join(doc_folder, "static.files");
|
||||||
|
const searchJs = fs.readdirSync(staticFiles).find(
|
||||||
|
f => f.match(/search.*\.js$/));
|
||||||
|
const searchModule = require(path.join(staticFiles, searchJs));
|
||||||
const searchWords = searchModule.initSearch(searchIndex.searchIndex);
|
const searchWords = searchModule.initSearch(searchIndex.searchIndex);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue