1 #![feature(rustc_private)]
4 extern crate env_logger;
7 use std::collections::BTreeMap;
13 use std::path::PathBuf;
14 use std::cell::RefCell;
16 use syntax::edition::DEFAULT_EDITION;
18 use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, Playground};
20 pub struct ErrorMetadata {
21 pub description: Option<String>,
24 /// Mapping from error codes to metadata that can be (de)serialized.
25 pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;
29 Markdown(MarkdownFormatter),
34 fn from(format: &str, resource_suffix: &str) -> OutputFormat {
35 match &*format.to_lowercase() {
36 "html" => OutputFormat::HTML(HTMLFormatter(RefCell::new(IdMap::new()),
37 resource_suffix.to_owned())),
38 "markdown" => OutputFormat::Markdown(MarkdownFormatter),
39 s => OutputFormat::Unknown(s.to_owned()),
45 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
46 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
47 fn error_code_block(&self, output: &mut dyn Write, info: &ErrorMetadata,
48 err_code: &str) -> Result<(), Box<dyn Error>>;
49 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
52 struct HTMLFormatter(RefCell<IdMap>, String);
53 struct MarkdownFormatter;
55 impl Formatter for HTMLFormatter {
56 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
57 write!(output, r##"<!DOCTYPE html>
60 <title>Rust Compiler Error Index</title>
61 <meta charset="utf-8">
62 <!-- Include rust.css after light.css so its rules take priority. -->
63 <link rel="stylesheet" type="text/css" href="light{suffix}.css"/>
64 <link rel="stylesheet" type="text/css" href="rust.css"/>
76 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
77 write!(output, "<h1>Rust Compiler Error Index</h1>\n")?;
81 fn error_code_block(&self, output: &mut dyn Write, info: &ErrorMetadata,
82 err_code: &str) -> Result<(), Box<dyn Error>> {
83 // Enclose each error in a div so they can be shown/hidden en masse.
84 let desc_desc = match info.description {
85 Some(_) => "error-described",
86 None => "error-undescribed",
88 write!(output, "<div class=\"{}\">", desc_desc)?;
90 // Error title (with self-link).
92 "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
95 // Description rendered as markdown.
96 match info.description {
98 let mut id_map = self.0.borrow_mut();
99 let playground = Playground {
101 url: String::from("https://play.rust-lang.org/"),
104 Markdown(desc, &[], &mut id_map,
105 ErrorCodes::Yes, DEFAULT_EDITION, &Some(playground)).to_string())?
107 None => write!(output, "<p>No description.</p>\n")?,
110 write!(output, "</div>\n")?;
114 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
115 write!(output, r##"<script>
116 function onEach(arr, func) {{
117 if (arr && arr.length > 0 && func) {{
118 for (var i = 0; i < arr.length; i++) {{
124 function hasClass(elem, className) {{
125 if (elem && className && elem.className) {{
126 var elemClass = elem.className;
127 var start = elemClass.indexOf(className);
130 }} else if (elemClass.length === className.length) {{
133 if (start > 0 && elemClass[start - 1] !== ' ') {{
136 var end = start + className.length;
137 if (end < elemClass.length && elemClass[end] !== ' ') {{
142 if (start > 0 && elemClass[start - 1] !== ' ') {{
145 var end = start + className.length;
146 if (end < elemClass.length && elemClass[end] !== ' ') {{
154 onEach(document.getElementsByClassName('rust-example-rendered'), function(e) {{
155 if (hasClass(e, 'compile_fail')) {{
156 e.addEventListener("mouseover", function(event) {{
157 e.previousElementSibling.childNodes[0].style.color = '#f00';
159 e.addEventListener("mouseout", function(event) {{
160 e.previousElementSibling.childNodes[0].style.color = '';
162 }} else if (hasClass(e, 'ignore')) {{
163 e.addEventListener("mouseover", function(event) {{
164 e.previousElementSibling.childNodes[0].style.color = '#ff9200';
166 e.addEventListener("mouseout", function(event) {{
167 e.previousElementSibling.childNodes[0].style.color = '';
178 impl Formatter for MarkdownFormatter {
179 #[allow(unused_variables)]
180 fn header(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
184 fn title(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
185 write!(output, "# Rust Compiler Error Index\n")?;
189 fn error_code_block(&self, output: &mut dyn Write, info: &ErrorMetadata,
190 err_code: &str) -> Result<(), Box<dyn Error>> {
191 Ok(match info.description {
192 Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?,
197 #[allow(unused_variables)]
198 fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
203 /// Output an HTML page for the errors in `err_map` to `output_path`.
204 fn render_error_page<T: Formatter>(err_map: &ErrorMetadataMap, output_path: &Path,
205 formatter: T) -> Result<(), Box<dyn Error>> {
206 let mut output_file = File::create(output_path)?;
208 formatter.header(&mut output_file)?;
209 formatter.title(&mut output_file)?;
211 for (err_code, info) in err_map {
212 formatter.error_code_block(&mut output_file, info, err_code)?;
215 formatter.footer(&mut output_file)
218 fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
219 let long_codes = register_all();
220 let mut err_map = BTreeMap::new();
221 for (code, desc) in long_codes {
222 err_map.insert(code.to_string(), ErrorMetadata {
223 description: desc.map(String::from),
227 OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
228 OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?,
229 OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?,
234 fn parse_args() -> (OutputFormat, PathBuf) {
235 let mut args = env::args().skip(1);
236 let format = args.next();
237 let dst = args.next();
238 let resource_suffix = args.next().unwrap_or_else(String::new);
239 let format = format.map(|a| OutputFormat::from(&a, &resource_suffix))
240 .unwrap_or(OutputFormat::from("html", &resource_suffix));
241 let dst = dst.map(PathBuf::from).unwrap_or_else(|| {
243 OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
244 OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"),
245 OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
253 let (format, dst) = parse_args();
254 let result = syntax::with_default_globals(move || {
255 main_with_result(format, &dst)
257 if let Err(e) = result {
258 panic!("{}", e.description());
262 include!(concat!(env!("OUT_DIR"), "/error_codes.rs"));