Re-enable hoedown by default
This commit is contained in:
parent
ff13b7c918
commit
80a2a94d5a
7 changed files with 382 additions and 150 deletions
|
@ -32,6 +32,7 @@ use std::ascii::AsciiExt;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
use std::ffi::CString;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::str;
|
use std::str;
|
||||||
use syntax::feature_gate::UnstableFeatures;
|
use syntax::feature_gate::UnstableFeatures;
|
||||||
|
@ -40,21 +41,28 @@ use syntax::codemap::Span;
|
||||||
use html::render::derive_id;
|
use html::render::derive_id;
|
||||||
use html::toc::TocBuilder;
|
use html::toc::TocBuilder;
|
||||||
use html::highlight;
|
use html::highlight;
|
||||||
|
use html::escape::Escape;
|
||||||
use test;
|
use test;
|
||||||
|
|
||||||
use pulldown_cmark::{html, Event, Tag, Parser};
|
use pulldown_cmark::{html, Event, Tag, Parser};
|
||||||
use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};
|
use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
|
pub enum RenderType {
|
||||||
|
Hoedown,
|
||||||
|
Pulldown,
|
||||||
|
}
|
||||||
|
|
||||||
/// A unit struct which has the `fmt::Display` trait implemented. When
|
/// A unit struct which has the `fmt::Display` trait implemented. When
|
||||||
/// formatted, this struct will emit the HTML corresponding to the rendered
|
/// formatted, this struct will emit the HTML corresponding to the rendered
|
||||||
/// version of the contained markdown string.
|
/// version of the contained markdown string.
|
||||||
// The second parameter is whether we need a shorter version or not.
|
// The second parameter is whether we need a shorter version or not.
|
||||||
pub struct Markdown<'a>(pub &'a str);
|
pub struct Markdown<'a>(pub &'a str, pub RenderType);
|
||||||
/// A unit struct like `Markdown`, that renders the markdown with a
|
/// A unit struct like `Markdown`, that renders the markdown with a
|
||||||
/// table of contents.
|
/// table of contents.
|
||||||
pub struct MarkdownWithToc<'a>(pub &'a str);
|
pub struct MarkdownWithToc<'a>(pub &'a str, pub RenderType);
|
||||||
/// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
|
/// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
|
||||||
pub struct MarkdownHtml<'a>(pub &'a str);
|
pub struct MarkdownHtml<'a>(pub &'a str, pub RenderType);
|
||||||
/// A unit struct like `Markdown`, that renders only the first paragraph.
|
/// A unit struct like `Markdown`, that renders only the first paragraph.
|
||||||
pub struct MarkdownSummaryLine<'a>(pub &'a str);
|
pub struct MarkdownSummaryLine<'a>(pub &'a str);
|
||||||
|
|
||||||
|
@ -73,6 +81,14 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a new string with all consecutive whitespace collapsed into
|
||||||
|
/// single spaces.
|
||||||
|
///
|
||||||
|
/// Any leading or trailing whitespace will be trimmed.
|
||||||
|
fn collapse_whitespace(s: &str) -> String {
|
||||||
|
s.split_whitespace().collect::<Vec<_>>().join(" ")
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert chars from a title for an id.
|
/// Convert chars from a title for an id.
|
||||||
///
|
///
|
||||||
/// "Hello, world!" -> "hello-world"
|
/// "Hello, world!" -> "hello-world"
|
||||||
|
@ -368,6 +384,7 @@ const HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3;
|
||||||
const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
|
const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
|
||||||
const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8;
|
const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8;
|
||||||
const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2;
|
const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2;
|
||||||
|
const HOEDOWN_HTML_ESCAPE: libc::c_uint = 1 << 1;
|
||||||
|
|
||||||
const HOEDOWN_EXTENSIONS: libc::c_uint =
|
const HOEDOWN_EXTENSIONS: libc::c_uint =
|
||||||
HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES |
|
HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES |
|
||||||
|
@ -462,6 +479,13 @@ struct hoedown_buffer {
|
||||||
unit: libc::size_t,
|
unit: libc::size_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>,
|
||||||
|
}
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
fn hoedown_html_renderer_new(render_flags: libc::c_uint,
|
fn hoedown_html_renderer_new(render_flags: libc::c_uint,
|
||||||
nesting_level: libc::c_int)
|
nesting_level: libc::c_int)
|
||||||
|
@ -478,6 +502,7 @@ extern {
|
||||||
fn hoedown_document_free(md: *mut hoedown_document);
|
fn hoedown_document_free(md: *mut hoedown_document);
|
||||||
|
|
||||||
fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer;
|
fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer;
|
||||||
|
fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char);
|
||||||
fn hoedown_buffer_free(b: *mut hoedown_buffer);
|
fn hoedown_buffer_free(b: *mut hoedown_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,6 +512,208 @@ impl hoedown_buffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(") {
|
||||||
|
"&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>",
|
||||||
|
"<", ">", "&", "'", """];
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
|
pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
|
||||||
extern fn block(_ob: *mut hoedown_buffer,
|
extern fn block(_ob: *mut hoedown_buffer,
|
||||||
text: *const hoedown_buffer,
|
text: *const hoedown_buffer,
|
||||||
|
@ -511,9 +738,24 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
|
||||||
stripped_filtered_line(l).unwrap_or(l)
|
stripped_filtered_line(l).unwrap_or(l)
|
||||||
});
|
});
|
||||||
let filename = tests.get_filename();
|
let filename = tests.get_filename();
|
||||||
|
|
||||||
|
if tests.render_type == RenderType::Hoedown {
|
||||||
|
let text = (*text).as_bytes();
|
||||||
|
let text = str::from_utf8(text).unwrap();
|
||||||
|
let lines = text.lines().map(|l| {
|
||||||
|
stripped_filtered_line(l).unwrap_or(l)
|
||||||
|
});
|
||||||
|
let text = lines.collect::<Vec<&str>>().join("\n");
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
tests.add_old_test(lines.collect::<Vec<&str>>().join("\n"), filename);
|
tests.add_old_test(lines.collect::<Vec<&str>>().join("\n"), filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern fn header(_ob: *mut hoedown_buffer,
|
extern fn header(_ob: *mut hoedown_buffer,
|
||||||
text: *const hoedown_buffer,
|
text: *const hoedown_buffer,
|
||||||
|
@ -533,7 +775,6 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
|
||||||
}
|
}
|
||||||
|
|
||||||
tests.set_position(position);
|
tests.set_position(position);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ob = hoedown_buffer_new(DEF_OUNIT);
|
let ob = hoedown_buffer_new(DEF_OUNIT);
|
||||||
let renderer = hoedown_html_renderer_new(0, 0);
|
let renderer = hoedown_html_renderer_new(0, 0);
|
||||||
|
@ -702,10 +943,13 @@ impl LangString {
|
||||||
|
|
||||||
impl<'a> fmt::Display for Markdown<'a> {
|
impl<'a> fmt::Display for Markdown<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let Markdown(md) = *self;
|
let Markdown(md, render_type) = *self;
|
||||||
|
|
||||||
// This is actually common enough to special-case
|
// This is actually common enough to special-case
|
||||||
if md.is_empty() { return Ok(()) }
|
if md.is_empty() { return Ok(()) }
|
||||||
|
if render_type == RenderType::Hoedown {
|
||||||
|
render(fmt, md, false, 0)
|
||||||
|
} else {
|
||||||
let mut opts = Options::empty();
|
let mut opts = Options::empty();
|
||||||
opts.insert(OPTION_ENABLE_TABLES);
|
opts.insert(OPTION_ENABLE_TABLES);
|
||||||
opts.insert(OPTION_ENABLE_FOOTNOTES);
|
opts.insert(OPTION_ENABLE_FOOTNOTES);
|
||||||
|
@ -719,12 +963,16 @@ impl<'a> fmt::Display for Markdown<'a> {
|
||||||
|
|
||||||
fmt.write_str(&s)
|
fmt.write_str(&s)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for MarkdownWithToc<'a> {
|
impl<'a> fmt::Display for MarkdownWithToc<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let MarkdownWithToc(md) = *self;
|
let MarkdownWithToc(md, render_type) = *self;
|
||||||
|
|
||||||
|
if render_type == RenderType::Hoedown {
|
||||||
|
render(fmt, md, true, 0)
|
||||||
|
} else {
|
||||||
let mut opts = Options::empty();
|
let mut opts = Options::empty();
|
||||||
opts.insert(OPTION_ENABLE_TABLES);
|
opts.insert(OPTION_ENABLE_TABLES);
|
||||||
opts.insert(OPTION_ENABLE_FOOTNOTES);
|
opts.insert(OPTION_ENABLE_FOOTNOTES);
|
||||||
|
@ -742,14 +990,18 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> {
|
||||||
|
|
||||||
fmt.write_str(&s)
|
fmt.write_str(&s)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for MarkdownHtml<'a> {
|
impl<'a> fmt::Display for MarkdownHtml<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let MarkdownHtml(md) = *self;
|
let MarkdownHtml(md, render_type) = *self;
|
||||||
|
|
||||||
// This is actually common enough to special-case
|
// This is actually common enough to special-case
|
||||||
if md.is_empty() { return Ok(()) }
|
if md.is_empty() { return Ok(()) }
|
||||||
|
if render_type == RenderType::Hoedown {
|
||||||
|
render(fmt, md, false, HOEDOWN_HTML_ESCAPE)
|
||||||
|
} else {
|
||||||
let mut opts = Options::empty();
|
let mut opts = Options::empty();
|
||||||
opts.insert(OPTION_ENABLE_TABLES);
|
opts.insert(OPTION_ENABLE_TABLES);
|
||||||
opts.insert(OPTION_ENABLE_FOOTNOTES);
|
opts.insert(OPTION_ENABLE_FOOTNOTES);
|
||||||
|
@ -769,6 +1021,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> {
|
||||||
|
|
||||||
fmt.write_str(&s)
|
fmt.write_str(&s)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for MarkdownSummaryLine<'a> {
|
impl<'a> fmt::Display for MarkdownSummaryLine<'a> {
|
||||||
|
|
|
@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace};
|
||||||
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
|
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
|
||||||
use html::format::fmt_impl_for_trait_page;
|
use html::format::fmt_impl_for_trait_page;
|
||||||
use html::item_type::ItemType;
|
use html::item_type::ItemType;
|
||||||
use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine};
|
use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, RenderType};
|
||||||
use html::{highlight, layout};
|
use html::{highlight, layout};
|
||||||
|
|
||||||
/// A pair of name and its optional document.
|
/// A pair of name and its optional document.
|
||||||
|
@ -98,6 +98,7 @@ pub struct Context {
|
||||||
/// publicly reused items to redirect to the right location.
|
/// publicly reused items to redirect to the right location.
|
||||||
pub render_redirect_pages: bool,
|
pub render_redirect_pages: bool,
|
||||||
pub shared: Arc<SharedContext>,
|
pub shared: Arc<SharedContext>,
|
||||||
|
pub render_type: RenderType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SharedContext {
|
pub struct SharedContext {
|
||||||
|
@ -433,7 +434,8 @@ pub fn run(mut krate: clean::Crate,
|
||||||
dst: PathBuf,
|
dst: PathBuf,
|
||||||
passes: FxHashSet<String>,
|
passes: FxHashSet<String>,
|
||||||
css_file_extension: Option<PathBuf>,
|
css_file_extension: Option<PathBuf>,
|
||||||
renderinfo: RenderInfo) -> Result<(), Error> {
|
renderinfo: RenderInfo,
|
||||||
|
render_type: RenderType) -> Result<(), Error> {
|
||||||
let src_root = match krate.src.parent() {
|
let src_root = match krate.src.parent() {
|
||||||
Some(p) => p.to_path_buf(),
|
Some(p) => p.to_path_buf(),
|
||||||
None => PathBuf::new(),
|
None => PathBuf::new(),
|
||||||
|
@ -495,6 +497,7 @@ pub fn run(mut krate: clean::Crate,
|
||||||
dst: dst,
|
dst: dst,
|
||||||
render_redirect_pages: false,
|
render_redirect_pages: false,
|
||||||
shared: Arc::new(scx),
|
shared: Arc::new(scx),
|
||||||
|
render_type: render_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Crawl the crate to build various caches used for the output
|
// Crawl the crate to build various caches used for the output
|
||||||
|
@ -1638,11 +1641,12 @@ fn plain_summary_line(s: Option<&str>) -> String {
|
||||||
|
|
||||||
fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
|
fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
|
||||||
document_stability(w, cx, item)?;
|
document_stability(w, cx, item)?;
|
||||||
document_full(w, item)?;
|
document_full(w, item, cx.render_type)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink) -> fmt::Result {
|
fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink,
|
||||||
|
render_type: RenderType) -> fmt::Result {
|
||||||
if let Some(s) = item.doc_value() {
|
if let Some(s) = item.doc_value() {
|
||||||
let markdown = if s.contains('\n') {
|
let markdown = if s.contains('\n') {
|
||||||
format!("{} [Read more]({})",
|
format!("{} [Read more]({})",
|
||||||
|
@ -1651,7 +1655,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
|
||||||
format!("{}", &plain_summary_line(Some(s)))
|
format!("{}", &plain_summary_line(Some(s)))
|
||||||
};
|
};
|
||||||
write!(w, "<div class='docblock'>{}</div>",
|
write!(w, "<div class='docblock'>{}</div>",
|
||||||
Markdown(&markdown))?;
|
Markdown(&markdown, render_type))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1681,10 +1685,11 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
|
fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
|
||||||
|
render_type: RenderType) -> fmt::Result {
|
||||||
if let Some(s) = get_doc_value(item) {
|
if let Some(s) = get_doc_value(item) {
|
||||||
write!(w, "<div class='docblock'>{}</div>",
|
write!(w, "<div class='docblock'>{}</div>",
|
||||||
Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?;
|
Markdown(&format!("{}{}", md_render_assoc_item(item), s), render_type))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1872,7 +1877,13 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
|
||||||
</tr>",
|
</tr>",
|
||||||
name = *myitem.name.as_ref().unwrap(),
|
name = *myitem.name.as_ref().unwrap(),
|
||||||
stab_docs = stab_docs,
|
stab_docs = stab_docs,
|
||||||
docs = MarkdownSummaryLine(doc_value),
|
docs = if cx.render_type == RenderType::Hoedown {
|
||||||
|
format!("{}",
|
||||||
|
shorter(Some(&Markdown(doc_value,
|
||||||
|
RenderType::Hoedown).to_string())))
|
||||||
|
} else {
|
||||||
|
format!("{}", MarkdownSummaryLine(doc_value))
|
||||||
|
},
|
||||||
class = myitem.type_(),
|
class = myitem.type_(),
|
||||||
stab = myitem.stability_class().unwrap_or("".to_string()),
|
stab = myitem.stability_class().unwrap_or("".to_string()),
|
||||||
unsafety_flag = unsafety_flag,
|
unsafety_flag = unsafety_flag,
|
||||||
|
@ -1915,7 +1926,9 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
let text = format!("Deprecated{}{}", since, MarkdownHtml(&deprecated_reason));
|
let text = format!("Deprecated{}{}",
|
||||||
|
since,
|
||||||
|
MarkdownHtml(&deprecated_reason, cx.render_type));
|
||||||
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
|
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1944,7 +1957,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
|
||||||
let text = format!("<summary><span class=microscope>🔬</span> \
|
let text = format!("<summary><span class=microscope>🔬</span> \
|
||||||
This is a nightly-only experimental API. {}\
|
This is a nightly-only experimental API. {}\
|
||||||
</summary>{}",
|
</summary>{}",
|
||||||
unstable_extra, MarkdownHtml(&stab.unstable_reason));
|
unstable_extra,
|
||||||
|
MarkdownHtml(&stab.unstable_reason, cx.render_type));
|
||||||
stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
|
stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
|
||||||
text));
|
text));
|
||||||
}
|
}
|
||||||
|
@ -1964,7 +1978,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let text = format!("Deprecated{}{}", since, MarkdownHtml(¬e));
|
let text = format!("Deprecated{}{}", since, MarkdownHtml(¬e, cx.render_type));
|
||||||
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
|
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2900,7 +2914,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
|
||||||
write!(w, "</span>")?;
|
write!(w, "</span>")?;
|
||||||
write!(w, "</h3>\n")?;
|
write!(w, "</h3>\n")?;
|
||||||
if let Some(ref dox) = i.impl_item.doc_value() {
|
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, cx.render_type))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2999,11 +3013,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
|
||||||
// because impls can't have a stability.
|
// because impls can't have a stability.
|
||||||
document_stability(w, cx, it)?;
|
document_stability(w, cx, it)?;
|
||||||
if get_doc_value(item).is_some() {
|
if get_doc_value(item).is_some() {
|
||||||
document_full(w, item)?;
|
document_full(w, item, cx.render_type)?;
|
||||||
} else {
|
} else {
|
||||||
// In case the item isn't documented,
|
// In case the item isn't documented,
|
||||||
// provide short documentation from the trait.
|
// provide short documentation from the trait.
|
||||||
document_short(w, it, link)?;
|
document_short(w, it, link, cx.render_type)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -3011,7 +3025,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
document_stability(w, cx, item)?;
|
document_stability(w, cx, item)?;
|
||||||
document_short(w, item, link)?;
|
document_short(w, item, link, cx.render_type)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -93,6 +93,8 @@ pub mod test;
|
||||||
|
|
||||||
use clean::AttributesExt;
|
use clean::AttributesExt;
|
||||||
|
|
||||||
|
use html::markdown::RenderType;
|
||||||
|
|
||||||
struct Output {
|
struct Output {
|
||||||
krate: clean::Crate,
|
krate: clean::Crate,
|
||||||
renderinfo: html::render::RenderInfo,
|
renderinfo: html::render::RenderInfo,
|
||||||
|
@ -169,6 +171,7 @@ pub fn opts() -> Vec<RustcOptGroup> {
|
||||||
"URL to send code snippets to, may be reset by --markdown-playground-url \
|
"URL to send code snippets to, may be reset by --markdown-playground-url \
|
||||||
or `#![doc(html_playground_url=...)]`",
|
or `#![doc(html_playground_url=...)]`",
|
||||||
"URL")),
|
"URL")),
|
||||||
|
unstable(optflag("", "enable-commonmark", "to enable commonmark doc rendering/testing")),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,6 +253,12 @@ pub fn main_args(args: &[String]) -> isize {
|
||||||
let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s));
|
let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s));
|
||||||
let cfgs = matches.opt_strs("cfg");
|
let cfgs = matches.opt_strs("cfg");
|
||||||
|
|
||||||
|
let render_type = if matches.opt_present("enable-commonmark") {
|
||||||
|
RenderType::Pulldown
|
||||||
|
} else {
|
||||||
|
RenderType::Hoedown
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(ref p) = css_file_extension {
|
if let Some(ref p) = css_file_extension {
|
||||||
if !p.is_file() {
|
if !p.is_file() {
|
||||||
writeln!(
|
writeln!(
|
||||||
|
@ -273,15 +282,17 @@ pub fn main_args(args: &[String]) -> isize {
|
||||||
|
|
||||||
match (should_test, markdown_input) {
|
match (should_test, markdown_input) {
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot)
|
return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type)
|
||||||
}
|
}
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot)
|
return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot,
|
||||||
|
render_type)
|
||||||
}
|
}
|
||||||
(false, true) => return markdown::render(input,
|
(false, true) => return markdown::render(input,
|
||||||
output.unwrap_or(PathBuf::from("doc")),
|
output.unwrap_or(PathBuf::from("doc")),
|
||||||
&matches, &external_html,
|
&matches, &external_html,
|
||||||
!matches.opt_present("markdown-no-toc")),
|
!matches.opt_present("markdown-no-toc"),
|
||||||
|
render_type),
|
||||||
(false, false) => {}
|
(false, false) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +306,8 @@ pub fn main_args(args: &[String]) -> isize {
|
||||||
output.unwrap_or(PathBuf::from("doc")),
|
output.unwrap_or(PathBuf::from("doc")),
|
||||||
passes.into_iter().collect(),
|
passes.into_iter().collect(),
|
||||||
css_file_extension,
|
css_file_extension,
|
||||||
renderinfo)
|
renderinfo,
|
||||||
|
render_type)
|
||||||
.expect("failed to generate documentation");
|
.expect("failed to generate documentation");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ use html::render::reset_ids;
|
||||||
use html::escape::Escape;
|
use html::escape::Escape;
|
||||||
use html::markdown;
|
use html::markdown;
|
||||||
use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code};
|
use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code};
|
||||||
|
use html::markdown::RenderType;
|
||||||
use test::{TestOptions, Collector};
|
use test::{TestOptions, Collector};
|
||||||
|
|
||||||
/// Separate any lines at the start of the file that begin with `# ` or `%`.
|
/// Separate any lines at the start of the file that begin with `# ` or `%`.
|
||||||
|
@ -50,7 +51,8 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
|
||||||
/// Render `input` (e.g. "foo.md") into an HTML file in `output`
|
/// Render `input` (e.g. "foo.md") into an HTML file in `output`
|
||||||
/// (e.g. output = "bar" => "bar/foo.html").
|
/// (e.g. output = "bar" => "bar/foo.html").
|
||||||
pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
|
pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
|
||||||
external_html: &ExternalHtml, include_toc: bool) -> isize {
|
external_html: &ExternalHtml, include_toc: bool,
|
||||||
|
render_type: RenderType) -> isize {
|
||||||
let input_p = Path::new(input);
|
let input_p = Path::new(input);
|
||||||
output.push(input_p.file_stem().unwrap());
|
output.push(input_p.file_stem().unwrap());
|
||||||
output.set_extension("html");
|
output.set_extension("html");
|
||||||
|
@ -94,9 +96,9 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
|
||||||
reset_ids(false);
|
reset_ids(false);
|
||||||
|
|
||||||
let rendered = if include_toc {
|
let rendered = if include_toc {
|
||||||
format!("{}", MarkdownWithToc(text))
|
format!("{}", MarkdownWithToc(text, render_type))
|
||||||
} else {
|
} else {
|
||||||
format!("{}", Markdown(text))
|
format!("{}", Markdown(text, render_type))
|
||||||
};
|
};
|
||||||
|
|
||||||
let err = write!(
|
let err = write!(
|
||||||
|
@ -147,7 +149,8 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
|
||||||
|
|
||||||
/// Run any tests/code examples in the markdown file `input`.
|
/// Run any tests/code examples in the markdown file `input`.
|
||||||
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
|
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
|
||||||
mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>) -> isize {
|
mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
|
||||||
|
render_type: RenderType) -> isize {
|
||||||
let input_str = match load_string(input) {
|
let input_str = match load_string(input) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(LoadStringError::ReadFail) => return 1,
|
Err(LoadStringError::ReadFail) => return 1,
|
||||||
|
@ -158,7 +161,8 @@ pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
|
||||||
opts.no_crate_inject = true;
|
opts.no_crate_inject = true;
|
||||||
let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
|
let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
|
||||||
true, opts, maybe_sysroot, None,
|
true, opts, maybe_sysroot, None,
|
||||||
Some(input.to_owned()));
|
Some(input.to_owned()),
|
||||||
|
render_type);
|
||||||
old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
|
old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
|
||||||
find_testable_code(&input_str, &mut collector, DUMMY_SP);
|
find_testable_code(&input_str, &mut collector, DUMMY_SP);
|
||||||
test_args.insert(0, "rustdoctest".to_string());
|
test_args.insert(0, "rustdoctest".to_string());
|
||||||
|
|
|
@ -43,7 +43,7 @@ use errors;
|
||||||
use errors::emitter::ColorConfig;
|
use errors::emitter::ColorConfig;
|
||||||
|
|
||||||
use clean::Attributes;
|
use clean::Attributes;
|
||||||
use html::markdown;
|
use html::markdown::{self, RenderType};
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct TestOptions {
|
pub struct TestOptions {
|
||||||
|
@ -57,7 +57,8 @@ pub fn run(input: &str,
|
||||||
externs: Externs,
|
externs: Externs,
|
||||||
mut test_args: Vec<String>,
|
mut test_args: Vec<String>,
|
||||||
crate_name: Option<String>,
|
crate_name: Option<String>,
|
||||||
maybe_sysroot: Option<PathBuf>)
|
maybe_sysroot: Option<PathBuf>,
|
||||||
|
render_type: RenderType)
|
||||||
-> isize {
|
-> isize {
|
||||||
let input_path = PathBuf::from(input);
|
let input_path = PathBuf::from(input);
|
||||||
let input = config::Input::File(input_path.clone());
|
let input = config::Input::File(input_path.clone());
|
||||||
|
@ -106,7 +107,8 @@ pub fn run(input: &str,
|
||||||
opts,
|
opts,
|
||||||
maybe_sysroot,
|
maybe_sysroot,
|
||||||
Some(codemap),
|
Some(codemap),
|
||||||
None);
|
None,
|
||||||
|
render_type);
|
||||||
|
|
||||||
{
|
{
|
||||||
let dep_graph = DepGraph::new(false);
|
let dep_graph = DepGraph::new(false);
|
||||||
|
@ -396,12 +398,15 @@ pub struct Collector {
|
||||||
position: Span,
|
position: Span,
|
||||||
codemap: Option<Rc<CodeMap>>,
|
codemap: Option<Rc<CodeMap>>,
|
||||||
filename: Option<String>,
|
filename: Option<String>,
|
||||||
|
// to be removed when hoedown will be removed as well
|
||||||
|
pub render_type: RenderType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Collector {
|
impl Collector {
|
||||||
pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
|
pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
|
||||||
use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
|
use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
|
||||||
codemap: Option<Rc<CodeMap>>, filename: Option<String>) -> Collector {
|
codemap: Option<Rc<CodeMap>>, filename: Option<String>,
|
||||||
|
render_type: RenderType) -> Collector {
|
||||||
Collector {
|
Collector {
|
||||||
tests: Vec::new(),
|
tests: Vec::new(),
|
||||||
old_tests: HashMap::new(),
|
old_tests: HashMap::new(),
|
||||||
|
@ -418,6 +423,7 @@ impl Collector {
|
||||||
position: DUMMY_SP,
|
position: DUMMY_SP,
|
||||||
codemap: codemap,
|
codemap: codemap,
|
||||||
filename: filename,
|
filename: filename,
|
||||||
|
render_type: render_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,6 +464,7 @@ impl Collector {
|
||||||
as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
|
as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
|
||||||
line: usize, filename: String) {
|
line: usize, filename: String) {
|
||||||
let name = self.generate_name(line, &filename);
|
let name = self.generate_name(line, &filename);
|
||||||
|
if self.render_type == RenderType::Pulldown {
|
||||||
let name_beg = self.generate_name_beginning(&filename);
|
let name_beg = self.generate_name_beginning(&filename);
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
// to be removed when hoedown is removed
|
// to be removed when hoedown is removed
|
||||||
|
@ -473,6 +480,7 @@ impl Collector {
|
||||||
name);
|
name);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let cfgs = self.cfgs.clone();
|
let cfgs = self.cfgs.clone();
|
||||||
let libs = self.libs.clone();
|
let libs = self.libs.clone();
|
||||||
let externs = self.externs.clone();
|
let externs = self.externs.clone();
|
||||||
|
@ -587,10 +595,15 @@ impl<'a, 'hir> HirCollector<'a, 'hir> {
|
||||||
attrs.unindent_doc_comments();
|
attrs.unindent_doc_comments();
|
||||||
if let Some(doc) = attrs.doc_value() {
|
if let Some(doc) = attrs.doc_value() {
|
||||||
self.collector.cnt = 0;
|
self.collector.cnt = 0;
|
||||||
|
if self.collector.render_type == RenderType::Pulldown {
|
||||||
markdown::old_find_testable_code(doc, self.collector,
|
markdown::old_find_testable_code(doc, self.collector,
|
||||||
attrs.span.unwrap_or(DUMMY_SP));
|
attrs.span.unwrap_or(DUMMY_SP));
|
||||||
markdown::find_testable_code(doc, self.collector,
|
markdown::find_testable_code(doc, self.collector,
|
||||||
attrs.span.unwrap_or(DUMMY_SP));
|
attrs.span.unwrap_or(DUMMY_SP));
|
||||||
|
} else {
|
||||||
|
markdown::old_find_testable_code(doc, self.collector,
|
||||||
|
attrs.span.unwrap_or(DUMMY_SP));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nested(self);
|
nested(self);
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
// Copyright 2017 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.
|
|
||||||
|
|
||||||
#![crate_name = "foo"]
|
|
||||||
|
|
||||||
// ignore-tidy-end-whitespace
|
|
||||||
|
|
||||||
// @has foo/fn.f.html
|
|
||||||
// @has - '<p>hard break:<br />'
|
|
||||||
// @has - 'after hard break</p>'
|
|
||||||
/// hard break:
|
|
||||||
/// after hard break
|
|
||||||
pub fn f() {}
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright 2017 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.
|
|
||||||
|
|
||||||
#![crate_name = "foo"]
|
|
||||||
|
|
||||||
// ignore-tidy-linelength
|
|
||||||
|
|
||||||
// @has foo/fn.f.html
|
|
||||||
// @has - '<p>markdown test</p>'
|
|
||||||
// @has - '<p>this is a <a href="https://example.com" title="this is a title">link</a>.</p>'
|
|
||||||
// @has - '<hr />'
|
|
||||||
// @has - '<p>a footnote<sup id="supref1"><a href="#ref1">1</a></sup>.</p>'
|
|
||||||
// @has - '<p>another footnote<sup id="supref2"><a href="#ref2">2</a></sup>.</p>'
|
|
||||||
// @has - '<p><img src="https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png" alt="Rust" /></p>'
|
|
||||||
// @has - '<div class="footnotes"><hr><ol><li id="ref1">'
|
|
||||||
// @has - '<p>Thing <a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2">'
|
|
||||||
// @has - '<p>Another Thing <a href="#supref2" rev="footnote">↩</a></p></li></ol></div>'
|
|
||||||
/// markdown test
|
|
||||||
///
|
|
||||||
/// this is a [link].
|
|
||||||
///
|
|
||||||
/// [link]: https://example.com "this is a title"
|
|
||||||
///
|
|
||||||
/// -----------
|
|
||||||
///
|
|
||||||
/// a footnote[^footnote].
|
|
||||||
///
|
|
||||||
/// another footnote[^footnotebis].
|
|
||||||
///
|
|
||||||
/// [^footnote]: Thing
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// [^footnotebis]: Another Thing
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// 
|
|
||||||
pub fn f() {}
|
|
Loading…
Add table
Add a link
Reference in a new issue