diff --git a/.gitmodules b/.gitmodules index d2e1fb868a999..53d1787492409 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/Cargo.lock b/src/Cargo.lock index a0b47f4f0b2bb..a9021dc34e207 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -8,7 +8,7 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -27,7 +27,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", ] @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -75,7 +75,7 @@ dependencies = [ "build_helper 0.1.0", "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -104,12 +104,12 @@ version = "0.1.0" [[package]] name = "clap" -version = "2.21.1" +version = "2.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -122,7 +122,7 @@ name = "cmake" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -140,7 +140,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -188,7 +188,7 @@ name = "flate" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -197,7 +197,7 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -215,10 +215,10 @@ version = "0.0.0" [[package]] name = "handlebars" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -243,7 +243,7 @@ dependencies = [ [[package]] name = "lazy_static" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -272,9 +272,9 @@ name = "mdbook" version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -358,6 +358,14 @@ dependencies = [ "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pulldown-cmark" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "qemu-test-client" version = "0.1.0" @@ -383,7 +391,7 @@ name = "regex" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -416,7 +424,7 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", "mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -593,7 +601,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", ] @@ -770,8 +778,9 @@ dependencies = [ "arena 0.0.0", "build_helper 0.1.0", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -818,7 +827,7 @@ dependencies = [ "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", @@ -978,22 +987,22 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" +"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" -"checksum bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e1ab483fc81a8143faa7203c4a3c02888ebd1a782e37e41fa34753ba9a162" -"checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" +"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" +"checksum clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e17a4a72ffea176f77d6e2db609c6c919ef221f23862c9915e687fb54d833485" "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a32cd40070d7611ab76343dcb3204b2bb28c8a9450989a83a3d590248142f439" +"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335" +"checksum handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "663e1728d8037fb0d4e13bcd1b1909fb5d913690a9929eb385922df157c2ff8f" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc" +"checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" "checksum mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "06a68e8738e42b38a02755d3ce5fa12d559e17acb238e4326cbc3cc056e65280" @@ -1002,6 +1011,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" +"checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 6ec8a37dfa433..c46b0c1324de6 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -838,10 +838,10 @@ impl Result { /// /// assert_eq!(1909, good_year); /// assert_eq!(0, bad_year); + /// ``` /// /// [`parse`]: ../../std/primitive.str.html#method.parse /// [`FromStr`]: ../../std/str/trait.FromStr.html - /// ``` #[inline] #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] pub fn unwrap_or_default(self) -> T { diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 1c479ce1d0157..52f5d99838dc7 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" @@ -26,6 +25,7 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } +pulldown-cmark = { version = "0.0.14", default-features = false } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs deleted file mode 100644 index 9fa6406c1d8b6..0000000000000 --- 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 or the MIT license -// , 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 c7c5aabab97ae..117cfbabb52f7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -10,29 +10,25 @@ //! Markdown formatting for rustdoc //! -//! This module implements markdown formatting through the hoedown C-library -//! (bundled into the rust runtime). This module self-contains the C bindings -//! and necessary legwork to render markdown, and exposes all of the +//! This module implements markdown formatting through the pulldown-cmark +//! rust-library. This module exposes all of the //! functionality through a unit-struct, `Markdown`, which has an implementation //! of `fmt::Display`. Example usage: //! //! ```rust,ignore -//! use rustdoc::html::markdown::Markdown; +//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle}; //! //! let s = "My *markdown* _text_"; -//! let html = format!("{}", Markdown(s)); +//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy)); //! // ... something using html //! ``` #![allow(non_camel_case_types)] -use libc; use std::ascii::AsciiExt; use std::cell::RefCell; use std::default::Default; -use std::ffi::CString; use std::fmt::{self, Write}; -use std::slice; use std::str; use syntax::feature_gate::UnstableFeatures; use syntax::codemap::Span; @@ -43,156 +39,41 @@ use html::highlight; use html::escape::Escape; use test; +use pulldown_cmark::{self, Event, Parser, Tag}; + +#[derive(Copy, Clone)] +pub enum MarkdownOutputStyle { + Compact, + Fancy, +} + +impl MarkdownOutputStyle { + pub fn is_compact(&self) -> bool { + match *self { + MarkdownOutputStyle::Compact => true, + _ => false, + } + } + + pub fn is_fancy(&self) -> bool { + match *self { + MarkdownOutputStyle::Fancy => true, + _ => false, + } + } +} + /// 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 MarkdownOutputStyle); /// 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, - blockquote: Option, - header: Option, - - other_block_level_callbacks: [libc::size_t; 11], - - blockhtml: Option, - - /* span level callbacks - NULL or return 0 prints the span verbatim */ - autolink: libc::size_t, // unused - codespan: Option, - other_span_level_callbacks_1: [libc::size_t; 7], - link: Option, - other_span_level_callbacks_2: [libc::size_t; 6], - - /* low level callbacks - NULL copies input directly into the output */ - entity: Option, - normal_text: Option, - - /* 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, -} - -#[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, -} - -#[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 @@ -222,123 +103,126 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = RefCell::new(None) }); +macro_rules! event_loop_break { + ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, $id:expr, + $($end_event:pat)|*) => {{ + fn inner(id: &mut Option<&mut String>, s: &str) { + if let Some(ref mut id) = *id { + id.push_str(s); + } + } + while let Some(event) = $parser.next() { + match event { + $($end_event)|* => break, + Event::Text(ref s) => { + inner($id, s); + if $escape { + $buf.push_str(&format!("{}", Escape(s))); + } else { + $buf.push_str(s); + } + } + Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => { + $buf.push(' '); + } + x => { + looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id); + } + } + } + }} +} 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 + shorter: MarkdownOutputStyle) -> fmt::Result { + fn code_block(parser: &mut Parser, buffer: &mut String, lang: &str) { + let mut origtext = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::CodeBlock(_)) => break, + Event::Text(ref s) => { + origtext.push_str(s); } - }; + _ => {} + } + } + let origtext = origtext.trim_left(); + debug!("docblock: ==============\n{:?}\n=======", origtext); - let lines = origtext.lines().filter(|l| { - stripped_filtered_line(*l).is_none() - }); - let text = lines.collect::>().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::>().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(") { - "&version=nightly" + let lines = origtext.lines().filter(|l| { + stripped_filtered_line(*l).is_none() + }); + let text = lines.collect::>().join("\n"); + let block_info = if lang.is_empty() { + LangString::all_false() + } else { + LangString::parse(lang) + }; + if !block_info.rust { + buffer.push_str(&format!("
{}
", + lang, text)); + return + } + PLAYGROUND.with(|play| { + // insert newline to clearly separate it from the + // previous block so we can shorten the html output + buffer.push('\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::>().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(") { + "&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 { - "" - }; - // 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'*' + write!(test_escaped, "%{:02X}", b).unwrap(); } - 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#"Run"#, - 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()); - }) - } + } + Some(format!( + r#"Run"#, + url, test_escaped, channel + )) + }); + buffer.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); + }); } - 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 _); } + fn heading(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, level: i32) { + let mut ret = String::new(); + let mut id = String::new(); + event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), + Event::End(Tag::Header(_))); + ret = ret.trim_right().to_owned(); - // 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 '', '' 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!["", "", "", "", - "", "", - "<", ">", "&", "'", """]; - 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() { @@ -353,145 +237,309 @@ pub fn render(w: &mut fmt::Formatter, } }).collect::(); - 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())) + let sec = toc_builder.as_mut().map_or("".to_owned(), |builder| { + format!("{} ", builder.push(level as u32, ret.clone(), id.clone())) }); // Render the HTML - let text = format!("\ - {sec}{}", - 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) - }; + buffer.push_str(&format!("\ + {sec}{}", + ret, lvl = level, id = id, sec = sec)); + } - let content = format!("{}", 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 + fn inline_code(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); + buffer.push_str(&format!("{}", + Escape(&collapse_whitespace(content.trim_right())))); } - 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); + fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, url: &str, mut title: String, + id: &mut Option<&mut String>) { + event_loop_break!(parser, toc_builder, shorter, title, true, id, + Event::End(Tag::Link(_, _))); + buffer.push_str(&format!("{}", url, title)); + } - 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); + fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, + Event::End(Tag::Paragraph)); + buffer.push_str(&format!("

{}

", content.trim_right())); + } - hoedown_html_renderer_free(renderer); + fn table_cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) | + Event::End(Tag::TableCell)); + buffer.push_str(&format!("{}", content.trim())); + } - let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| { - write!(w, "", builder.into_toc()) - }); + fn table_row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) => break, + Event::Start(Tag::TableCell) => { + table_cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); + } + } + } + buffer.push_str(&format!("{}", content)); + } - if ret.is_ok() { - let buf = (*ob).as_bytes(); - ret = w.write_str(str::from_utf8(buf).unwrap()); + fn table_head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableCell) => { + table_cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); + } + } + } + if !content.is_empty() { + buffer.push_str(&format!("{}", content.replace("td>", "th>"))); } - hoedown_buffer_free(ob); - ret } -} -pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { - extern fn block(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - lang: *const hoedown_buffer, - data: *const hoedown_renderer_data, - line: libc::size_t) { - unsafe { - if text.is_null() { return } - let block_info = if lang.is_null() { - LangString::all_false() - } else { - let lang = (*lang).as_bytes(); - let s = str::from_utf8(lang).unwrap(); - LangString::parse(s) - }; - if !block_info.rust { return } - let text = (*text).as_bytes(); - let opaque = (*data).opaque as *mut hoedown_html_renderer_state; - let tests = &mut *((*opaque).opaque as *mut ::test::Collector); - let text = str::from_utf8(text).unwrap(); - let lines = text.lines().map(|l| { - stripped_filtered_line(l).unwrap_or(l) - }); - let text = lines.collect::>().join("\n"); - let line = tests.get_line() + line; - 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); + fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + let mut rows = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableHead) => { + table_head(parser, &mut content, toc_builder, shorter); + } + Event::Start(Tag::TableRow) => { + table_row(parser, &mut rows, toc_builder, shorter); + } + _ => {} + } } + buffer.push_str(&format!("{}{}
", + content, + if shorter.is_compact() || rows.is_empty() { + String::new() + } else { + format!("{}", rows) + })); } - extern fn header(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - level: libc::c_int, data: *const hoedown_renderer_data, - _: libc::size_t) { - unsafe { - let opaque = (*data).opaque as *mut hoedown_html_renderer_state; - let tests = &mut *((*opaque).opaque as *mut ::test::Collector); - if text.is_null() { - tests.register_header("", level as u32); - } else { - let text = (*text).as_bytes(); - let text = str::from_utf8(text).unwrap(); - tests.register_header(text, level as u32); + fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, + Event::End(Tag::BlockQuote)); + buffer.push_str(&format!("
{}
", content.trim_right())); + } + + fn list_item(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Item) => break, + Event::Text(ref s) => { + content.push_str(&format!("{}", Escape(s))); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); + } + } + } + buffer.push_str(&format!("
  • {}
  • ", content)); + } + + fn list(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::List(_)) => break, + Event::Start(Tag::Item) => { + list_item(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); + } + } + } + buffer.push_str(&format!("
      {}
    ", content)); + } + + fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, false, id, + Event::End(Tag::Emphasis)); + buffer.push_str(&format!("{}", content)); + } + + fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, false, id, + Event::End(Tag::Strong)); + buffer.push_str(&format!("{}", content)); + } + + fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) -> bool { + if let Some(event) = next_event { + match event { + Event::Start(Tag::CodeBlock(lang)) => { + code_block(parser, buffer, &*lang); + } + Event::Start(Tag::Header(level)) => { + heading(parser, buffer, toc_builder, shorter, level); + } + Event::Start(Tag::Code) => { + inline_code(parser, buffer, toc_builder, shorter, id); + } + Event::Start(Tag::Paragraph) => { + paragraph(parser, buffer, toc_builder, shorter, id); + } + Event::Start(Tag::Link(ref url, ref t)) => { + link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); + } + Event::Start(Tag::Table(_)) => { + table(parser, buffer, toc_builder, shorter); + } + Event::Start(Tag::BlockQuote) => { + blockquote(parser, buffer, toc_builder, shorter); + } + Event::Start(Tag::List(_)) => { + list(parser, buffer, toc_builder, shorter); + } + Event::Start(Tag::Emphasis) => { + emphasis(parser, buffer, toc_builder, shorter, id); + } + Event::Start(Tag::Strong) => { + strong(parser, buffer, toc_builder, shorter, id); + } + Event::Html(h) | Event::InlineHtml(h) => { + buffer.push_str(&*h); + } + _ => {} } + shorter.is_fancy() + } else { + false + } + } + + let mut toc_builder = if print_toc { + Some(TocBuilder::new()) + } else { + None + }; + let mut buffer = String::new(); + 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, shorter, &mut None) { + break } } + let mut ret = toc_builder.map_or(Ok(()), |builder| { + write!(w, "", builder.into_toc()) + }); + + if ret.is_ok() { + ret = w.write_str(&buffer); + } + ret +} +pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { tests.set_position(position); - unsafe { - let ob = hoedown_buffer_new(DEF_OUNIT); - let renderer = hoedown_html_renderer_new(0, 0); - (*renderer).blockcode = Some(block); - (*renderer).header = Some(header); - (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque - = tests as *mut _ as *mut libc::c_void; - - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); - hoedown_document_render(document, ob, doc.as_ptr(), - doc.len() as libc::size_t); - hoedown_document_free(document); - - hoedown_html_renderer_free(renderer); - hoedown_buffer_free(ob); + + let mut parser = Parser::new(doc); + let mut prev_offset = 0; + let mut nb_lines = 0; + let mut register_header = None; + '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::>().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; + } + 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; + } + _ => {} + } } } @@ -570,17 +618,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, MarkdownOutputStyle::Fancy) } } @@ -589,62 +637,67 @@ 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) + render(fmt, md, false, MarkdownOutputStyle::Fancy) } } pub fn plain_summary_line(md: &str) -> String { - extern fn link(_ob: *mut hoedown_buffer, - _link: *const hoedown_buffer, - _title: *const hoedown_buffer, - content: *const hoedown_buffer, - data: *const hoedown_renderer_data, - _: libc::size_t) -> libc::c_int - { - unsafe { - if !content.is_null() && (*content).size > 0 { - let ob = (*data).opaque as *mut hoedown_buffer; - hoedown_buffer_put(ob, (*content).data as *const libc::c_char, - (*content).size); - } - } - 1 - } - - extern fn normal_text(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - data: *const hoedown_renderer_data, - _: libc::size_t) - { - unsafe { - let ob = (*data).opaque as *mut hoedown_buffer; - hoedown_buffer_put(ob, (*text).data as *const libc::c_char, - (*text).size); - } + struct ParserWrapper<'a> { + inner: Parser<'a>, + is_in: isize, + is_first: bool, } - unsafe { - let ob = hoedown_buffer_new(DEF_OUNIT); - let mut plain_renderer: hoedown_renderer = ::std::mem::zeroed(); - let renderer: *mut hoedown_renderer = &mut plain_renderer; - (*renderer).opaque = ob as *mut libc::c_void; - (*renderer).link = Some(link); - (*renderer).normal_text = Some(normal_text); + impl<'a> Iterator for ParserWrapper<'a> { + type Item = String; - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); - hoedown_document_render(document, ob, md.as_ptr(), - md.len() as libc::size_t); - hoedown_document_free(document); - let plain_slice = (*ob).as_bytes(); - let plain = str::from_utf8(plain_slice).unwrap_or("").to_owned(); - hoedown_buffer_free(ob); - plain + fn next(&mut self) -> Option { + let next_event = self.inner.next(); + if next_event.is_none() { + return None + } + let next_event = next_event.unwrap(); + let (ret, is_in) = match next_event { + Event::Start(Tag::Paragraph) => (None, 1), + Event::Start(Tag::Link(_, ref t)) if !self.is_first => { + (Some(t.as_ref().to_owned()), 1) + } + Event::Start(Tag::Code) => (Some("`".to_owned()), 1), + Event::End(Tag::Code) => (Some("`".to_owned()), -1), + Event::Start(Tag::Header(_)) => (None, 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) | Event::End(Tag::Header(_)) => (None, -1), + _ => (None, 0), + }; + if is_in > 0 || (is_in < 0 && self.is_in > 0) { + self.is_in += is_in; + } + if ret.is_some() { + self.is_first = false; + ret + } else { + Some(String::new()) + } + } + } + let mut s = String::with_capacity(md.len() * 3 / 2); + let mut p = ParserWrapper { + inner: Parser::new(md), + is_in: 0, + is_first: true, + }; + while let Some(t) = p.next() { + if !t.is_empty() { + s.push_str(&t); + } } + s } #[cfg(test)] mod tests { - use super::{LangString, Markdown, MarkdownHtml}; + use super::{LangString, Markdown, MarkdownHtml, MarkdownOutputStyle}; use super::plain_summary_line; use html::render::reset_ids; @@ -684,52 +737,52 @@ mod tests { #[test] fn issue_17736() { let markdown = "# title"; - format!("{}", Markdown(markdown)); + format!("{}", Markdown(markdown, MarkdownOutputStyle::Fancy)); reset_ids(true); } #[test] fn test_header() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); - assert_eq!(output, expect); + let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); + assert_eq!(output, expect, "original: {}", input); reset_ids(true); } - t("# Foo bar", "\n

    \ - Foo bar

    "); - t("## Foo-bar_baz qux", "\n

    Foo-bar_baz qux

    "); + t("# Foo bar", "

    \ + Foo bar

    "); + t("## Foo-bar_baz qux", "

    Foo-bar_baz qux

    "); t("### **Foo** *bar* baz!?!& -_qux_-%", - "\n

    \ - Foo \ - bar baz!?!& -_qux_-%

    "); - t("####**Foo?** & \\*bar?!* _`baz`_ ❤ #qux", - "\n

    \ - Foo? & *bar?!* \ + "

    \ + Foo \ + bar baz!?!& -qux-%

    "); + t("#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux", + "

    \ + Foo? & *bar?!* \ baz ❤ #qux

    "); } #[test] fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); - assert_eq!(output, expect); + let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); + assert_eq!(output, expect, "original: {}", input); } let test = || { - t("# Example", "\n

    \ - Example

    "); - t("# Panics", "\n

    \ - Panics

    "); - t("# Example", "\n

    \ - Example

    "); - t("# Main", "\n

    \ - Main

    "); - t("# Example", "\n

    \ - Example

    "); - t("# Panics", "\n

    \ - Panics

    "); + t("# Example", "

    \ + Example

    "); + t("# Panics", "

    \ + Panics

    "); + t("# Example", "

    \ + Example

    "); + t("# Main", "

    \ + Main

    "); + t("# Example", "

    \ + Example

    "); + t("# Panics", "

    \ + Panics

    "); }; test(); reset_ids(true); @@ -740,7 +793,7 @@ mod tests { fn test_plain_summary_line() { fn t(input: &str, expect: &str) { let output = plain_summary_line(input); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); } t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); @@ -754,10 +807,10 @@ mod tests { fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let output = format!("{}", MarkdownHtml(input)); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); } - t("`Struct<'a, T>`", "

    Struct<'a, T>

    \n"); - t("Struct<'a, T>", "

    Struct<'a, T>

    \n"); + t("`Struct<'a, T>`", "

    Struct<'a, T>

    "); + t("Struct<'a, T>", "

    Struct<'a, T>

    "); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 612e765a499b7..f0b624105e347 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; use html::item_type::ItemType; -use html::markdown::{self, Markdown, MarkdownHtml}; +use html::markdown::{self, Markdown, MarkdownHtml, MarkdownOutputStyle}; use html::{highlight, layout}; /// A pair of name and its optional document. @@ -1650,7 +1650,8 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin } else { format!("{}", &plain_summary_line(Some(s))) }; - write!(w, "
    {}
    ", Markdown(&markdown))?; + write!(w, "
    {}
    ", + Markdown(&markdown, MarkdownOutputStyle::Fancy))?; } Ok(()) } @@ -1683,7 +1684,8 @@ 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, "
    {}
    ", - Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s), + MarkdownOutputStyle::Fancy))?; } Ok(()) } @@ -1871,7 +1873,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = shorter(Some(&Markdown(doc_value).to_string())), + docs = shorter(Some(&Markdown(doc_value, + MarkdownOutputStyle::Compact).to_string())), class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -2901,7 +2904,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
    {}
    ", Markdown(dox))?; + write!(w, "
    {}
    ", Markdown(dox, MarkdownOutputStyle::Fancy))?; } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 8dd03f6edc4d5..447d60018d912 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -9,7 +9,7 @@ // except according to those terms. #![crate_name = "rustdoc"] -#![unstable(feature = "rustdoc", issue = "27812")] +#![unstable(feature = "rustc_private", issue = "27812")] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", @@ -48,6 +48,7 @@ extern crate test as testing; extern crate std_unicode; #[macro_use] extern crate log; extern crate rustc_errors as errors; +extern crate pulldown_cmark; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 5fadda030a4b4..5cc0f03e1f629 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string}; use html::render::reset_ids; use html::escape::Escape; use html::markdown; -use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; +use html::markdown::{Markdown, MarkdownWithToc, MarkdownOutputStyle, find_testable_code}; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. @@ -96,7 +96,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, MarkdownOutputStyle::Fancy)) }; let err = write!( diff --git a/src/rt/hoedown b/src/rt/hoedown deleted file mode 160000 index da282f1bb7277..0000000000000 --- a/src/rt/hoedown +++ /dev/null @@ -1 +0,0 @@ -Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 diff --git a/src/rustc/rustdoc.rs b/src/rustc/rustdoc.rs index 6fecd3a27a8a4..a4f43c42623d3 100644 --- a/src/rustc/rustdoc.rs +++ b/src/rustc/rustdoc.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustdoc)] +#![feature(rustc_private)] extern crate rustdoc; diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index e33df0dfbc8de..1d4f2c60d544f 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle, PLAYGROUND}; use rustc_serialize::json; enum OutputFormat { @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc))?, + Some(ref desc) => write!(output, "{}", Markdown(desc, MarkdownOutputStyle::Fancy))?, None => write!(output, "

    No description.

    \n")?, }