mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-09 13:33:43 +00:00
Rewrite error index generator to greatly reduce the size of the pages
This commit is contained in:
parent
a9bb589cd6
commit
8ad36c45f8
@ -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();
|
||||
}
|
||||
}
|
@ -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>"##
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Formatter for MarkdownFormatter {
|
||||
#[allow(unused_variables)]
|
||||
fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
|
||||
write!(output, "# Rust Compiler Error Index\n")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 => (),
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
|
||||
write!(output, "</body></html>")?;
|
||||
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_markdown(output_path: &Path) -> Result<(), Box<dyn Error>> {
|
||||
let mut output_file = File::create(output_path)?;
|
||||
|
||||
formatter.header(&mut output_file)?;
|
||||
formatter.title(&mut output_file)?;
|
||||
write!(output_file, "# Rust Compiler Error Index\n")?;
|
||||
|
||||
for (err_code, info) in err_map {
|
||||
formatter.error_code_block(&mut output_file, info, err_code)?;
|
||||
for (err_code, description) in error_codes().iter() {
|
||||
match description {
|
||||
Some(ref desc) => write!(output_file, "## {}\n{}\n", err_code, desc)?,
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_html(output_path: &Path, formatter: HTMLFormatter) -> Result<(), Box<dyn Error>> {
|
||||
let mut output_file = File::create(output_path)?;
|
||||
|
||||
let error_codes_dir = "error_codes";
|
||||
|
||||
let parent = output_path.parent().expect("There should have a parent").join(error_codes_dir);
|
||||
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user