use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; use errors; use testing; use syntax::edition::Edition; use syntax::source_map::DUMMY_SP; use rustc_feature::UnstableFeatures; use crate::externalfiles::{LoadStringError, load_string}; use crate::config::{Options, RenderOptions}; use crate::html::escape::Escape; use crate::html::markdown; use crate::html::markdown::{ErrorCodes, IdMap, Markdown, MarkdownWithToc, find_testable_code}; use crate::test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { let mut metadata = Vec::new(); let mut count = 0; for line in s.lines() { if line.starts_with("# ") || line.starts_with("%") { // trim the whitespace after the symbol metadata.push(line[1..].trim_start()); count += line.len() + 1; } else { return (metadata, &s[count..]); } } // if we're here, then all lines were metadata `# ` or `%` lines. (metadata, "") } /// Render `input` (e.g., "foo.md") into an HTML file in `output` /// (e.g., output = "bar" => "bar/foo.html"). pub fn render( input: PathBuf, options: RenderOptions, diag: &errors::Handler, edition: Edition ) -> i32 { let mut output = options.output; output.push(input.file_name().unwrap()); output.set_extension("html"); let mut css = String::new(); for name in &options.markdown_css { let s = format!("\n", name); css.push_str(&s) } let input_str = match load_string(&input, diag) { Ok(s) => s, Err(LoadStringError::ReadFail) => return 1, Err(LoadStringError::BadUtf8) => return 2, }; let playground_url = options.markdown_playground_url .or(options.playground_url); let playground = playground_url.map(|url| markdown::Playground { crate_name: None, url, }); let mut out = match File::create(&output) { Err(e) => { diag.struct_err(&format!("{}: {}", output.display(), e)).emit(); return 4; } Ok(f) => f, }; let (metadata, text) = extract_leading_metadata(&input_str); if metadata.is_empty() { diag.struct_err("invalid markdown file: no initial lines starting with `# ` or `%`").emit(); return 5; } let title = metadata[0]; let mut ids = IdMap::new(); let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); let text = if !options.markdown_no_toc { MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).to_string() } else { Markdown(text, &[], &mut ids, error_codes, edition, &playground).to_string() }; let err = write!( &mut out, r#"