From 17d40c6057c88f4c432b0d7bac88e1b84cb7e67f Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:03:36 +0200 Subject: Adding upstream version 1.65.0+dfsg1. Signed-off-by: Daniel Baumann --- src/tools/error_index_generator/Cargo.toml | 5 +- src/tools/error_index_generator/book_config.toml | 19 ++ src/tools/error_index_generator/build.rs | 31 -- src/tools/error_index_generator/error-index.css | 38 +++ src/tools/error_index_generator/error-index.js | 9 + src/tools/error_index_generator/main.rs | 377 +++++++++-------------- src/tools/error_index_generator/redirect.js | 16 + 7 files changed, 225 insertions(+), 270 deletions(-) create mode 100644 src/tools/error_index_generator/book_config.toml delete mode 100644 src/tools/error_index_generator/build.rs create mode 100644 src/tools/error_index_generator/error-index.css create mode 100644 src/tools/error_index_generator/error-index.js create mode 100644 src/tools/error_index_generator/redirect.js (limited to 'src/tools/error_index_generator') diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml index c84b79e11..f4dac6e94 100644 --- a/src/tools/error_index_generator/Cargo.toml +++ b/src/tools/error_index_generator/Cargo.toml @@ -4,10 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] -rustdoc = { path = "../../librustdoc" } - -[build-dependencies] -walkdir = "2" +mdbook = { version = "0.4", default-features = false, features = ["search"] } [[bin]] name = "error_index_generator" diff --git a/src/tools/error_index_generator/book_config.toml b/src/tools/error_index_generator/book_config.toml new file mode 100644 index 000000000..885100ae3 --- /dev/null +++ b/src/tools/error_index_generator/book_config.toml @@ -0,0 +1,19 @@ +[book] +title = "Error codes index" +description = "Book listing all Rust error codes" +src = "" + +[output.html] +git-repository-url = "https://github.com/rust-lang/rust/" +additional-css = ["error-index.css"] +additional-js = ["error-index.js"] + +[output.html.search] +enable = true +limit-results = 20 +use-boolean-and = true +boost-title = 2 +boost-hierarchy = 2 +boost-paragraph = 1 +expand = true +heading-split-level = 0 diff --git a/src/tools/error_index_generator/build.rs b/src/tools/error_index_generator/build.rs deleted file mode 100644 index 70b00b36c..000000000 --- a/src/tools/error_index_generator/build.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::path::PathBuf; -use std::{env, fs}; -use walkdir::WalkDir; - -fn main() { - // The src directory (we are in src/tools/error_index_generator) - // Note that we could skip one of the .. but this ensures we at least loosely find the right - // directory. - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - - let error_codes_path = "../../../compiler/rustc_error_codes/src/error_codes.rs"; - - println!("cargo:rerun-if-changed={}", error_codes_path); - let file = fs::read_to_string(error_codes_path) - .unwrap() - .replace(": include_str!(\"./error_codes/", ": include_str!(\"./"); - let contents = format!("(|| {{\n{}\n}})()", file); - fs::write(&out_dir.join("all_error_codes.rs"), &contents).unwrap(); - - // We copy the md files as well to the target directory. - for entry in WalkDir::new("../../../compiler/rustc_error_codes/src/error_codes") { - let entry = entry.unwrap(); - match entry.path().extension() { - Some(s) if s == "md" => {} - _ => continue, - } - println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap()); - let md_content = fs::read_to_string(entry.path()).unwrap(); - fs::write(&out_dir.join(entry.file_name()), &md_content).unwrap(); - } -} diff --git a/src/tools/error_index_generator/error-index.css b/src/tools/error_index_generator/error-index.css new file mode 100644 index 000000000..8975af82d --- /dev/null +++ b/src/tools/error_index_generator/error-index.css @@ -0,0 +1,38 @@ +code.compile_fail { + border-left: 2px solid red; +} + +pre .tooltip { + position: absolute; + left: -25px; + top: 0; + z-index: 1; + color: red; + cursor: pointer; +} +pre .tooltip::after { + display: none; + content: "This example deliberately fails to compile"; + background-color: #000; + color: #fff; + border-color: #000; + text-align: center; + padding: 5px 3px 3px 3px; + border-radius: 6px; + margin-left: 5px; +} +pre .tooltip::before { + display: none; + border-color: transparent black transparent transparent; + content: " "; + position: absolute; + top: 50%; + left: 16px; + margin-top: -5px; + border-width: 5px; + border-style: solid; +} + +pre .tooltip:hover::before, pre .tooltip:hover::after { + display: inline; +} diff --git a/src/tools/error_index_generator/error-index.js b/src/tools/error_index_generator/error-index.js new file mode 100644 index 000000000..39b371be0 --- /dev/null +++ b/src/tools/error_index_generator/error-index.js @@ -0,0 +1,9 @@ +for (const elem of document.querySelectorAll("pre.playground")) { + if (elem.querySelector(".compile_fail") === null) { + continue; + } + const child = document.createElement("div"); + child.className = "tooltip"; + child.textContent = "ⓘ"; + elem.appendChild(child); +} diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 1ce02e48c..1bde8e007 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -1,267 +1,195 @@ #![feature(rustc_private)] extern crate rustc_driver; -extern crate rustc_span; -use std::cell::RefCell; -use std::collections::BTreeMap; +// We use the function we generate from `register_diagnostics!`. +use crate::error_codes::error_codes; + use std::env; use std::error::Error; -use std::fs::File; +use std::fs::{self, File}; use std::io::Write; use std::path::Path; use std::path::PathBuf; -use rustc_span::edition::DEFAULT_EDITION; +use std::str::FromStr; -use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; +use mdbook::book::{parse_summary, BookItem, Chapter}; +use mdbook::{Config, MDBook}; -pub struct ErrorMetadata { - pub description: Option, +macro_rules! register_diagnostics { + ($($error_code:ident: $message:expr,)+ ; $($undocumented:ident,)* ) => { + pub fn error_codes() -> Vec<(&'static str, Option<&'static str>)> { + let mut errors: Vec<(&str, Option<&str>)> = vec![ + $((stringify!($error_code), Some($message)),)+ + $((stringify!($undocumented), None),)+ + ]; + errors.sort(); + errors + } + } } -/// Mapping from error codes to metadata that can be (de)serialized. -pub type ErrorMetadataMap = BTreeMap; +#[path = "../../../compiler/rustc_error_codes/src/error_codes.rs"] +mod error_codes; enum OutputFormat { - HTML(HTMLFormatter), - Markdown(MarkdownFormatter), + HTML, + Markdown, Unknown(String), } impl OutputFormat { - fn from(format: &str, resource_suffix: &str) -> OutputFormat { + fn from(format: &str) -> OutputFormat { match &*format.to_lowercase() { - "html" => OutputFormat::HTML(HTMLFormatter( - RefCell::new(IdMap::new()), - resource_suffix.to_owned(), - )), - "markdown" => OutputFormat::Markdown(MarkdownFormatter), + "html" => OutputFormat::HTML, + "markdown" => OutputFormat::Markdown, s => OutputFormat::Unknown(s.to_owned()), } } } -trait Formatter { - fn header(&self, output: &mut dyn Write) -> Result<(), Box>; - fn title(&self, output: &mut dyn Write) -> Result<(), Box>; - fn error_code_block( - &self, - output: &mut dyn Write, - info: &ErrorMetadata, - err_code: &str, - ) -> Result<(), Box>; - fn footer(&self, output: &mut dyn Write) -> Result<(), Box>; -} - -struct HTMLFormatter(RefCell, String); -struct MarkdownFormatter; +/// Output an HTML page for the errors in `err_map` to `output_path`. +fn render_markdown(output_path: &Path) -> Result<(), Box> { + let mut output_file = File::create(output_path)?; -impl Formatter for HTMLFormatter { - fn header(&self, output: &mut dyn Write) -> Result<(), Box> { - write!( - output, - r##" - - -Rust Compiler Error Index - - - - - - - - -"##, - suffix = self.1 - )?; - Ok(()) - } + write!(output_file, "# Rust Compiler Error Index\n")?; - fn title(&self, output: &mut dyn Write) -> Result<(), Box> { - write!(output, "

Rust Compiler Error Index

\n")?; - Ok(()) + for (err_code, description) in error_codes().iter() { + match description { + Some(ref desc) => write!(output_file, "## {}\n{}\n", err_code, desc)?, + None => {} + } } - fn error_code_block( - &self, - output: &mut dyn Write, - info: &ErrorMetadata, - err_code: &str, - ) -> Result<(), Box> { - // Enclose each error in a div so they can be shown/hidden en masse. - let desc_desc = match info.description { - Some(_) => "error-described", - None => "error-undescribed", - }; - write!(output, "
", desc_desc)?; - - // Error title (with self-link). - write!( - output, - "

{0}

\n", - err_code - )?; + Ok(()) +} - // Description rendered as markdown. - match info.description { - Some(ref desc) => { - let mut id_map = self.0.borrow_mut(); - let playground = Playground { - crate_name: None, - url: String::from("https://play.rust-lang.org/"), - }; - write!( - output, - "{}", - Markdown { - content: desc, - links: &[], - ids: &mut id_map, - error_codes: ErrorCodes::Yes, - edition: DEFAULT_EDITION, - playground: &Some(playground), - heading_offset: HeadingOffset::H1, +// By default, mdbook doesn't consider code blocks as Rust ones contrary to rustdoc so we have +// to manually add `rust` attribute whenever needed. +fn add_rust_attribute_on_codeblock(explanation: &str) -> String { + // Very hacky way to add the rust attribute on all code blocks. + let mut skip = true; + explanation.split("\n```").fold(String::new(), |mut acc, part| { + if !acc.is_empty() { + acc.push_str("\n```"); + } + if !skip { + if let Some(attrs) = part.split('\n').next() { + if !attrs.contains("rust") + && (attrs.is_empty() + || attrs.contains("compile_fail") + || attrs.contains("ignore") + || attrs.contains("edition")) + { + if !attrs.is_empty() { + acc.push_str("rust,"); + } else { + acc.push_str("rust"); } - .into_string() - )? + } } - None => write!(output, "

No description.

\n")?, } - - write!(output, "
\n")?; - Ok(()) - } - - fn footer(&self, output: &mut dyn Write) -> Result<(), Box> { - write!( - output, - r##" - -"## - )?; - Ok(()) - } + skip = !skip; + acc.push_str(part); + acc + }) } -impl Formatter for MarkdownFormatter { - #[allow(unused_variables)] - fn header(&self, output: &mut dyn Write) -> Result<(), Box> { - Ok(()) - } - - fn title(&self, output: &mut dyn Write) -> Result<(), Box> { - write!(output, "# Rust Compiler Error Index\n")?; - Ok(()) - } - - fn error_code_block( - &self, - output: &mut dyn Write, - info: &ErrorMetadata, - err_code: &str, - ) -> Result<(), Box> { - Ok(match info.description { - Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?, - None => (), - }) - } - - #[allow(unused_variables)] - fn footer(&self, output: &mut dyn Write) -> Result<(), Box> { - Ok(()) +fn render_html(output_path: &Path) -> Result<(), Box> { + let mut introduction = format!( + " +# Rust error codes index + +This page lists all the error codes emitted by the Rust compiler. + +" + ); + + let err_codes = error_codes(); + let mut chapters = Vec::with_capacity(err_codes.len()); + + for (err_code, explanation) in err_codes.iter() { + if let Some(explanation) = explanation { + introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code)); + + let content = add_rust_attribute_on_codeblock(explanation); + chapters.push(BookItem::Chapter(Chapter { + name: err_code.to_string(), + content: format!("# Error code {}\n\n{}\n", err_code, content), + number: None, + sub_items: Vec::new(), + // We generate it into the `error_codes` folder. + path: Some(PathBuf::from(&format!("{}.html", err_code))), + source_path: None, + parent_names: Vec::new(), + })); + } else { + introduction.push_str(&format!(" * {}\n", err_code)); + } } -} - -/// Output an HTML page for the errors in `err_map` to `output_path`. -fn render_error_page( - err_map: &ErrorMetadataMap, - output_path: &Path, - formatter: T, -) -> Result<(), Box> { - let mut output_file = File::create(output_path)?; - - formatter.header(&mut output_file)?; - formatter.title(&mut output_file)?; - for (err_code, info) in err_map { - formatter.error_code_block(&mut output_file, info, err_code)?; - } + let mut config = Config::from_str(include_str!("book_config.toml"))?; + config.build.build_dir = output_path.join("error_codes").to_path_buf(); + let mut book = MDBook::load_with_config_and_summary( + env!("CARGO_MANIFEST_DIR"), + config, + parse_summary("")?, + )?; + let chapter = Chapter { + name: "Rust error codes index".to_owned(), + content: introduction, + number: None, + sub_items: chapters, + // Very important: this file is named as `error-index.html` and not `index.html`! + path: Some(PathBuf::from("error-index.html")), + source_path: None, + parent_names: Vec::new(), + }; + book.book.sections.push(BookItem::Chapter(chapter)); + book.build()?; + + // We can't put this content into another file, otherwise `mbdbook` will also put it into the + // output directory, making a duplicate. + fs::write( + output_path.join("error-index.html"), + r#" + + + Rust error codes index - Error codes index + + + + + +
If you are not automatically redirected to the error code index, please here. + + +"#, + )?; + + // No need for a 404 file, it's already handled by the server. + fs::remove_file(output_path.join("error_codes/404.html"))?; - formatter.footer(&mut output_file) + Ok(()) } fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box> { - let long_codes = register_all(); - let mut err_map = BTreeMap::new(); - for (code, desc) in long_codes { - err_map.insert(code.to_string(), ErrorMetadata { description: desc.map(String::from) }); - } match format { OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s), - OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?, - OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?, + OutputFormat::HTML => render_html(dst), + OutputFormat::Markdown => render_markdown(dst), } - Ok(()) } fn parse_args() -> (OutputFormat, PathBuf) { let mut args = env::args().skip(1); let format = args.next(); let dst = args.next(); - let resource_suffix = args.next().unwrap_or_else(String::new); - let format = format - .map(|a| OutputFormat::from(&a, &resource_suffix)) - .unwrap_or(OutputFormat::from("html", &resource_suffix)); + let format = format.map(|a| OutputFormat::from(&a)).unwrap_or(OutputFormat::from("html")); let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format { - OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"), - OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"), + OutputFormat::HTML => PathBuf::from("doc"), + OutputFormat::Markdown => PathBuf::from("doc/error-index.md"), OutputFormat::Unknown(..) => PathBuf::from(""), }); (format, dst) @@ -270,29 +198,8 @@ fn parse_args() -> (OutputFormat, PathBuf) { fn main() { rustc_driver::init_env_logger("RUST_LOG"); let (format, dst) = parse_args(); - let result = - rustc_span::create_default_session_globals_then(move || main_with_result(format, &dst)); + let result = main_with_result(format, &dst); if let Err(e) = result { - panic!("{}", e.to_string()); - } -} - -fn register_all() -> Vec<(&'static str, Option<&'static str>)> { - let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new(); - macro_rules! register_diagnostics { - ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => ( - $( - {long_codes.extend([ - (stringify!($ecode), Some($message)), - ].iter());} - )* - $( - {long_codes.extend([ - stringify!($code), - ].iter().cloned().map(|s| (s, None)).collect::>());} - )* - ) + panic!("{:?}", e); } - include!(concat!(env!("OUT_DIR"), "/all_error_codes.rs")); - long_codes } diff --git a/src/tools/error_index_generator/redirect.js b/src/tools/error_index_generator/redirect.js new file mode 100644 index 000000000..8c907f579 --- /dev/null +++ b/src/tools/error_index_generator/redirect.js @@ -0,0 +1,16 @@ +(function() { + if (window.location.hash) { + let code = window.location.hash.replace(/^#/, ''); + // We have to make sure this pattern matches to avoid inadvertently creating an + // open redirect. + if (!/^E[0-9]+$/.test(code)) { + return; + } + if (window.location.pathname.indexOf("/error_codes/") !== -1) { + // We're not at the top level, so we don't prepend with "./error_codes/". + window.location = './' + code + '.html'; + } else { + window.location = './error_codes/' + code + '.html'; + } + } +})() -- cgit v1.2.3