Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Mathjax Support to Rustdoc #16991

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/librustdoc/html/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::fmt;
use std::io;

use externalfiles::ExternalHtml;
use html::markdown;

#[deriving(Clone)]
pub struct Layout {
Expand All @@ -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> {
Expand All @@ -34,6 +36,10 @@ pub fn render<T: fmt::Show, S: fmt::Show>(
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##"<!DOCTYPE html>
<html lang="en">
Expand Down Expand Up @@ -124,6 +130,7 @@ r##"<!DOCTYPE html>
<script src="{root_path}main.js"></script>
{play_js}
<script async src="{root_path}search-index.js"></script>
{mathjax_js}
</body>
</html>"##,
content = *t,
Expand Down Expand Up @@ -156,6 +163,13 @@ r##"<!DOCTYPE html>
} else {
format!(r#"<script src="{}playpen.js"></script>"#, 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#"<script async src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML">
</script>"#.to_string()
} else {
"".to_string()
},
)
}

Expand Down
76 changes: 72 additions & 4 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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 {
Expand All @@ -76,6 +80,8 @@ struct hoedown_renderer {
*mut libc::c_void)>,
header: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
libc::c_int, *mut libc::c_void)>,
math: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
libc::c_int, *mut libc::c_void) -> libc::c_int>,
other: [libc::size_t, ..28],
}

Expand All @@ -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<TocBuilder>,
math_enabled: bool,
math_seen: bool,
}

#[repr(C)]
Expand All @@ -109,6 +117,9 @@ struct hoedown_buffer {
size: libc::size_t,
asize: libc::size_t,
unit: libc::size_t,
data_realloc: Option<hoedown_realloc_callback>,
data_free: Option<hoedown_free_callback>,
buffer_free: Option<hoedown_free_callback>,
}

// hoedown FFI
Expand All @@ -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
Expand All @@ -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<HashMap<String, uint>>)
local_data_key!(test_idx: Cell<uint>)
// None == render an example, but there's no crate name
local_data_key!(pub playground_krate: Option<String>)
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,
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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
}
}
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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));
}
_ => {}
}
}
Expand Down