1 #![feature(rustc_private)]
3 extern crate rustc_driver;
5 // We use the function we generate from `register_diagnostics!`.
6 use crate::error_codes::error_codes;
10 use std::fs::{self, File};
13 use std::path::PathBuf;
15 use std::str::FromStr;
17 use mdbook::book::{parse_summary, BookItem, Chapter};
18 use mdbook::{Config, MDBook};
20 macro_rules! register_diagnostics {
21 ($($error_code:ident: $message:expr,)+ ; $($undocumented:ident,)* ) => {
22 pub fn error_codes() -> Vec<(&'static str, Option<&'static str>)> {
23 let mut errors: Vec<(&str, Option<&str>)> = vec![
24 $((stringify!($error_code), Some($message)),)+
25 $((stringify!($undocumented), None),)+
33 #[path = "../../../compiler/rustc_error_codes/src/error_codes.rs"]
43 fn from(format: &str) -> OutputFormat {
44 match &*format.to_lowercase() {
45 "html" => OutputFormat::HTML,
46 "markdown" => OutputFormat::Markdown,
47 s => OutputFormat::Unknown(s.to_owned()),
52 /// Output an HTML page for the errors in `err_map` to `output_path`.
53 fn render_markdown(output_path: &Path) -> Result<(), Box<dyn Error>> {
54 let mut output_file = File::create(output_path)?;
56 write!(output_file, "# Rust Compiler Error Index\n")?;
58 for (err_code, description) in error_codes().iter() {
60 Some(ref desc) => write!(output_file, "## {}\n{}\n", err_code, desc)?,
68 // By default, mdbook doesn't consider code blocks as Rust ones contrary to rustdoc so we have
69 // to manually add `rust` attribute whenever needed.
70 fn add_rust_attribute_on_codeblock(explanation: &str) -> String {
71 // Very hacky way to add the rust attribute on all code blocks.
73 explanation.split("\n```").fold(String::new(), |mut acc, part| {
75 acc.push_str("\n```");
78 if let Some(attrs) = part.split('\n').next() {
79 if !attrs.contains("rust")
81 || attrs.contains("compile_fail")
82 || attrs.contains("ignore")
83 || attrs.contains("edition"))
85 if !attrs.is_empty() {
86 acc.push_str("rust,");
99 fn render_html(output_path: &Path) -> Result<(), Box<dyn Error>> {
100 let mut introduction = format!(
101 "<script src='redirect.js'></script>
102 # Rust error codes index
104 This page lists all the error codes emitted by the Rust compiler.
109 let err_codes = error_codes();
110 let mut chapters = Vec::with_capacity(err_codes.len());
112 for (err_code, explanation) in err_codes.iter() {
113 if let Some(explanation) = explanation {
114 introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code));
116 let content = add_rust_attribute_on_codeblock(explanation);
117 chapters.push(BookItem::Chapter(Chapter {
118 name: err_code.to_string(),
119 content: format!("# Error code {}\n\n{}\n", err_code, content),
121 sub_items: Vec::new(),
122 // We generate it into the `error_codes` folder.
123 path: Some(PathBuf::from(&format!("{}.html", err_code))),
125 parent_names: Vec::new(),
128 introduction.push_str(&format!(" * {}\n", err_code));
132 let mut config = Config::from_str(include_str!("book_config.toml"))?;
133 config.build.build_dir = output_path.join("error_codes").to_path_buf();
134 let mut book = MDBook::load_with_config_and_summary(
135 env!("CARGO_MANIFEST_DIR"),
139 let chapter = Chapter {
140 name: "Rust error codes index".to_owned(),
141 content: introduction,
144 // Very important: this file is named as `error-index.html` and not `index.html`!
145 path: Some(PathBuf::from("error-index.html")),
147 parent_names: Vec::new(),
149 book.book.sections.push(BookItem::Chapter(chapter));
152 // We can't put this content into another file, otherwise `mbdbook` will also put it into the
153 // output directory, making a duplicate.
155 output_path.join("error-index.html"),
159 <title>Rust error codes index - Error codes index</title>
160 <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
161 <meta name="description" content="Book listing all Rust error codes">
162 <script src="error_codes/redirect.js"></script>
165 <div>If you are not automatically redirected to the error code index, please <a id="index-link" href="./error_codes/error-index.html">here</a>.
166 <script>document.getElementById("index-link").click()</script>
171 // No need for a 404 file, it's already handled by the server.
172 fs::remove_file(output_path.join("error_codes/404.html"))?;
177 fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
179 OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
180 OutputFormat::HTML => render_html(dst),
181 OutputFormat::Markdown => render_markdown(dst),
185 fn parse_args() -> (OutputFormat, PathBuf) {
186 let mut args = env::args().skip(1);
187 let format = args.next();
188 let dst = args.next();
189 let format = format.map(|a| OutputFormat::from(&a)).unwrap_or(OutputFormat::from("html"));
190 let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format {
191 OutputFormat::HTML => PathBuf::from("doc"),
192 OutputFormat::Markdown => PathBuf::from("doc/error-index.md"),
193 OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
199 rustc_driver::init_env_logger("RUST_LOG");
200 let (format, dst) = parse_args();
201 let result = main_with_result(format, &dst);
202 if let Err(e) = result {