Skip to content

Commit 4a1b2e8

Browse files
Gankrahuonw
authored andcommitted
rustdoc: enable support for mathematics.
1 parent 035a321 commit 4a1b2e8

File tree

3 files changed

+96
-9
lines changed

3 files changed

+96
-9
lines changed

src/librustdoc/html/layout.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::fmt;
1212
use std::io;
1313

1414
use externalfiles::ExternalHtml;
15+
use html::markdown;
1516

1617
#[deriving(Clone)]
1718
pub struct Layout {
@@ -20,6 +21,7 @@ pub struct Layout {
2021
pub external_html: ExternalHtml,
2122
pub krate: String,
2223
pub playground_url: String,
24+
pub use_mathjax: bool,
2325
}
2426

2527
pub struct Page<'a> {
@@ -34,7 +36,11 @@ pub fn render<T: fmt::Show, S: fmt::Show>(
3436
dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T)
3537
-> io::IoResult<()>
3638
{
37-
write!(dst,
39+
// Reset state on whether we've seen math, so as to avoid loading mathjax
40+
// on pages that don't actually *have* math.
41+
markdown::math_seen.replace(Some(false));
42+
43+
try!(write!(dst,
3844
r##"<!DOCTYPE html>
3945
<html lang="en">
4046
<head>
@@ -124,8 +130,7 @@ r##"<!DOCTYPE html>
124130
<script src="{root_path}main.js"></script>
125131
{play_js}
126132
<script async src="{root_path}search-index.js"></script>
127-
</body>
128-
</html>"##,
133+
"##,
129134
content = *t,
130135
root_path = page.root_path,
131136
ty = page.ty,
@@ -156,7 +161,16 @@ r##"<!DOCTYPE html>
156161
} else {
157162
format!(r#"<script src="{}playpen.js"></script>"#, page.root_path)
158163
},
159-
)
164+
));
165+
166+
// this must be done after everything is rendered, so that
167+
// `math_seen` captures all possible $$'s on this page.
168+
if layout.use_mathjax && markdown::math_seen.get().map_or(false, |x| *x) {
169+
try!(dst.write_str("\
170+
<script async src=\"https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML\"></script>"));
171+
}
172+
173+
dst.write_str("</body>\n</html>")
160174
}
161175

162176
pub fn redirect(dst: &mut io::Writer, url: &str) -> io::IoResult<()> {

src/librustdoc/html/markdown.rs

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ static HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3;
5656
static HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
5757
static HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8;
5858
static HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2;
59+
static HOEDOWN_EXT_MATH: libc::c_uint = 1 << 13;
5960

6061
static HOEDOWN_EXTENSIONS: libc::c_uint =
6162
HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES |
@@ -64,6 +65,9 @@ static HOEDOWN_EXTENSIONS: libc::c_uint =
6465
HOEDOWN_EXT_FOOTNOTES;
6566

6667
type hoedown_document = libc::c_void; // this is opaque to us
68+
type hoedown_realloc_callback = extern "C" fn(*mut libc::c_void, libc::size_t)
69+
-> *mut libc::size_t;
70+
type hoedown_free_callback = extern "C" fn(*mut libc::c_void);
6771

6872
#[repr(C)]
6973
struct hoedown_renderer {
@@ -76,7 +80,10 @@ struct hoedown_renderer {
7680
*mut libc::c_void)>,
7781
header: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
7882
libc::c_int, *mut libc::c_void)>,
79-
other: [libc::size_t, ..28],
83+
other1: [libc::size_t, ..24],
84+
math: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
85+
libc::c_int, *mut libc::c_void) -> libc::c_int>,
86+
other2: [libc::size_t, ..4],
8087
}
8188

8289
#[repr(C)]
@@ -101,6 +108,8 @@ struct MyOpaque {
101108
dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
102109
*const hoedown_buffer, *mut libc::c_void),
103110
toc_builder: Option<TocBuilder>,
111+
math_enabled: bool,
112+
math_seen: bool,
104113
}
105114

106115
#[repr(C)]
@@ -109,6 +118,9 @@ struct hoedown_buffer {
109118
size: libc::size_t,
110119
asize: libc::size_t,
111120
unit: libc::size_t,
121+
data_realloc: Option<hoedown_realloc_callback>,
122+
data_free: Option<hoedown_free_callback>,
123+
buffer_free: Option<hoedown_free_callback>,
112124
}
113125

114126
// hoedown FFI
@@ -130,8 +142,13 @@ extern {
130142

131143
fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer;
132144
fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char);
133-
fn hoedown_buffer_free(b: *mut hoedown_buffer);
145+
fn hoedown_buffer_put(b: *mut hoedown_buffer, data: *const libc::c_void, len: libc::size_t);
134146

147+
fn hoedown_buffer_free(b: *mut hoedown_buffer);
148+
fn hoedown_escape_html(ob: *mut hoedown_buffer,
149+
src: *const libc::uint8_t,
150+
size: libc::size_t,
151+
secure: libc::c_int);
135152
}
136153

137154
/// Returns Some(code) if `s` is a line that should be stripped from
@@ -147,10 +164,23 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
147164
}
148165
}
149166

167+
fn hoedown_extensions() -> libc::c_uint {
168+
let mut extensions = HOEDOWN_EXTENSIONS;
169+
170+
match use_mathjax.get().as_ref() {
171+
Some(use_math) if **use_math => { extensions |= HOEDOWN_EXT_MATH; }
172+
_ => {}
173+
}
174+
175+
extensions
176+
}
177+
150178
local_data_key!(used_header_map: RefCell<HashMap<String, uint>>)
151179
local_data_key!(test_idx: Cell<uint>)
152180
// None == render an example, but there's no crate name
153181
local_data_key!(pub playground_krate: Option<String>)
182+
local_data_key!(pub use_mathjax: bool)
183+
local_data_key!(pub math_seen: bool)
154184

155185
pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
156186
extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer,
@@ -268,18 +298,49 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
268298
text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) });
269299
}
270300

301+
extern fn math(ob: *mut hoedown_buffer, text: *const hoedown_buffer,
302+
display_mode: libc::c_int, opaque: *mut libc::c_void) -> libc::c_int {
303+
let opaque = opaque as *mut hoedown_html_renderer_state;
304+
let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) };
305+
306+
opaque.math_seen = true;
307+
308+
let (open, close) = if !opaque.math_enabled {
309+
("$$", "$$")
310+
} else if display_mode == 1 {
311+
("\\[", "\\]")
312+
} else {
313+
("\\(", "\\)")
314+
};
315+
316+
open.with_c_str(|open| {
317+
close.with_c_str(|close| {
318+
unsafe {
319+
hoedown_buffer_put(ob, open as *const libc::c_void, 2);
320+
hoedown_escape_html(ob, (*text).data, (*text).size, 0);
321+
hoedown_buffer_put(ob, close as *const libc::c_void, 2);
322+
}
323+
})
324+
});
325+
326+
1
327+
}
328+
271329
unsafe {
272330
let ob = hoedown_buffer_new(DEF_OUNIT);
273331
let renderer = hoedown_html_renderer_new(0, 0);
274332
let mut opaque = MyOpaque {
275333
dfltblk: (*renderer).blockcode.unwrap(),
276-
toc_builder: if print_toc {Some(TocBuilder::new())} else {None}
334+
toc_builder: if print_toc {Some(TocBuilder::new())} else {None},
335+
math_enabled: use_mathjax.get().map_or(false, |x| *x),
336+
math_seen: false,
277337
};
278338
(*(*renderer).opaque).opaque = &mut opaque as *mut _ as *mut libc::c_void;
279339
(*renderer).blockcode = Some(block);
280340
(*renderer).header = Some(header);
341+
(*renderer).math = Some(math);
281342

282-
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
343+
let document = hoedown_document_new(renderer, hoedown_extensions(), 16);
283344
hoedown_document_render(document, ob, s.as_ptr(),
284345
s.len() as libc::size_t);
285346
hoedown_document_free(document);
@@ -297,6 +358,10 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
297358
});
298359
}
299360
hoedown_buffer_free(ob);
361+
362+
let old = math_seen.get().map_or(false, |x| *x);
363+
math_seen.replace(Some(old || opaque.math_seen));
364+
300365
ret
301366
}
302367
}
@@ -357,7 +422,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
357422
(*renderer).header = Some(header);
358423
(*(*renderer).opaque).opaque = tests as *mut _ as *mut libc::c_void;
359424

360-
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
425+
let document = hoedown_document_new(renderer, hoedown_extensions(), 16);
361426
hoedown_document_render(document, ob, doc.as_ptr(),
362427
doc.len() as libc::size_t);
363428
hoedown_document_free(document);

src/librustdoc/html/render.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,14 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) ->
247247
external_html: external_html.clone(),
248248
krate: krate.name.clone(),
249249
playground_url: "".to_string(),
250+
use_mathjax: false,
250251
},
251252
include_sources: true,
252253
render_redirect_pages: false,
253254
};
254255

256+
markdown::use_mathjax.replace(None);
257+
255258
try!(mkdir(&cx.dst));
256259

257260
// Crawl the crate, building a summary of the stability levels. NOTE: this
@@ -286,6 +289,11 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) ->
286289
if "html_no_source" == x.as_slice() => {
287290
cx.include_sources = false;
288291
}
292+
clean::Word(ref x)
293+
if "enable_mathjax" == x.as_slice() => {
294+
cx.layout.use_mathjax = true;
295+
markdown::use_mathjax.replace(Some(true));
296+
}
289297
_ => {}
290298
}
291299
}

0 commit comments

Comments
 (0)