diff --git a/.gitmodules b/.gitmodules
index d2e1fb868a9..53d17874924 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -5,10 +5,6 @@
 [submodule "src/compiler-rt"]
 	path = src/compiler-rt
 	url = https://github.com/rust-lang/compiler-rt.git
-[submodule "src/rt/hoedown"]
-	path = src/rt/hoedown
-	url = https://github.com/rust-lang/hoedown.git
-	branch = rust-2015-09-21-do-not-delete
 [submodule "src/jemalloc"]
 	path = src/jemalloc
 	url = https://github.com/rust-lang/jemalloc.git
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 2222077aae8..ff18daa7aa0 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -2,7 +2,6 @@
 authors = ["The Rust Project Developers"]
 name = "rustdoc"
 version = "0.0.0"
-build = "build.rs"
 
 [lib]
 name = "rustdoc"
diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs
deleted file mode 100644
index 9fa6406c1d8..00000000000
--- a/src/librustdoc/build.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2015 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.
-
-extern crate build_helper;
-extern crate gcc;
-
-fn main() {
-    let src_dir = std::path::Path::new("../rt/hoedown/src");
-    build_helper::rerun_if_changed_anything_in_dir(src_dir);
-    let mut cfg = gcc::Config::new();
-    cfg.file("../rt/hoedown/src/autolink.c")
-       .file("../rt/hoedown/src/buffer.c")
-       .file("../rt/hoedown/src/document.c")
-       .file("../rt/hoedown/src/escape.c")
-       .file("../rt/hoedown/src/html.c")
-       .file("../rt/hoedown/src/html_blocks.c")
-       .file("../rt/hoedown/src/html_smartypants.c")
-       .file("../rt/hoedown/src/stack.c")
-       .file("../rt/hoedown/src/version.c")
-       .include(src_dir)
-       .compile("libhoedown.a");
-}
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index a36e99e80df..9ae6c443f9e 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -26,7 +26,7 @@
 
 #![allow(non_camel_case_types)]
 
-use libc;
+//use libc;
 use std::ascii::AsciiExt;
 use std::cell::RefCell;
 use std::default::Default;
@@ -43,158 +43,19 @@ use html::highlight;
 use html::escape::Escape;
 use test;
 
-use pulldown_cmark::{self, Event, Parser};
+use pulldown_cmark::{self, Event, Parser, Tag};
 
 /// A unit struct which has the `fmt::Display` trait implemented. When
 /// formatted, this struct will emit the HTML corresponding to the rendered
 /// version of the contained markdown string.
-pub struct Markdown<'a>(pub &'a str);
+// The second parameter is whether we need a shorter version or not.
+pub struct Markdown<'a>(pub &'a str, pub bool);
 /// A unit struct like `Markdown`, that renders the markdown with a
 /// table of contents.
 pub struct MarkdownWithToc<'a>(pub &'a str);
 /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
 pub struct MarkdownHtml<'a>(pub &'a str);
 
-/*const DEF_OUNIT: libc::size_t = 64;
-const HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 11;
-const HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0;
-const HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1;
-const HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3;
-const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
-const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8;
-const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2;
-const HOEDOWN_HTML_ESCAPE: libc::c_uint = 1 << 1;
-
-const HOEDOWN_EXTENSIONS: libc::c_uint =
-    HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES |
-    HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK |
-    HOEDOWN_EXT_STRIKETHROUGH | HOEDOWN_EXT_SUPERSCRIPT |
-    HOEDOWN_EXT_FOOTNOTES;
-
-enum hoedown_document {}
-
-type blockcodefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
-                                 *const hoedown_buffer, *const hoedown_renderer_data,
-                                 libc::size_t);
-
-type blockquotefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
-                                  *const hoedown_renderer_data, libc::size_t);
-
-type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
-                              libc::c_int, *const hoedown_renderer_data,
-                              libc::size_t);
-
-type blockhtmlfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
-                                 *const hoedown_renderer_data, libc::size_t);
-
-type codespanfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
-                                *const hoedown_renderer_data, libc::size_t) -> libc::c_int;
-
-type linkfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer,
-                             *const hoedown_buffer, *const hoedown_buffer,
-                             *const hoedown_renderer_data, libc::size_t) -> libc::c_int;
-
-type entityfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer,
-                               *const hoedown_renderer_data, libc::size_t);
-
-type normaltextfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
-                                  *const hoedown_renderer_data, libc::size_t);
-
-#[repr(C)]
-struct hoedown_renderer_data {
-    opaque: *mut libc::c_void,
-}
-
-#[repr(C)]
-struct hoedown_renderer {
-    opaque: *mut libc::c_void,
-
-    blockcode: Option<blockcodefn>,
-    blockquote: Option<blockquotefn>,
-    header: Option<headerfn>,
-
-    other_block_level_callbacks: [libc::size_t; 11],
-
-    blockhtml: Option<blockhtmlfn>,
-
-    /* span level callbacks - NULL or return 0 prints the span verbatim */
-    autolink: libc::size_t, // unused
-    codespan: Option<codespanfn>,
-    other_span_level_callbacks_1: [libc::size_t; 7],
-    link: Option<linkfn>,
-    other_span_level_callbacks_2: [libc::size_t; 6],
-
-    /* low level callbacks - NULL copies input directly into the output */
-    entity: Option<entityfn>,
-    normal_text: Option<normaltextfn>,
-
-    /* header and footer */
-    other_callbacks: [libc::size_t; 2],
-}
-
-#[repr(C)]
-struct hoedown_html_renderer_state {
-    opaque: *mut libc::c_void,
-    toc_data: html_toc_data,
-    flags: libc::c_uint,
-    link_attributes: Option<extern "C" fn(*mut hoedown_buffer,
-                                          *const hoedown_buffer,
-                                          *const hoedown_renderer_data)>,
-}
-
-#[repr(C)]
-struct html_toc_data {
-    header_count: libc::c_int,
-    current_level: libc::c_int,
-    level_offset: libc::c_int,
-    nesting_level: libc::c_int,
-}
-
-struct MyOpaque {
-    dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
-                           *const hoedown_buffer, *const hoedown_renderer_data,
-                           libc::size_t),
-    toc_builder: Option<TocBuilder>,
-}
-
-#[repr(C)]
-struct hoedown_buffer {
-    data: *const u8,
-    size: libc::size_t,
-    asize: libc::size_t,
-    unit: libc::size_t,
-}
-
-extern {
-    fn hoedown_html_renderer_new(render_flags: libc::c_uint,
-                                 nesting_level: libc::c_int)
-        -> *mut hoedown_renderer;
-    fn hoedown_html_renderer_free(renderer: *mut hoedown_renderer);
-
-    fn hoedown_document_new(rndr: *const hoedown_renderer,
-                            extensions: libc::c_uint,
-                            max_nesting: libc::size_t) -> *mut hoedown_document;
-    fn hoedown_document_render(doc: *mut hoedown_document,
-                               ob: *mut hoedown_buffer,
-                               document: *const u8,
-                               doc_size: libc::size_t);
-    fn hoedown_document_free(md: *mut hoedown_document);
-
-    fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer;
-    /*fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char,
-                          n: libc::size_t);*/
-    fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char);
-    fn hoedown_buffer_free(b: *mut hoedown_buffer);
-
-}
-
-// hoedown_buffer helpers
-impl hoedown_buffer {
-    fn as_bytes(&self) -> &[u8] {
-        unsafe { slice::from_raw_parts(self.data, self.size as usize) }
-    }
-}*/
-
 /// Returns Some(code) if `s` is a line that should be stripped from
 /// documentation but used in example code. `code` is the portion of
 /// `s` that should be used in tests. (None for lines that should be
@@ -228,213 +89,15 @@ thread_local!(pub static PLAYGROUND: RefCell<Option<(Option<String>, String)>> =
 pub fn render(w: &mut fmt::Formatter,
               s: &str,
               print_toc: bool,
-              _html_flags: libc::c_uint) -> fmt::Result {
-    /*extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer,
-                    lang: *const hoedown_buffer, data: *const hoedown_renderer_data,
-                    line: libc::size_t) {
-        unsafe {
-            if orig_text.is_null() { return }
-
-            let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
-            let my_opaque: &MyOpaque = &*((*opaque).opaque as *const MyOpaque);
-            let text = (*orig_text).as_bytes();
-            let origtext = str::from_utf8(text).unwrap();
-            let origtext = origtext.trim_left();
-            debug!("docblock: ==============\n{:?}\n=======", text);
-            let rendered = if lang.is_null() || origtext.is_empty() {
-                false
-            } else {
-                let rlang = (*lang).as_bytes();
-                let rlang = str::from_utf8(rlang).unwrap();
-                if !LangString::parse(rlang).rust {
-                    (my_opaque.dfltblk)(ob, orig_text, lang,
-                                        opaque as *const hoedown_renderer_data,
-                                        line);
-                    true
-                } else {
-                    false
-                }
-            };
-
-            let lines = origtext.lines().filter(|l| {
-                stripped_filtered_line(*l).is_none()
-            });
-            let text = lines.collect::<Vec<&str>>().join("\n");
-            if rendered { return }
-            PLAYGROUND.with(|play| {
-                // insert newline to clearly separate it from the
-                // previous block so we can shorten the html output
-                let mut s = String::from("\n");
-                let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| {
-                    if url.is_empty() {
-                        return None;
-                    }
-                    let test = origtext.lines().map(|l| {
-                        stripped_filtered_line(l).unwrap_or(l)
-                    }).collect::<Vec<&str>>().join("\n");
-                    let krate = krate.as_ref().map(|s| &**s);
-                    let test = test::maketest(&test, krate, false,
-                                              &Default::default());
-                    let channel = if test.contains("#![feature(") {
-                        "&amp;version=nightly"
-                    } else {
-                        ""
-                    };
-                    // These characters don't need to be escaped in a URI.
-                    // FIXME: use a library function for percent encoding.
-                    fn dont_escape(c: u8) -> bool {
-                        (b'a' <= c && c <= b'z') ||
-                        (b'A' <= c && c <= b'Z') ||
-                        (b'0' <= c && c <= b'9') ||
-                        c == b'-' || c == b'_' || c == b'.' ||
-                        c == b'~' || c == b'!' || c == b'\'' ||
-                        c == b'(' || c == b')' || c == b'*'
-                    }
-                    let mut test_escaped = String::new();
-                    for b in test.bytes() {
-                        if dont_escape(b) {
-                            test_escaped.push(char::from(b));
-                        } else {
-                            write!(test_escaped, "%{:02X}", b).unwrap();
-                        }
-                    }
-                    Some(format!(
-                        r#"<a class="test-arrow" target="_blank" href="{}?code={}{}">Run</a>"#,
-                        url, test_escaped, channel
-                    ))
-                });
-                s.push_str(&highlight::render_with_highlighting(
-                               &text,
-                               Some("rust-example-rendered"),
-                               None,
-                               playground_button.as_ref().map(String::as_str)));
-                let output = CString::new(s).unwrap();
-                hoedown_buffer_puts(ob, output.as_ptr());
-            })
-        }
-    }
-
-    extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer,
-                     level: libc::c_int, data: *const hoedown_renderer_data,
-                     _: libc::size_t) {
-        // hoedown does this, we may as well too
-        unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); }
-
-        // Extract the text provided
-        let s = if text.is_null() {
-            "".to_owned()
-        } else {
-            let s = unsafe { (*text).as_bytes() };
-            str::from_utf8(&s).unwrap().to_owned()
-        };
-
-        // Discard '<em>', '<code>' tags and some escaped characters,
-        // transform the contents of the header into a hyphenated string
-        // without non-alphanumeric characters other than '-' and '_'.
-        //
-        // This is a terrible hack working around how hoedown gives us rendered
-        // html for text rather than the raw text.
-        let mut id = s.clone();
-        let repl_sub = vec!["<em>", "</em>", "<code>", "</code>",
-                            "<strong>", "</strong>",
-                            "&lt;", "&gt;", "&amp;", "&#39;", "&quot;"];
-        for sub in repl_sub {
-            id = id.replace(sub, "");
-        }
-        let id = id.chars().filter_map(|c| {
-            if c.is_alphanumeric() || c == '-' || c == '_' {
-                if c.is_ascii() {
-                    Some(c.to_ascii_lowercase())
-                } else {
-                    Some(c)
-                }
-            } else if c.is_whitespace() && c.is_ascii() {
-                Some('-')
-            } else {
-                None
-            }
-        }).collect::<String>();
-
-        let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state };
-        let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) };
-
-        let id = derive_id(id);
-
-        let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| {
-            format!("{} ", builder.push(level as u32, s.clone(), id.clone()))
-        });
-
-        // Render the HTML
-        let text = format!("<h{lvl} id='{id}' class='section-header'>\
-                           <a href='#{id}'>{sec}{}</a></h{lvl}>",
-                           s, lvl = level, id = id, sec = sec);
-
-        let text = CString::new(text).unwrap();
-        unsafe { hoedown_buffer_puts(ob, text.as_ptr()) }
-    }
-
-    extern fn codespan(
-        ob: *mut hoedown_buffer,
-        text: *const hoedown_buffer,
-        _: *const hoedown_renderer_data,
-        _: libc::size_t
-    ) -> libc::c_int {
-        let content = if text.is_null() {
-            "".to_owned()
-        } else {
-            let bytes = unsafe { (*text).as_bytes() };
-            let s = str::from_utf8(bytes).unwrap();
-            collapse_whitespace(s)
-        };
-
-        let content = format!("<code>{}</code>", Escape(&content));
-        let element = CString::new(content).unwrap();
-        unsafe { hoedown_buffer_puts(ob, element.as_ptr()); }
-        // Return anything except 0, which would mean "also print the code span verbatim".
-        1
-    }
-
-    unsafe {
-        let ob = hoedown_buffer_new(DEF_OUNIT);
-        let renderer = hoedown_html_renderer_new(html_flags, 0);
-        let mut opaque = MyOpaque {
-            dfltblk: (*renderer).blockcode.unwrap(),
-            toc_builder: if print_toc {Some(TocBuilder::new())} else {None}
-        };
-        (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
-                = &mut opaque as *mut _ as *mut libc::c_void;
-        (*renderer).blockcode = Some(block);
-        (*renderer).header = Some(header);
-        (*renderer).codespan = Some(codespan);
-
-        let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
-        hoedown_document_render(document, ob, s.as_ptr(),
-                                s.len() as libc::size_t);
-        hoedown_document_free(document);
-
-        hoedown_html_renderer_free(renderer);
-
-        let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| {
-            write!(w, "<nav id=\"TOC\">{}</nav>", builder.into_toc())
-        });
-
-        if ret.is_ok() {
-            let buf = (*ob).as_bytes();
-            ret = w.write_str(str::from_utf8(buf).unwrap());
-        }
-        hoedown_buffer_free(ob);
-        ret
-    }*/
-
-    fn block(parser: &mut Parser, lang: &str, buffer: &mut String) {
+              shorter: bool) -> fmt::Result {
+    fn block(parser: &mut Parser, buffer: &mut String, lang: &str) {
         let mut origtext = String::new();
         loop {
             let event = parser.next();
             if let Some(event) = event {
                 match event {
-                    pulldown_cmark::Event::End(
-                        pulldown_cmark::Tag::CodeBlock(_)) => break,
-                    pulldown_cmark::Event::Text(ref s) => {
+                    Event::End(Tag::CodeBlock(_)) => break,
+                    Event::Text(ref s) => {
                         origtext.push_str(s);
                     }
                     _ => {}
@@ -445,25 +108,21 @@ pub fn render(w: &mut fmt::Formatter,
         }
         let origtext = origtext.trim_left();
         debug!("docblock: ==============\n{:?}\n=======", origtext);
-        let rendered = if lang.is_empty() || origtext.is_empty() {
-            false
-        } else {
-            if !LangString::parse(lang).rust {
-                /*(my_opaque.dfltblk)(ob, orig_text, lang,
-                                    opaque as *const hoedown_renderer_data,
-                                    line);*/
-                // true
-                false
-            } else {
-                false
-            }
-        };
 
         let lines = origtext.lines().filter(|l| {
             stripped_filtered_line(*l).is_none()
         });
         let text = lines.collect::<Vec<&str>>().join("\n");
-        if rendered { return }
+        let block_info = if lang.is_empty() {
+            LangString::all_false()
+        } else {
+            LangString::parse(lang)
+        };
+        if !block_info.rust {
+            buffer.push_str(&format!("<pre><code class=\"language-{}\">{}</code></pre>",
+                            lang, text));
+            return
+        }
         PLAYGROUND.with(|play| {
             // insert newline to clearly separate it from the
             // previous block so we can shorten the html output
@@ -521,9 +180,8 @@ pub fn render(w: &mut fmt::Formatter,
             let event = parser.next();
             if let Some(event) = event {
                 match event {
-                    pulldown_cmark::Event::End(
-                        pulldown_cmark::Tag::Header(_)) => break,
-                    pulldown_cmark::Event::Text(ref s) => {
+                    Event::End(Tag::Header(_)) => break,
+                    Event::Text(ref s) => {
                         ret.push_str(s);
                     }
                     _ => {}
@@ -561,8 +219,8 @@ pub fn render(w: &mut fmt::Formatter,
         });
 
         // Render the HTML
-        buffer.push_str(&format!("<h{lvl} id='{id}' class='section-header'>\
-                                  <a href='#{id}'>{sec}{}</a></h{lvl}>",
+        buffer.push_str(&format!("<h{lvl} id=\"{id}\" class=\"section-header\">\
+                                  <a href=\"#{id}\">{sec}{}</a></h{lvl}>",
                                  ret, lvl = level, id = id, sec = sec));
     }
 
@@ -572,9 +230,8 @@ pub fn render(w: &mut fmt::Formatter,
             let event = parser.next();
             if let Some(event) = event {
                 match event {
-                    pulldown_cmark::Event::End(
-                        pulldown_cmark::Tag::Code) => break,
-                    pulldown_cmark::Event::Text(ref s) => {
+                    Event::End(Tag::Code) => break,
+                    Event::Text(ref s) => {
                         content.push_str(s);
                     }
                     _ => {}
@@ -591,9 +248,8 @@ pub fn render(w: &mut fmt::Formatter,
             let event = parser.next();
             if let Some(event) = event {
                 match event {
-                    pulldown_cmark::Event::End(
-                        pulldown_cmark::Tag::Link(_, _)) => break,
-                    pulldown_cmark::Event::Text(ref s) => {
+                    Event::End(Tag::Link(_, _)) => break,
+                    Event::Text(ref s) => {
                         title.push_str(s);
                     }
                     _ => {}
@@ -605,19 +261,19 @@ pub fn render(w: &mut fmt::Formatter,
         buffer.push_str(&format!("<a href=\"{}\">{}</a>", url, title));
     }
 
-    fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>) {
+    fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
+                 shorter: bool) {
         let mut content = String::new();
         loop {
             let event = parser.next();
             if let Some(event) = event {
                 match event {
-                    pulldown_cmark::Event::End(
-                        pulldown_cmark::Tag::Paragraph) => break,
-                    pulldown_cmark::Event::Text(ref s) => {
+                    Event::End(Tag::Paragraph) => break,
+                    Event::Text(ref s) => {
                         content.push_str(s);
                     }
                     x => {
-                        looper(parser, &mut content, Some(x), toc_builder);
+                        looper(parser, &mut content, Some(x), toc_builder, shorter);
                     }
                 }
             } else {
@@ -627,28 +283,135 @@ pub fn render(w: &mut fmt::Formatter,
         buffer.push_str(&format!("<p>{}</p>", content));
     }
 
+    fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
+            shorter: bool) {
+        let mut content = String::new();
+        loop {
+            let event = parser.next();
+            if let Some(event) = event {
+                match event {
+                    Event::End(Tag::TableHead) |
+                        Event::End(Tag::Table(_)) |
+                        Event::End(Tag::TableRow) |
+                        Event::End(Tag::TableCell) => break,
+                    Event::Text(ref s) => {
+                        content.push_str(s);
+                    }
+                    x => {
+                        looper(parser, &mut content, Some(x), toc_builder, shorter);
+                    }
+                }
+            } else {
+                break
+            }
+        }
+        buffer.push_str(&format!("<td>{}</td>", content.trim()));
+    }
+
+    fn row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
+           shorter: bool) {
+        let mut content = String::new();
+        loop {
+            let event = parser.next();
+            if let Some(event) = event {
+                match event {
+                    Event::End(Tag::TableHead) |
+                        Event::End(Tag::Table(_)) |
+                        Event::End(Tag::TableRow) => break,
+                    Event::Start(Tag::TableCell) => {
+                        cell(parser, &mut content, toc_builder, shorter);
+                    }
+                    x => {
+                        looper(parser, &mut content, Some(x), toc_builder, shorter);
+                    }
+                }
+            } else {
+                break
+            }
+        }
+        buffer.push_str(&format!("<tr>{}</tr>", content));
+    }
+
+    fn head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
+            shorter: bool) {
+        let mut content = String::new();
+        loop {
+            let event = parser.next();
+            if let Some(event) = event {
+                match event {
+                    Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break,
+                    Event::Start(Tag::TableCell) => {
+                        cell(parser, &mut content, toc_builder, shorter);
+                    }
+                    x => {
+                        looper(parser, &mut content, Some(x), toc_builder, shorter);
+                    }
+                }
+            } else {
+                break
+            }
+        }
+        if content.is_empty() {
+            return
+        }
+        buffer.push_str(&format!("<thead><tr>{}</tr></thead>", content.replace("td>", "th>")));
+    }
+
+    fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
+             shorter: bool) {
+        let mut content = String::new();
+        let mut rows = String::new();
+        loop {
+            let event = parser.next();
+            if let Some(event) = event {
+                match event {
+                    Event::End(Tag::Table(_)) => break,
+                    Event::Start(Tag::TableHead) => {
+                        head(parser, &mut content, toc_builder, shorter);
+                    }
+                    Event::Start(Tag::TableRow) => {
+                        row(parser, &mut rows, toc_builder, shorter);
+                    }
+                    _ => {}
+                }
+            } else {
+                break
+            }
+        }
+        buffer.push_str(&format!("<table>{}{}</table>",
+                                 content,
+                                 if shorter || rows.is_empty() {
+                                     String::new()
+                                 } else {
+                                     format!("<tbody>{}</tbody>", rows)
+                                 }));
+    }
+
     fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option<Event<'a>>,
-                  toc_builder: &mut Option<TocBuilder>) -> bool {
+                  toc_builder: &mut Option<TocBuilder>, shorter: bool) -> bool {
         if let Some(event) = next_event {
             match event {
-                pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => {
-                    block(parser, &*s, buffer);
+                Event::Start(Tag::CodeBlock(lang)) => {
+                    block(parser, buffer, &*lang);
                 }
-                pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => {
+                Event::Start(Tag::Header(level)) => {
                     header(parser, level, toc_builder, buffer);
                 }
-                pulldown_cmark::Event::Start(pulldown_cmark::Tag::Code) => {
+                Event::Start(Tag::Code) => {
                     codespan(parser, buffer);
                 }
-                pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => {
-                    paragraph(parser, buffer, toc_builder);
+                Event::Start(Tag::Paragraph) => {
+                    paragraph(parser, buffer, toc_builder, shorter);
                 }
-                pulldown_cmark::Event::Start(pulldown_cmark::Tag::Link(ref url, ref t)) => {
+                Event::Start(Tag::Link(ref url, ref t)) => {
                     link(parser, buffer, url, t.as_ref().to_owned());
                 }
+                Event::Start(Tag::Table(_)) => {
+                    table(parser, buffer, toc_builder, shorter);
+                }
                 _ => {}
             }
-            true
+            shorter == false
         } else {
             false
         }
@@ -660,10 +423,10 @@ pub fn render(w: &mut fmt::Formatter,
         None
     };
     let mut buffer = String::new();
-    let mut parser = Parser::new(s);
+    let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES);
     loop {
         let next_event = parser.next();
-        if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder) {
+        if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter) {
             break
         }
     }
@@ -684,67 +447,64 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Sp
     let mut prev_offset = 0;
     let mut nb_lines = 0;
     let mut register_header = None;
-    'main: loop {
-        let next_event = parser.next();
-        if let Some(event) = next_event {
-            match event {
-                pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => {
-                    let block_info = if s.is_empty() {
-                        LangString::all_false()
-                    } else {
-                        LangString::parse(&*s)
-                    };
-                    let mut test_s = String::new();
-                    let mut offset = None;
-                    loop {
-                        let event = parser.next();
-                        if let Some(event) = event {
-                            match event {
-                                pulldown_cmark::Event::End(
-                                    pulldown_cmark::Tag::CodeBlock(_)) => break,
-                                pulldown_cmark::Event::Text(ref s) => {
-                                    test_s.push_str(s);
-                                    if offset.is_none() {
-                                        offset = Some(parser.get_offset());
-                                    }
+    'main: while let Some(event) = parser.next() {
+        match event {
+            Event::Start(Tag::CodeBlock(s)) => {
+                let block_info = if s.is_empty() {
+                    LangString::all_false()
+                } else {
+                    LangString::parse(&*s)
+                };
+                if !block_info.rust {
+                    continue
+                }
+                let mut test_s = String::new();
+                let mut offset = None;
+                loop {
+                    let event = parser.next();
+                    if let Some(event) = event {
+                        match event {
+                            Event::End(Tag::CodeBlock(_)) => break,
+                            Event::Text(ref s) => {
+                                test_s.push_str(s);
+                                if offset.is_none() {
+                                    offset = Some(parser.get_offset());
                                 }
-                                _ => {}
                             }
-                        } else {
-                            break 'main;
+                            _ => {}
                         }
-                    }
-                    let offset = offset.unwrap_or(0);
-                    let lines = test_s.lines().map(|l| {
-                        stripped_filtered_line(l).unwrap_or(l)
-                    });
-                    let text = lines.collect::<Vec<&str>>().join("\n");
-                    nb_lines += doc[prev_offset..offset].lines().count();
-                    let line = tests.get_line() + (nb_lines - 1);
-                    let filename = tests.get_filename();
-                    tests.add_test(text.to_owned(),
-                                   block_info.should_panic, block_info.no_run,
-                                   block_info.ignore, block_info.test_harness,
-                                   block_info.compile_fail, block_info.error_codes,
-                                   line, filename);
-                    prev_offset = offset;
-                }
-                pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => {
-                    register_header = Some(level as u32);
-                }
-                pulldown_cmark::Event::Text(ref s) if register_header.is_some() => {
-                    let level = register_header.unwrap();
-                    if s.is_empty() {
-                        tests.register_header("", level);
                     } else {
-                        tests.register_header(s, level);
+                        break 'main;
                     }
-                    register_header = None;
                 }
-                _ => {}
+                let offset = offset.unwrap_or(0);
+                let lines = test_s.lines().map(|l| {
+                    stripped_filtered_line(l).unwrap_or(l)
+                });
+                let text = lines.collect::<Vec<&str>>().join("\n");
+                nb_lines += doc[prev_offset..offset].lines().count();
+                let line = tests.get_line() + (nb_lines - 1);
+                let filename = tests.get_filename();
+                tests.add_test(text.to_owned(),
+                               block_info.should_panic, block_info.no_run,
+                               block_info.ignore, block_info.test_harness,
+                               block_info.compile_fail, block_info.error_codes,
+                               line, filename);
+                prev_offset = offset;
             }
-        } else {
-            break
+            Event::Start(Tag::Header(level)) => {
+                register_header = Some(level as u32);
+            }
+            Event::Text(ref s) if register_header.is_some() => {
+                let level = register_header.unwrap();
+                if s.is_empty() {
+                    tests.register_header("", level);
+                } else {
+                    tests.register_header(s, level);
+                }
+                register_header = None;
+            }
+            _ => {}
         }
     }
 }
@@ -824,17 +584,17 @@ impl LangString {
 
 impl<'a> fmt::Display for Markdown<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let Markdown(md) = *self;
+        let Markdown(md, shorter) = *self;
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
-        render(fmt, md, false, 0)
+        render(fmt, md, false, shorter)
     }
 }
 
 impl<'a> fmt::Display for MarkdownWithToc<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let MarkdownWithToc(md) = *self;
-        render(fmt, md, true, 0)
+        render(fmt, md, true, false)
     }
 }
 
@@ -843,7 +603,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> {
         let MarkdownHtml(md) = *self;
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
-        render(fmt, md, false, /*HOEDOWN_HTML_ESCAPE*/0)
+        render(fmt, md, false, false)
     }
 }
 
@@ -864,12 +624,13 @@ pub fn plain_summary_line(md: &str) -> String {
             }
             let next_event = next_event.unwrap();
             let (ret, is_in) = match next_event {
-                pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => (None, 1),
-                pulldown_cmark::Event::Start(
-                    pulldown_cmark::Tag::Link(_, ref t)) if !self.is_first => (Some(t.as_ref().to_owned()), 1),
-                pulldown_cmark::Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0),
-                pulldown_cmark::Event::End(pulldown_cmark::Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1),
-                pulldown_cmark::Event::End(pulldown_cmark::Tag::Paragraph) => (None, -1),
+                Event::Start(Tag::Paragraph) => (None, 1),
+                Event::Start(Tag::Link(_, ref t)) if !self.is_first => {
+                    (Some(t.as_ref().to_owned()), 1)
+                }
+                Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0),
+                Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1),
+                Event::End(Tag::Paragraph) => (None, -1),
                 _ => (None, 0),
             };
             if is_in > 0 || (is_in < 0 && self.is_in > 0) {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 5c94032c6b9..8c1416b8097 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1650,7 +1650,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
         } else {
             format!("{}", &plain_summary_line(Some(s)))
         };
-        write!(w, "<div class='docblock'>{}</div>", Markdown(&markdown))?;
+        write!(w, "<div class='docblock'>{}</div>", Markdown(&markdown, false))?;
     }
     Ok(())
 }
@@ -1683,7 +1683,7 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> {
 fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
     if let Some(s) = get_doc_value(item) {
         write!(w, "<div class='docblock'>{}</div>",
-               Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?;
+               Markdown(&format!("{}{}", md_render_assoc_item(item), s), false))?;
     }
     Ok(())
 }
@@ -1871,7 +1871,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
                        </tr>",
                        name = *myitem.name.as_ref().unwrap(),
                        stab_docs = stab_docs,
-                       docs = shorter(Some(&Markdown(doc_value).to_string())),
+                       docs = shorter(Some(&Markdown(doc_value, true).to_string())),
                        class = myitem.type_(),
                        stab = myitem.stability_class().unwrap_or("".to_string()),
                        unsafety_flag = unsafety_flag,
@@ -2901,7 +2901,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
         write!(w, "</span>")?;
         write!(w, "</h3>\n")?;
         if let Some(ref dox) = i.impl_item.doc_value() {
-            write!(w, "<div class='docblock'>{}</div>", Markdown(dox))?;
+            write!(w, "<div class='docblock'>{}</div>", Markdown(dox, false))?;
         }
     }
 
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index c67e2fdc2b0..a048750279e 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -94,7 +94,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
     let rendered = if include_toc {
         format!("{}", MarkdownWithToc(text))
     } else {
-        format!("{}", Markdown(text))
+        format!("{}", Markdown(text, false))
     };
 
     let err = write!(
diff --git a/src/rt/hoedown b/src/rt/hoedown
deleted file mode 160000
index da282f1bb72..00000000000
--- a/src/rt/hoedown
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92