about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-06-30 07:31:29 +0000
committerbors <bors@rust-lang.org>2014-06-30 07:31:29 +0000
commit2735c7bb104d0938bccd261c5ea0d083f05ceba5 (patch)
treeb17bfa5031a983fc6fcb2cd4f6548d728773261e
parente1683f50c00297e9908ae028fa1d41b9a52a6f6f (diff)
parent63afc082629044755df0c416ecf4c20ef0375254 (diff)
downloadrust-2735c7bb104d0938bccd261c5ea0d083f05ceba5.tar.gz
rust-2735c7bb104d0938bccd261c5ea0d083f05ceba5.zip
auto merge of #15237 : zzmp/rust/feat/markdown-in-crate-documentation, r=huonw
This makes the `in-header`, `markdown-before-content`, and `markdown-after-content` options available to `rustdoc` when generating documentation for any crate.

Before, these options were only available when creating documentation *from* markdown. Now, they are available when generating documentation from source.

This also updates the `rustdoc -h` output to reflect these changes. It does not update the `man rustdoc` page, nor does it update the documentation in [the `rustdoc` manual](http://doc.rust-lang.org/rustdoc.html).
-rw-r--r--man/rustdoc.19
-rw-r--r--mk/docs.mk8
-rw-r--r--src/doc/rustdoc.md19
-rw-r--r--src/librustdoc/externalfiles.rs70
-rw-r--r--src/librustdoc/html/layout.rs11
-rw-r--r--src/librustdoc/html/render.rs8
-rw-r--r--src/librustdoc/lib.rs28
-rw-r--r--src/librustdoc/markdown.rs59
8 files changed, 143 insertions, 69 deletions
diff --git a/man/rustdoc.1 b/man/rustdoc.1
index 82b7ee27b94..d5795c328e7 100644
--- a/man/rustdoc.1
+++ b/man/rustdoc.1
@@ -38,6 +38,15 @@ directory to load plugins from (default: /tmp/rustdoc_ng/plugins)
 -L --library-path <val>
 directory to add to crate search path
 .TP
+--html-in-header <val>
+file to add to <head>
+.TP
+--html-before-content <val>
+file to add in <body>, before content
+.TP
+--html-after-content <val>
+file to add in <body>, after content
+.TP
 -h, --help
 Print help
 
diff --git a/mk/docs.mk b/mk/docs.mk
index 8098a0682a5..213565b09ac 100644
--- a/mk/docs.mk
+++ b/mk/docs.mk
@@ -35,16 +35,16 @@ DOCS := index intro tutorial guide guide-ffi guide-macros guide-lifetimes \
 PDF_DOCS := tutorial rust
 
 RUSTDOC_DEPS_rust := doc/full-toc.inc
-RUSTDOC_FLAGS_rust := --markdown-in-header=doc/full-toc.inc
+RUSTDOC_FLAGS_rust := --html-in-header=doc/full-toc.inc
 
 L10N_LANGS := ja
 
 # Generally no need to edit below here.
 
 # The options are passed to the documentation generators.
-RUSTDOC_HTML_OPTS_NO_CSS = --markdown-before-content=doc/version_info.html \
-	--markdown-in-header=doc/favicon.inc \
-	--markdown-after-content=doc/footer.inc \
+RUSTDOC_HTML_OPTS_NO_CSS = --html-before-content=doc/version_info.html \
+	--html-in-header=doc/favicon.inc \
+	--html-after-content=doc/footer.inc \
 	--markdown-playground-url='http://play.rust-lang.org/'
 
 RUSTDOC_HTML_OPTS = $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css rust.css
diff --git a/src/doc/rustdoc.md b/src/doc/rustdoc.md
index 2287bcabff7..8199eaea82c 100644
--- a/src/doc/rustdoc.md
+++ b/src/doc/rustdoc.md
@@ -103,6 +103,17 @@ rustdoc can also generate JSON, for consumption by other tools, with
 `rustdoc --output-format json`, and also consume already-generated JSON with
 `rustdoc --input-format json`.
 
+rustdoc also supports personalizing the output from crates' documentation,
+similar to markdown options.
+
+- `--html-in-header FILE`: includes the contents of `FILE` at the
+  end of the `<head>...</head>` section.
+- `--html-before-content FILE`: includes the contents of `FILE`
+  directly after `<body>`, before the rendered content (including the
+  search bar).
+- `--html-after-content FILE`: includes the contents of `FILE`
+  after all the rendered content.
+
 # Using the Documentation
 
 The web pages generated by rustdoc present the same logical hierarchy that one
@@ -238,16 +249,16 @@ detected by a `.md` or `.markdown` extension.
 There are 4 options to modify the output that Rustdoc creates.
 
 - `--markdown-css PATH`: adds a `<link rel="stylesheet">` tag pointing to `PATH`.
-- `--markdown-in-header FILE`: includes the contents of `FILE` at the
+- `--html-in-header FILE`: includes the contents of `FILE` at the
   end of the `<head>...</head>` section.
-- `--markdown-before-content FILE`: includes the contents of `FILE`
+- `--html-before-content FILE`: includes the contents of `FILE`
   directly after `<body>`, before the rendered content (including the
   title).
-- `--markdown-after-content FILE`: includes the contents of `FILE`
+- `--html-after-content FILE`: includes the contents of `FILE`
   directly before `</body>`, after all the rendered content.
 
 All of these can be specified multiple times, and they are output in
-the order in which they are specified. The first line of the file must
+the order in which they are specified. The first line of the file being rendered must
 be the title, prefixed with `%` (e.g. this page has `% Rust
 Documentation` on the first line).
 
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
new file mode 100644
index 00000000000..0931f132c02
--- /dev/null
+++ b/src/librustdoc/externalfiles.rs
@@ -0,0 +1,70 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::{io, str};
+
+#[deriving(Clone)]
+pub struct ExternalHtml{
+    pub in_header: String,
+    pub before_content: String,
+    pub after_content: String
+}
+
+impl ExternalHtml {
+    pub fn load(in_header: &[String], before_content: &[String], after_content: &[String])
+            -> Option<ExternalHtml> {
+        match (load_external_files(in_header),
+               load_external_files(before_content),
+               load_external_files(after_content)) {
+            (Some(ih), Some(bc), Some(ac)) => Some(ExternalHtml {
+                in_header: ih,
+                before_content: bc,
+                after_content: ac
+            }),
+            _ => None
+        }
+    }
+}
+
+pub fn load_string(input: &Path) -> io::IoResult<Option<String>> {
+    let mut f = try!(io::File::open(input));
+    let d = try!(f.read_to_end());
+    Ok(str::from_utf8(d.as_slice()).map(|s| s.to_string()))
+}
+
+macro_rules! load_or_return {
+    ($input: expr, $cant_read: expr, $not_utf8: expr) => {
+        {
+            let input = Path::new($input);
+            match ::externalfiles::load_string(&input) {
+                Err(e) => {
+                    let _ = writeln!(&mut io::stderr(),
+                                     "error reading `{}`: {}", input.display(), e);
+                    return $cant_read;
+                }
+                Ok(None) => {
+                    let _ = writeln!(&mut io::stderr(),
+                                     "error reading `{}`: not UTF-8", input.display());
+                    return $not_utf8;
+                }
+                Ok(Some(s)) => s
+            }
+        }
+    }
+}
+
+pub fn load_external_files(names: &[String]) -> Option<String> {
+    let mut out = String::new();
+    for name in names.iter() {
+        out.push_str(load_or_return!(name.as_slice(), None, None).as_slice());
+        out.push_char('\n');
+    }
+    Some(out)
+}
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 61a2d3c5d9c..aa298d07780 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -11,10 +11,13 @@
 use std::fmt;
 use std::io;
 
+use externalfiles::ExternalHtml;
+
 #[deriving(Clone)]
 pub struct Layout {
     pub logo: String,
     pub favicon: String,
+    pub external_html: ExternalHtml,
     pub krate: String,
     pub playground_url: String,
 }
@@ -44,6 +47,7 @@ r##"<!DOCTYPE html>
     <link rel="stylesheet" type="text/css" href="{root_path}main.css">
 
     {favicon}
+    {in_header}
 </head>
 <body>
     <!--[if lte IE 8]>
@@ -53,6 +57,8 @@ r##"<!DOCTYPE html>
     </div>
     <![endif]-->
 
+    {before_content}
+
     <section class="sidebar">
         {logo}
         {sidebar}
@@ -105,6 +111,8 @@ r##"<!DOCTYPE html>
         </div>
     </div>
 
+    {after_content}
+
     <script>
         window.rootPath = "{root_path}";
         window.currentCrate = "{krate}";
@@ -133,6 +141,9 @@ r##"<!DOCTYPE html>
     } else {
         format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
     },
+    in_header = layout.external_html.in_header,
+    before_content = layout.external_html.before_content,
+    after_content = layout.external_html.after_content,
     sidebar   = *sidebar,
     krate     = layout.krate,
     play_url  = layout.playground_url,
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index aacb13156b7..f5d379c4baf 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -41,6 +41,8 @@ use std::str;
 use std::string::String;
 use std::sync::Arc;
 
+use externalfiles::ExternalHtml;
+
 use serialize::json::ToJson;
 use syntax::ast;
 use syntax::ast_util;
@@ -78,7 +80,7 @@ pub struct Context {
     /// This changes as the context descends into the module hierarchy.
     pub dst: Path,
     /// This describes the layout of each page, and is not modified after
-    /// creation of the context (contains info like the favicon)
+    /// creation of the context (contains info like the favicon and added html).
     pub layout: layout::Layout,
     /// This map is a list of what should be displayed on the sidebar of the
     /// current page. The key is the section header (traits, modules,
@@ -220,7 +222,7 @@ local_data_key!(pub cache_key: Arc<Cache>)
 local_data_key!(pub current_location_key: Vec<String> )
 
 /// Generates the documentation for `crate` into the directory `dst`
-pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
+pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) -> io::IoResult<()> {
     let mut cx = Context {
         dst: dst,
         current: Vec::new(),
@@ -229,12 +231,14 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
         layout: layout::Layout {
             logo: "".to_string(),
             favicon: "".to_string(),
+            external_html: external_html.clone(),
             krate: krate.name.clone(),
             playground_url: "".to_string(),
         },
         include_sources: true,
         render_redirect_pages: false,
     };
+
     try!(mkdir(&cx.dst));
 
     // Crawl the crate attributes looking for attributes which control how we're
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index be14ffa87af..46aa6cb5e94 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -32,6 +32,7 @@ use std::io::{File, MemWriter};
 use std::str;
 use std::gc::Gc;
 use serialize::{json, Decodable, Encodable};
+use externalfiles::ExternalHtml;
 
 // reexported from `clean` so it can be easily updated with the mod itself
 pub use clean::SCHEMA_VERSION;
@@ -39,6 +40,8 @@ pub use clean::SCHEMA_VERSION;
 pub mod clean;
 pub mod core;
 pub mod doctree;
+#[macro_escape]
+pub mod externalfiles;
 pub mod fold;
 pub mod html {
     pub mod highlight;
@@ -113,16 +116,17 @@ pub fn opts() -> Vec<getopts::OptGroup> {
                  "ARGS"),
         optmulti("", "markdown-css", "CSS files to include via <link> in a rendered Markdown file",
                  "FILES"),
-        optmulti("", "markdown-in-header",
-                 "files to include inline in the <head> section of a rendered Markdown file",
+        optmulti("", "html-in-header",
+                 "files to include inline in the <head> section of a rendered Markdown file \
+                 or generated documentation",
                  "FILES"),
-        optmulti("", "markdown-before-content",
+        optmulti("", "html-before-content",
                  "files to include inline between <body> and the content of a rendered \
-                 Markdown file",
+                 Markdown file or generated documentation",
                  "FILES"),
-        optmulti("", "markdown-after-content",
+        optmulti("", "html-after-content",
                  "files to include inline between the content and </body> of a rendered \
-                 Markdown file",
+                 Markdown file or generated documentation",
                  "FILES"),
         optopt("", "markdown-playground-url",
                "URL to send code snippets to", "URL")
@@ -179,6 +183,14 @@ pub fn main_args(args: &[String]) -> int {
     let output = matches.opt_str("o").map(|s| Path::new(s));
     let cfgs = matches.opt_strs("cfg");
 
+    let external_html = match ExternalHtml::load(
+            matches.opt_strs("html-in-header").as_slice(),
+            matches.opt_strs("html-before-content").as_slice(),
+            matches.opt_strs("html-after-content").as_slice()) {
+        Some(eh) => eh,
+        None => return 3
+    };
+
     match (should_test, markdown_input) {
         (true, true) => {
             return markdown::test(input, libs, test_args)
@@ -187,7 +199,7 @@ pub fn main_args(args: &[String]) -> int {
             return test::run(input, cfgs, libs, test_args)
         }
         (false, true) => return markdown::render(input, output.unwrap_or(Path::new("doc")),
-                                                 &matches),
+                                                 &matches, &external_html),
         (false, false) => {}
     }
 
@@ -215,7 +227,7 @@ pub fn main_args(args: &[String]) -> int {
     let started = time::precise_time_ns();
     match matches.opt_str("w").as_ref().map(|s| s.as_slice()) {
         Some("html") | None => {
-            match html::render::run(krate, output.unwrap_or(Path::new("doc"))) {
+            match html::render::run(krate, &external_html, output.unwrap_or(Path::new("doc"))) {
                 Ok(()) => {}
                 Err(e) => fail!("failed to generate documentation: {}", e),
             }
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 76366240f1a..da271be4768 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -9,43 +9,19 @@
 // except according to those terms.
 
 use std::collections::HashSet;
-use std::{str, io};
+use std::io;
 use std::string::String;
 
 use getopts;
 use testing;
 
+use externalfiles::ExternalHtml;
+
 use html::escape::Escape;
 use html::markdown;
 use html::markdown::{MarkdownWithToc, find_testable_code, reset_headers};
 use test::Collector;
 
-fn load_string(input: &Path) -> io::IoResult<Option<String>> {
-    let mut f = try!(io::File::open(input));
-    let d = try!(f.read_to_end());
-    Ok(str::from_utf8(d.as_slice()).map(|s| s.to_string()))
-}
-macro_rules! load_or_return {
-    ($input: expr, $cant_read: expr, $not_utf8: expr) => {
-        {
-            let input = Path::new($input);
-            match load_string(&input) {
-                Err(e) => {
-                    let _ = writeln!(&mut io::stderr(),
-                                     "error reading `{}`: {}", input.display(), e);
-                    return $cant_read;
-                }
-                Ok(None) => {
-                    let _ = writeln!(&mut io::stderr(),
-                                     "error reading `{}`: not UTF-8", input.display());
-                    return $not_utf8;
-                }
-                Ok(Some(s)) => s
-            }
-        }
-    }
-}
-
 /// Separate any lines at the start of the file that begin with `%`.
 fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
     let mut metadata = Vec::new();
@@ -62,18 +38,10 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
     (metadata, "")
 }
 
-fn load_external_files(names: &[String]) -> Option<String> {
-    let mut out = String::new();
-    for name in names.iter() {
-        out.push_str(load_or_return!(name.as_slice(), None, None).as_slice());
-        out.push_char('\n');
-    }
-    Some(out)
-}
-
 /// Render `input` (e.g. "foo.md") into an HTML file in `output`
 /// (e.g. output = "bar" => "bar/foo.html").
-pub fn render(input: &str, mut output: Path, matches: &getopts::Matches) -> int {
+pub fn render(input: &str, mut output: Path, matches: &getopts::Matches,
+              external_html: &ExternalHtml) -> int {
     let input_p = Path::new(input);
     output.push(input_p.filestem().unwrap());
     output.set_extension("html");
@@ -91,17 +59,6 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches) -> int
     }
     let playground = playground.unwrap_or("".to_string());
 
-    let (in_header, before_content, after_content) =
-        match (load_external_files(matches.opt_strs("markdown-in-header")
-                                          .as_slice()),
-               load_external_files(matches.opt_strs("markdown-before-content")
-                                          .as_slice()),
-               load_external_files(matches.opt_strs("markdown-after-content")
-                                          .as_slice())) {
-        (Some(a), Some(b), Some(c)) => (a,b,c),
-        _ => return 3
-    };
-
     let mut out = match io::File::create(&output) {
         Err(e) => {
             let _ = writeln!(&mut io::stderr(),
@@ -153,10 +110,10 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches) -> int
 </html>"#,
         title = Escape(title),
         css = css,
-        in_header = in_header,
-        before_content = before_content,
+        in_header = external_html.in_header,
+        before_content = external_html.before_content,
         text = MarkdownWithToc(text),
-        after_content = after_content,
+        after_content = external_html.after_content,
         playground = playground,
         );