diff options
| author | Guillaume Gomez <guillaume.gomez@huawei.com> | 2022-08-23 18:27:18 +0200 |
|---|---|---|
| committer | Guillaume Gomez <guillaume.gomez@huawei.com> | 2022-08-23 18:27:18 +0200 |
| commit | 8ad36c45f8116c80cda018e63b9db6862e73a87d (patch) | |
| tree | 73f1d1dd225d856745f3c2b9b58303c47e42854c | |
| parent | a9bb589cd678e034d194193fa892942315b10e2a (diff) | |
| download | rust-8ad36c45f8116c80cda018e63b9db6862e73a87d.tar.gz rust-8ad36c45f8116c80cda018e63b9db6862e73a87d.zip | |
Rewrite error index generator to greatly reduce the size of the pages
| -rw-r--r-- | src/tools/error_index_generator/build.rs | 31 | ||||
| -rw-r--r-- | src/tools/error_index_generator/main.rs | 297 |
2 files changed, 106 insertions, 222 deletions
diff --git a/src/tools/error_index_generator/build.rs b/src/tools/error_index_generator/build.rs deleted file mode 100644 index 70b00b36cf1..00000000000 --- 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/main.rs b/src/tools/error_index_generator/main.rs index 1ce02e48c05..22243f9fc9d 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -3,11 +3,11 @@ extern crate rustc_driver; extern crate rustc_span; -use std::cell::RefCell; -use std::collections::BTreeMap; +use crate::error_codes::error_codes; + use std::env; use std::error::Error; -use std::fs::File; +use std::fs::{create_dir_all, File}; use std::io::Write; use std::path::Path; use std::path::PathBuf; @@ -16,49 +16,81 @@ use rustc_span::edition::DEFAULT_EDITION; use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; -pub struct ErrorMetadata { - pub description: Option<String>, +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<String, ErrorMetadata>; +#[path = "../../../compiler/rustc_error_codes/src/error_codes.rs"] +mod error_codes; enum OutputFormat { HTML(HTMLFormatter), - Markdown(MarkdownFormatter), + Markdown, Unknown(String), } impl OutputFormat { fn from(format: &str, resource_suffix: &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(HTMLFormatter(resource_suffix.to_owned())), + "markdown" => OutputFormat::Markdown, s => OutputFormat::Unknown(s.to_owned()), } } } -trait Formatter { - fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>; - fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>; - fn error_code_block( +struct HTMLFormatter(String); + +impl HTMLFormatter { + fn create_error_code_file( &self, - output: &mut dyn Write, - info: &ErrorMetadata, err_code: &str, - ) -> Result<(), Box<dyn Error>>; - fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>; -} + explanation: &str, + parent_dir: &Path, + ) -> Result<(), Box<dyn Error>> { + let mut output_file = File::create(parent_dir.join(err_code).with_extension("html"))?; -struct HTMLFormatter(RefCell<IdMap>, String); -struct MarkdownFormatter; + self.header(&mut output_file, "../")?; + self.title(&mut output_file, &format!("Error code {}", err_code))?; -impl Formatter for HTMLFormatter { - fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> { + let mut id_map = IdMap::new(); + let playground = + Playground { crate_name: None, url: String::from("https://play.rust-lang.org/") }; + write!( + output_file, + "{}", + Markdown { + content: explanation, + links: &[], + ids: &mut id_map, + error_codes: ErrorCodes::Yes, + edition: DEFAULT_EDITION, + playground: &Some(playground), + heading_offset: HeadingOffset::H1, + } + .into_string() + )?; + write!( + output_file, + "<p>\ + <a style='text-align: center;display: block;width: 100%;' \ + href='../error-index.html'>Back to list of error codes</a>\ + </p>", + )?; + + self.footer(&mut output_file) + } + + fn header(&self, output: &mut dyn Write, extra: &str) -> Result<(), Box<dyn Error>> { write!( output, r##"<!DOCTYPE html> @@ -67,9 +99,9 @@ impl Formatter for HTMLFormatter { <title>Rust Compiler Error Index</title> <meta charset="utf-8"> <!-- Include rust.css after light.css so its rules take priority. --> -<link rel="stylesheet" type="text/css" href="rustdoc{suffix}.css"/> -<link rel="stylesheet" type="text/css" href="light{suffix}.css"/> -<link rel="stylesheet" type="text/css" href="rust.css"/> +<link rel="stylesheet" type="text/css" href="{extra}rustdoc{suffix}.css"/> +<link rel="stylesheet" type="text/css" href="{extra}light{suffix}.css"/> +<link rel="stylesheet" type="text/css" href="{extra}rust.css"/> <style> .error-undescribed {{ display: none; @@ -78,177 +110,80 @@ impl Formatter for HTMLFormatter { </head> <body> "##, - suffix = self.1 + suffix = self.0, )?; Ok(()) } - fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> { - write!(output, "<h1>Rust Compiler Error Index</h1>\n")?; - Ok(()) - } - - fn error_code_block( - &self, - output: &mut dyn Write, - info: &ErrorMetadata, - err_code: &str, - ) -> Result<(), Box<dyn Error>> { - // 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, "<div class=\"{}\">", desc_desc)?; - - // Error title (with self-link). - write!( - output, - "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n", - err_code - )?; - - // 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, - } - .into_string() - )? - } - None => write!(output, "<p>No description.</p>\n")?, - } - - write!(output, "</div>\n")?; + fn title(&self, output: &mut dyn Write, title: &str) -> Result<(), Box<dyn Error>> { + write!(output, "<h1>{}</h1>\n", title)?; Ok(()) } fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> { - write!( - output, - r##"<script> -function onEach(arr, func) {{ - if (arr && arr.length > 0 && func) {{ - var length = arr.length; - var i; - for (i = 0; i < length; ++i) {{ - if (func(arr[i])) {{ - return true; - }} - }} - }} - return false; -}} - -function onEachLazy(lazyArray, func) {{ - return onEach( - Array.prototype.slice.call(lazyArray), - func); -}} - -function hasClass(elem, className) {{ - return elem && elem.classList && elem.classList.contains(className); -}} - -onEachLazy(document.getElementsByClassName('rust-example-rendered'), function(e) {{ - if (hasClass(e, 'compile_fail')) {{ - e.addEventListener("mouseover", function(event) {{ - e.parentElement.previousElementSibling.childNodes[0].style.color = '#f00'; - }}); - e.addEventListener("mouseout", function(event) {{ - e.parentElement.previousElementSibling.childNodes[0].style.color = ''; - }}); - }} else if (hasClass(e, 'ignore')) {{ - e.addEventListener("mouseover", function(event) {{ - e.parentElement.previousElementSibling.childNodes[0].style.color = '#ff9200'; - }}); - e.addEventListener("mouseout", function(event) {{ - e.parentElement.previousElementSibling.childNodes[0].style.color = ''; - }}); - }} -}}); -</script> -</body> -</html>"## - )?; + write!(output, "</body></html>")?; Ok(()) } } -impl Formatter for MarkdownFormatter { - #[allow(unused_variables)] - fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> { - Ok(()) - } +/// Output an HTML page for the errors in `err_map` to `output_path`. +fn render_markdown(output_path: &Path) -> Result<(), Box<dyn Error>> { + let mut output_file = File::create(output_path)?; - fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> { - write!(output, "# Rust Compiler Error Index\n")?; - Ok(()) - } + write!(output_file, "# Rust Compiler Error Index\n")?; - fn error_code_block( - &self, - output: &mut dyn Write, - info: &ErrorMetadata, - err_code: &str, - ) -> Result<(), Box<dyn Error>> { - Ok(match info.description { - Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?, - None => (), - }) + for (err_code, description) in error_codes().iter() { + match description { + Some(ref desc) => write!(output_file, "## {}\n{}\n", err_code, desc)?, + None => {} + } } - #[allow(unused_variables)] - fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> { - Ok(()) - } + Ok(()) } -/// Output an HTML page for the errors in `err_map` to `output_path`. -fn render_error_page<T: Formatter>( - err_map: &ErrorMetadataMap, - output_path: &Path, - formatter: T, -) -> Result<(), Box<dyn Error>> { +fn render_html(output_path: &Path, formatter: HTMLFormatter) -> Result<(), Box<dyn Error>> { let mut output_file = File::create(output_path)?; - formatter.header(&mut output_file)?; - formatter.title(&mut output_file)?; + let error_codes_dir = "error_codes"; + + let parent = output_path.parent().expect("There should have a parent").join(error_codes_dir); - for (err_code, info) in err_map { - formatter.error_code_block(&mut output_file, info, err_code)?; + if !parent.exists() { + create_dir_all(&parent)?; } + formatter.header(&mut output_file, "")?; + formatter.title(&mut output_file, "Rust Compiler Error Index")?; + + write!( + output_file, + "<p>This page lists all the error codes emitted by the Rust compiler. If you want a full \ + explanation on an error code, click on it.</p>\ + <ul>", + )?; + for (err_code, explanation) in error_codes().iter() { + if let Some(explanation) = explanation { + write!( + output_file, + "<li><a href='./{0}/{1}.html'>{1}</a></li>", + error_codes_dir, err_code + )?; + formatter.create_error_code_file(err_code, explanation, &parent)?; + } else { + write!(output_file, "<li>{}</li>", err_code)?; + } + } + write!(output_file, "</ul>")?; formatter.footer(&mut output_file) } fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> { - 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(h) => render_html(dst, h), + OutputFormat::Markdown => render_markdown(dst), } - Ok(()) } fn parse_args() -> (OutputFormat, PathBuf) { @@ -261,7 +196,7 @@ fn parse_args() -> (OutputFormat, PathBuf) { .unwrap_or(OutputFormat::from("html", &resource_suffix)); 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::Markdown => PathBuf::from("doc/error-index.md"), OutputFormat::Unknown(..) => PathBuf::from("<nul>"), }); (format, dst) @@ -276,23 +211,3 @@ fn main() { 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::<Vec<_>>());} - )* - ) - } - include!(concat!(env!("OUT_DIR"), "/all_error_codes.rs")); - long_codes -} |
