Skip to content

Commit f85d1dc

Browse files
committed
---
yaml --- r: 102438 b: refs/heads/master c: f22c96c h: refs/heads/master v: v3
1 parent 030ec52 commit f85d1dc

File tree

5 files changed

+313
-13
lines changed

5 files changed

+313
-13
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: 69b8ef806b3742ba7d41a77cd216713c84f36254
2+
refs/heads/master: f22c96cc888eac4c1c5d44ea4765e5c2a65f64f3
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 6e7f170fedd3c526a643c0b2d13863acd982be02
55
refs/heads/try: a97642026c18a624ff6ea01075dd9550f8ed07ff

trunk/src/librustdoc/html/markdown.rs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,16 @@ use std::str;
3636
use std::vec;
3737
use collections::HashMap;
3838

39+
use html::toc::TocBuilder;
3940
use html::highlight;
4041

4142
/// A unit struct which has the `fmt::Show` trait implemented. When
4243
/// formatted, this struct will emit the HTML corresponding to the rendered
4344
/// version of the contained markdown string.
4445
pub struct Markdown<'a>(&'a str);
46+
/// A unit struct like `Markdown`, that renders the markdown with a
47+
/// table of contents.
48+
pub struct MarkdownWithToc<'a>(&'a str);
4549

4650
static OUTPUT_UNIT: libc::size_t = 64;
4751
static MKDEXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 0;
@@ -75,6 +79,7 @@ struct html_renderopt {
7579
struct my_opaque {
7680
opt: html_renderopt,
7781
dfltblk: extern "C" fn(*buf, *buf, *buf, *libc::c_void),
82+
toc_builder: Option<TocBuilder>,
7883
}
7984

8085
struct buf {
@@ -121,7 +126,7 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
121126

122127
local_data_key!(used_header_map: HashMap<~str, uint>)
123128

124-
pub fn render(w: &mut io::Writer, s: &str) -> fmt::Result {
129+
pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
125130
extern fn block(ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
126131
unsafe {
127132
let my_opaque: &my_opaque = cast::transmute(opaque);
@@ -162,7 +167,7 @@ pub fn render(w: &mut io::Writer, s: &str) -> fmt::Result {
162167
}
163168

164169
extern fn header(ob: *buf, text: *buf, level: libc::c_int,
165-
_opaque: *libc::c_void) {
170+
opaque: *libc::c_void) {
166171
// sundown does this, we may as well too
167172
"\n".with_c_str(|p| unsafe { bufputs(ob, p) });
168173

@@ -183,6 +188,8 @@ pub fn render(w: &mut io::Writer, s: &str) -> fmt::Result {
183188
}
184189
}).to_owned_vec().connect("-");
185190

191+
let opaque = unsafe {&mut *(opaque as *mut my_opaque)};
192+
186193
// Make sure our hyphenated ID is unique for this page
187194
let id = local_data::get_mut(used_header_map, |map| {
188195
let map = map.unwrap();
@@ -194,9 +201,18 @@ pub fn render(w: &mut io::Writer, s: &str) -> fmt::Result {
194201
id.clone()
195202
});
196203

204+
let sec = match opaque.toc_builder {
205+
Some(ref mut builder) => {
206+
builder.push(level as u32, s.clone(), id.clone())
207+
}
208+
None => {""}
209+
};
210+
197211
// Render the HTML
198-
let text = format!(r#"<h{lvl} id="{id}">{}</h{lvl}>"#,
199-
s, lvl = level, id = id);
212+
let text = format!(r#"<h{lvl} id="{id}">{sec_len,plural,=0{}other{{sec} }}{}</h{lvl}>"#,
213+
s, lvl = level, id = id,
214+
sec_len = sec.len(), sec = sec);
215+
200216
text.with_c_str(|p| unsafe { bufputs(ob, p) });
201217
}
202218

@@ -218,23 +234,30 @@ pub fn render(w: &mut io::Writer, s: &str) -> fmt::Result {
218234
let mut callbacks: sd_callbacks = mem::init();
219235

220236
sdhtml_renderer(&callbacks, &options, 0);
221-
let opaque = my_opaque {
237+
let mut opaque = my_opaque {
222238
opt: options,
223239
dfltblk: callbacks.blockcode.unwrap(),
240+
toc_builder: if print_toc {Some(TocBuilder::new())} else {None}
224241
};
225242
callbacks.blockcode = Some(block);
226243
callbacks.header = Some(header);
227244
let markdown = sd_markdown_new(extensions, 16, &callbacks,
228-
&opaque as *my_opaque as *libc::c_void);
245+
&mut opaque as *mut my_opaque as *libc::c_void);
229246

230247

231248
sd_markdown_render(ob, s.as_ptr(), s.len() as libc::size_t, markdown);
232249
sd_markdown_free(markdown);
233250

234-
let ret = vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
235-
w.write(buf)
236-
});
251+
let mut ret = match opaque.toc_builder {
252+
Some(b) => write!(w, "<nav id=\"TOC\">{}</nav>", b.into_toc()),
253+
None => Ok(())
254+
};
237255

256+
if ret.is_ok() {
257+
ret = vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
258+
w.write(buf)
259+
});
260+
}
238261
bufrelease(ob);
239262
ret
240263
}
@@ -319,6 +342,13 @@ impl<'a> fmt::Show for Markdown<'a> {
319342
let Markdown(md) = *self;
320343
// This is actually common enough to special-case
321344
if md.len() == 0 { return Ok(()) }
322-
render(fmt.buf, md.as_slice())
345+
render(fmt.buf, md.as_slice(), false)
346+
}
347+
}
348+
349+
impl<'a> fmt::Show for MarkdownWithToc<'a> {
350+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
351+
let MarkdownWithToc(md) = *self;
352+
render(fmt.buf, md.as_slice(), true)
323353
}
324354
}

0 commit comments

Comments
 (0)