1 #![feature(rustc_private)]
3 extern crate rustc_driver;
4 extern crate rustc_span;
6 use std::cell::RefCell;
7 use std::collections::BTreeMap;
13 use std::path::PathBuf;
15 use rustc_span::edition::DEFAULT_EDITION;
17 use rustdoc::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};
19 pub struct ErrorMetadata {
20 pub description: Option<String>,
23 /// Mapping from error codes to metadata that can be (de)serialized.
24 pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;
28 Markdown(MarkdownFormatter),
33 fn from(format: &str, resource_suffix: &str) -> OutputFormat {
34 match &*format.to_lowercase() {
35 "html" => OutputFormat::HTML(HTMLFormatter(
36 RefCell::new(IdMap::new()),
37 resource_suffix.to_owned(),
39 "markdown" => OutputFormat::Markdown(MarkdownFormatter),
40 s => OutputFormat::Unknown(s.to_owned()),
46 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
47 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
50 output: &mut dyn Write,
53 ) -> Result<(), Box<dyn Error>>;
54 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
57 struct HTMLFormatter(RefCell<IdMap>, String);
58 struct MarkdownFormatter;
60 impl Formatter for HTMLFormatter {
61 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
67 <title>Rust Compiler Error Index</title>
68 <meta charset="utf-8">
69 <!-- Include rust.css after light.css so its rules take priority. -->
70 <link rel="stylesheet" type="text/css" href="light{suffix}.css"/>
71 <link rel="stylesheet" type="text/css" href="rust.css"/>
85 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
86 write!(output, "<h1>Rust Compiler Error Index</h1>\n")?;
92 output: &mut dyn Write,
95 ) -> Result<(), Box<dyn Error>> {
96 // Enclose each error in a div so they can be shown/hidden en masse.
97 let desc_desc = match info.description {
98 Some(_) => "error-described",
99 None => "error-undescribed",
101 write!(output, "<div class=\"{}\">", desc_desc)?;
103 // Error title (with self-link).
106 "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
110 // Description rendered as markdown.
111 match info.description {
113 let mut id_map = self.0.borrow_mut();
114 let playground = Playground {
116 url: String::from("https://play.rust-lang.org/"),
132 None => write!(output, "<p>No description.</p>\n")?,
135 write!(output, "</div>\n")?;
139 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
143 function onEach(arr, func) {{
144 if (arr && arr.length > 0 && func) {{
145 for (var i = 0; i < arr.length; i++) {{
151 function hasClass(elem, className) {{
152 if (elem && className && elem.className) {{
153 var elemClass = elem.className;
154 var start = elemClass.indexOf(className);
157 }} else if (elemClass.length === className.length) {{
160 if (start > 0 && elemClass[start - 1] !== ' ') {{
163 var end = start + className.length;
164 if (end < elemClass.length && elemClass[end] !== ' ') {{
169 if (start > 0 && elemClass[start - 1] !== ' ') {{
172 var end = start + className.length;
173 if (end < elemClass.length && elemClass[end] !== ' ') {{
181 onEach(document.getElementsByClassName('rust-example-rendered'), function(e) {{
182 if (hasClass(e, 'compile_fail')) {{
183 e.addEventListener("mouseover", function(event) {{
184 e.previousElementSibling.childNodes[0].style.color = '#f00';
186 e.addEventListener("mouseout", function(event) {{
187 e.previousElementSibling.childNodes[0].style.color = '';
189 }} else if (hasClass(e, 'ignore')) {{
190 e.addEventListener("mouseover", function(event) {{
191 e.previousElementSibling.childNodes[0].style.color = '#ff9200';
193 e.addEventListener("mouseout", function(event) {{
194 e.previousElementSibling.childNodes[0].style.color = '';
206 impl Formatter for MarkdownFormatter {
207 #[allow(unused_variables)]
208 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
212 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
213 write!(output, "# Rust Compiler Error Index\n")?;
219 output: &mut dyn Write,
220 info: &ErrorMetadata,
222 ) -> Result<(), Box<dyn Error>> {
223 Ok(match info.description {
224 Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?,
229 #[allow(unused_variables)]
230 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
235 /// Output an HTML page for the errors in `err_map` to `output_path`.
236 fn render_error_page<T: Formatter>(
237 err_map: &ErrorMetadataMap,
240 ) -> Result<(), Box<dyn Error>> {
241 let mut output_file = File::create(output_path)?;
243 formatter.header(&mut output_file)?;
244 formatter.title(&mut output_file)?;
246 for (err_code, info) in err_map {
247 formatter.error_code_block(&mut output_file, info, err_code)?;
250 formatter.footer(&mut output_file)
253 fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
254 let long_codes = register_all();
255 let mut err_map = BTreeMap::new();
256 for (code, desc) in long_codes {
257 err_map.insert(code.to_string(), ErrorMetadata { description: desc.map(String::from) });
260 OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
261 OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?,
262 OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?,
267 fn parse_args() -> (OutputFormat, PathBuf) {
268 let mut args = env::args().skip(1);
269 let format = args.next();
270 let dst = args.next();
271 let resource_suffix = args.next().unwrap_or_else(String::new);
273 .map(|a| OutputFormat::from(&a, &resource_suffix))
274 .unwrap_or(OutputFormat::from("html", &resource_suffix));
275 let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format {
276 OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
277 OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"),
278 OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
284 rustc_driver::init_env_logger("RUST_LOG");
285 let (format, dst) = parse_args();
286 let result = rustc_span::with_default_session_globals(move || main_with_result(format, &dst));
287 if let Err(e) = result {
288 panic!("{}", e.to_string());
292 include!(concat!(env!("OUT_DIR"), "/error_codes.rs"));