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 "# Rust error codes index
103 This page lists all the error codes emitted by the Rust compiler.
108 let err_codes
= error_codes();
109 let mut chapters
= Vec
::with_capacity(err_codes
.len());
111 for (err_code
, explanation
) in err_codes
.iter() {
112 if let Some(explanation
) = explanation
{
113 introduction
.push_str(&format
!(" * [{0}](./{0}.html)\n", err_code
));
115 let content
= add_rust_attribute_on_codeblock(explanation
);
116 chapters
.push(BookItem
::Chapter(Chapter
{
117 name
: err_code
.to_string(),
118 content
: format
!("# Error code {}\n\n{}\n", err_code
, content
),
120 sub_items
: Vec
::new(),
121 // We generate it into the `error_codes` folder.
122 path
: Some(PathBuf
::from(&format
!("{}.html", err_code
))),
124 parent_names
: Vec
::new(),
127 introduction
.push_str(&format
!(" * {}\n", err_code
));
131 let mut config
= Config
::from_str(include_str
!("book_config.toml"))?
;
132 config
.build
.build_dir
= output_path
.join("error_codes").to_path_buf();
133 let mut book
= MDBook
::load_with_config_and_summary(
134 env
!("CARGO_MANIFEST_DIR"),
138 let chapter
= Chapter
{
139 name
: "Rust error codes index".to_owned(),
140 content
: introduction
,
143 // Very important: this file is named as `error-index.html` and not `index.html`!
144 path
: Some(PathBuf
::from("error-index.html")),
146 parent_names
: Vec
::new(),
148 book
.book
.sections
.push(BookItem
::Chapter(chapter
));
151 // The error-index used to be generated manually (without mdbook), and the
152 // index was located at the top level. Now that it is generated with
153 // mdbook, error-index.html has moved to error_codes/error-index.html.
154 // This adds a redirect so that old links go to the new location.
156 // We can't put this content into another file, otherwise `mdbook` will also put it into the
157 // output directory, making a duplicate.
159 output_path
.join("error-index.html"),
163 <title>Rust error codes index - Error codes index</title>
164 <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
165 <meta name="description" content="Book listing all Rust error codes">
166 <script src="error_codes/redirect.js"></script>
169 <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>.
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
{