]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
9346a6ac | 11 | use std::default::Default; |
c34b1796 | 12 | use std::fs::File; |
c34b1796 | 13 | use std::io::prelude::*; |
9346a6ac | 14 | use std::io; |
c34b1796 | 15 | use std::path::{PathBuf, Path}; |
1a4d82fc | 16 | |
1a4d82fc JJ |
17 | use getopts; |
18 | use testing; | |
19 | use rustc::session::search_paths::SearchPaths; | |
5bcae85e | 20 | use rustc::session::config::Externs; |
8bb4bdeb | 21 | use syntax::codemap::DUMMY_SP; |
1a4d82fc | 22 | |
c30ab7b3 | 23 | use externalfiles::{ExternalHtml, LoadStringError, load_string}; |
1a4d82fc | 24 | |
92a42be0 | 25 | use html::render::reset_ids; |
1a4d82fc JJ |
26 | use html::escape::Escape; |
27 | use html::markdown; | |
92a42be0 | 28 | use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; |
9346a6ac | 29 | use test::{TestOptions, Collector}; |
1a4d82fc JJ |
30 | |
31 | /// Separate any lines at the start of the file that begin with `%`. | |
32 | fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { | |
33 | let mut metadata = Vec::new(); | |
c1a9b12d | 34 | let mut count = 0; |
1a4d82fc JJ |
35 | for line in s.lines() { |
36 | if line.starts_with("%") { | |
37 | // remove %<whitespace> | |
c1a9b12d SL |
38 | metadata.push(line[1..].trim_left()); |
39 | count += line.len() + 1; | |
1a4d82fc | 40 | } else { |
c1a9b12d | 41 | return (metadata, &s[count..]); |
1a4d82fc JJ |
42 | } |
43 | } | |
44 | // if we're here, then all lines were metadata % lines. | |
45 | (metadata, "") | |
46 | } | |
47 | ||
48 | /// Render `input` (e.g. "foo.md") into an HTML file in `output` | |
49 | /// (e.g. output = "bar" => "bar/foo.html"). | |
c34b1796 AL |
50 | pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, |
51 | external_html: &ExternalHtml, include_toc: bool) -> isize { | |
1a4d82fc | 52 | let input_p = Path::new(input); |
c34b1796 | 53 | output.push(input_p.file_stem().unwrap()); |
1a4d82fc JJ |
54 | output.set_extension("html"); |
55 | ||
56 | let mut css = String::new(); | |
85aaf69f | 57 | for name in &matches.opt_strs("markdown-css") { |
1a4d82fc | 58 | let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name); |
85aaf69f | 59 | css.push_str(&s) |
1a4d82fc JJ |
60 | } |
61 | ||
c30ab7b3 SL |
62 | let input_str = match load_string(input) { |
63 | Ok(s) => s, | |
64 | Err(LoadStringError::ReadFail) => return 1, | |
65 | Err(LoadStringError::BadUtf8) => return 2, | |
66 | }; | |
476ff2be SL |
67 | if let Some(playground) = matches.opt_str("markdown-playground-url").or( |
68 | matches.opt_str("playground-url")) { | |
c30ab7b3 | 69 | markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); }); |
1a4d82fc | 70 | } |
1a4d82fc | 71 | |
c34b1796 | 72 | let mut out = match File::create(&output) { |
1a4d82fc | 73 | Err(e) => { |
c34b1796 | 74 | let _ = writeln!(&mut io::stderr(), |
476ff2be | 75 | "rustdoc: {}: {}", |
1a4d82fc JJ |
76 | output.display(), e); |
77 | return 4; | |
78 | } | |
79 | Ok(f) => f | |
80 | }; | |
81 | ||
85aaf69f | 82 | let (metadata, text) = extract_leading_metadata(&input_str); |
9346a6ac | 83 | if metadata.is_empty() { |
476ff2be SL |
84 | let _ = writeln!( |
85 | &mut io::stderr(), | |
86 | "rustdoc: invalid markdown file: expecting initial line with `% ...TITLE...`" | |
87 | ); | |
1a4d82fc JJ |
88 | return 5; |
89 | } | |
85aaf69f | 90 | let title = metadata[0]; |
1a4d82fc | 91 | |
54a0048b | 92 | reset_ids(false); |
1a4d82fc JJ |
93 | |
94 | let rendered = if include_toc { | |
95 | format!("{}", MarkdownWithToc(text)) | |
96 | } else { | |
97 | format!("{}", Markdown(text)) | |
98 | }; | |
99 | ||
100 | let err = write!( | |
101 | &mut out, | |
102 | r#"<!DOCTYPE html> | |
103 | <html lang="en"> | |
104 | <head> | |
105 | <meta charset="utf-8"> | |
85aaf69f | 106 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
1a4d82fc JJ |
107 | <meta name="generator" content="rustdoc"> |
108 | <title>{title}</title> | |
109 | ||
110 | {css} | |
111 | {in_header} | |
112 | </head> | |
113 | <body class="rustdoc"> | |
114 | <!--[if lte IE 8]> | |
115 | <div class="warning"> | |
116 | This old browser is unsupported and will most likely display funky | |
117 | things. | |
118 | </div> | |
119 | <![endif]--> | |
120 | ||
121 | {before_content} | |
122 | <h1 class="title">{title}</h1> | |
123 | {text} | |
1a4d82fc JJ |
124 | {after_content} |
125 | </body> | |
126 | </html>"#, | |
127 | title = Escape(title), | |
128 | css = css, | |
129 | in_header = external_html.in_header, | |
130 | before_content = external_html.before_content, | |
131 | text = rendered, | |
132 | after_content = external_html.after_content, | |
1a4d82fc JJ |
133 | ); |
134 | ||
135 | match err { | |
136 | Err(e) => { | |
c34b1796 | 137 | let _ = writeln!(&mut io::stderr(), |
476ff2be | 138 | "rustdoc: cannot write to `{}`: {}", |
1a4d82fc JJ |
139 | output.display(), e); |
140 | 6 | |
141 | } | |
142 | Ok(_) => 0 | |
143 | } | |
144 | } | |
145 | ||
146 | /// Run any tests/code examples in the markdown file `input`. | |
5bcae85e | 147 | pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs, |
32a655c1 | 148 | mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>) -> isize { |
c30ab7b3 SL |
149 | let input_str = match load_string(input) { |
150 | Ok(s) => s, | |
151 | Err(LoadStringError::ReadFail) => return 1, | |
152 | Err(LoadStringError::BadUtf8) => return 2, | |
153 | }; | |
1a4d82fc | 154 | |
9346a6ac AL |
155 | let mut opts = TestOptions::default(); |
156 | opts.no_crate_inject = true; | |
92a42be0 | 157 | let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, |
8bb4bdeb XL |
158 | true, opts, maybe_sysroot, None, |
159 | Some(input.to_owned())); | |
160 | find_testable_code(&input_str, &mut collector, DUMMY_SP); | |
1a4d82fc | 161 | test_args.insert(0, "rustdoctest".to_string()); |
85aaf69f | 162 | testing::test_main(&test_args, collector.tests); |
1a4d82fc JJ |
163 | 0 |
164 | } |