diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 896d070c155ee..46b89b3851526 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -12,6 +12,7 @@ use std::fmt; use std::io; use externalfiles::ExternalHtml; +use html::markdown; #[deriving(Clone)] pub struct Layout { @@ -20,6 +21,7 @@ pub struct Layout { pub external_html: ExternalHtml, pub krate: String, pub playground_url: String, + pub use_mathjax: bool, } pub struct Page<'a> { @@ -34,6 +36,10 @@ pub fn render( dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T) -> io::IoResult<()> { + // Reset state on whether we've seen math, so as to avoid loading mathjax + // on pages that don't actually *have* math. + markdown::math_seen.replace(Some(false)); + write!(dst, r##" @@ -124,6 +130,7 @@ r##" {play_js} + {mathjax_js} "##, content = *t, @@ -156,6 +163,13 @@ r##" } else { format!(r#""#, page.root_path) }, + // this must be last so that `math_seen` captures all possible $$'s on this page. + mathjax_js = if layout.use_mathjax && markdown::math_seen.get().map_or(false, |x| *x) { + r#""#.to_string() + } else { + "".to_string() + }, ) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 305c18480f669..4d4b8ffd63e82 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -56,6 +56,7 @@ static HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3; static HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4; static HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8; static HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2; +static HOEDOWN_EXT_MATH: libc::c_uint = 1 << 13; static HOEDOWN_EXTENSIONS: libc::c_uint = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | @@ -64,6 +65,9 @@ static HOEDOWN_EXTENSIONS: libc::c_uint = HOEDOWN_EXT_FOOTNOTES; type hoedown_document = libc::c_void; // this is opaque to us +type hoedown_realloc_callback = extern "C" fn(*mut libc::c_void, libc::size_t) + -> *mut libc::size_t; +type hoedown_free_callback = extern "C" fn(*mut libc::c_void); #[repr(C)] struct hoedown_renderer { @@ -76,6 +80,8 @@ struct hoedown_renderer { *mut libc::c_void)>, header: Option, + math: Option libc::c_int>, other: [libc::size_t, ..28], } @@ -101,6 +107,8 @@ struct MyOpaque { dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, *const hoedown_buffer, *mut libc::c_void), toc_builder: Option, + math_enabled: bool, + math_seen: bool, } #[repr(C)] @@ -109,6 +117,9 @@ struct hoedown_buffer { size: libc::size_t, asize: libc::size_t, unit: libc::size_t, + data_realloc: Option, + data_free: Option, + buffer_free: Option, } // hoedown FFI @@ -130,8 +141,13 @@ extern { 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_put(b: *mut hoedown_buffer, data: *const libc::c_void, len: libc::size_t); + fn hoedown_buffer_free(b: *mut hoedown_buffer); + fn hoedown_escape_html(ob: *mut hoedown_buffer, + src: *const libc::uint8_t, + size: libc::size_t, + secure: libc::c_int); } /// Returns Some(code) if `s` is a line that should be stripped from @@ -147,10 +163,23 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { } } +fn hoedown_extensions() -> libc::c_uint { + let mut extensions = HOEDOWN_EXTENSIONS; + + match use_mathjax.get().as_ref() { + Some(use_math) if **use_math => { extensions |= HOEDOWN_EXT_MATH; } + _ => {} + } + + extensions +} + local_data_key!(used_header_map: RefCell>) local_data_key!(test_idx: Cell) // None == render an example, but there's no crate name local_data_key!(pub playground_krate: Option) +local_data_key!(pub use_mathjax: bool) +local_data_key!(pub math_seen: bool) pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { extern fn block(ob: *mut hoedown_buffer, text: *const hoedown_buffer, @@ -173,6 +202,9 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { size: text.len() as libc::size_t, asize: text.len() as libc::size_t, unit: 0, + data_free: None, + data_realloc: None, + buffer_free: None, }; let rendered = if lang.is_null() { false @@ -274,18 +306,50 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); } + extern fn math(ob: *mut hoedown_buffer, text: *const hoedown_buffer, + display_mode: libc::c_int, opaque: *mut libc::c_void) -> libc::c_int { + + let opaque = opaque as *mut hoedown_html_renderer_state; + let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; + + opaque.math_seen = true; + + let (open, close) = if !opaque.math_enabled { + ("$$", "$$") + } else if display_mode == 1 { + ("\\[", "\\]") + } else { + ("\\(", "\\)") + }; + + open.with_c_str(|open| { + close.with_c_str(|close| { + unsafe { + hoedown_buffer_put(ob, open as *const libc::c_void, 2); + hoedown_escape_html(ob, (*text).data, (*text).size, 0); + hoedown_buffer_put(ob, close as *const libc::c_void, 2); + } + }) + }); + + 1 + } + unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); let renderer = hoedown_html_renderer_new(0, 0); let mut opaque = MyOpaque { dfltblk: (*renderer).blockcode.unwrap(), - toc_builder: if print_toc {Some(TocBuilder::new())} else {None} + toc_builder: if print_toc {Some(TocBuilder::new())} else {None}, + math_enabled: use_mathjax.get().map_or(false, |x| *x), + math_seen: false, }; (*(*renderer).opaque).opaque = &mut opaque as *mut _ as *mut libc::c_void; (*renderer).blockcode = Some(block); (*renderer).header = Some(header); + (*renderer).math = Some(math); - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); + 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); @@ -303,6 +367,10 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { }); } hoedown_buffer_free(ob); + + let old = math_seen.get().map_or(false, |x| *x); + math_seen.replace(Some(old || opaque.math_seen)); + ret } } @@ -363,7 +431,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { (*renderer).header = Some(header); (*(*renderer).opaque).opaque = tests as *mut _ as *mut libc::c_void; - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); + 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); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index fc8fd0d086bc0..043d313a54384 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -245,11 +245,14 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) -> external_html: external_html.clone(), krate: krate.name.clone(), playground_url: "".to_string(), + use_mathjax: false, }, include_sources: true, render_redirect_pages: false, }; + markdown::use_mathjax.replace(None); + try!(mkdir(&cx.dst)); // Crawl the crate, building a summary of the stability levels. NOTE: this @@ -284,6 +287,11 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) -> if "html_no_source" == x.as_slice() => { cx.include_sources = false; } + clean::Word(ref x) + if "enable_mathjax" == x.as_slice() => { + cx.layout.use_mathjax = true; + markdown::use_mathjax.replace(Some(true)); + } _ => {} } } diff --git a/src/rt/hoedown b/src/rt/hoedown index 238c4d57cce10..794d91b370202 160000 --- a/src/rt/hoedown +++ b/src/rt/hoedown @@ -1 +1 @@ -Subproject commit 238c4d57cce10d33b05cf52a91fc62a09f31ffbb +Subproject commit 794d91b37020242446c53713c7ce0c09b33b5f0c