diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 6f19519ee7c..00182a80ab3 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -72,16 +72,40 @@ type blockcodefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, libc::c_int, *mut libc::c_void); +type linkfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_buffer, *const hoedown_buffer, + *mut libc::c_void) -> libc::c_int; + +type normaltextfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *mut libc::c_void); + #[repr(C)] struct hoedown_renderer { - opaque: *mut hoedown_html_renderer_state, + opaque: *mut libc::c_void, + blockcode: Option, blockquote: Option, blockhtml: Option, header: Option, - other: [libc::size_t; 28], + + other_block_level_callbacks: [libc::size_t; 9], + + /* span level callbacks - NULL or return 0 prints the span verbatim */ + other_span_level_callbacks_1: [libc::size_t; 9], + link: Option, + other_span_level_callbacks_2: [libc::size_t; 5], + // hoedown will add `math` callback here, but we use an old version of it. + + /* low level callbacks - NULL copies input directly into the output */ + entity: Option, + normal_text: Option, + + /* header and footer */ + doc_header: Option, + doc_footer: Option, } #[repr(C)] @@ -134,6 +158,8 @@ extern { fn hoedown_document_free(md: *mut hoedown_document); fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; + fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char, + n: libc::size_t); fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char); fn hoedown_buffer_free(b: *mut hoedown_buffer); @@ -279,7 +305,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { dfltblk: (*renderer).blockcode.unwrap(), toc_builder: if print_toc {Some(TocBuilder::new())} else {None} }; - (*(*renderer).opaque).opaque = &mut opaque as *mut _ as *mut libc::c_void; + (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque + = &mut opaque as *mut _ as *mut libc::c_void; (*renderer).blockcode = Some(block as blockcodefn); (*renderer).header = Some(header as headerfn); @@ -355,7 +382,8 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { let renderer = hoedown_html_renderer_new(0, 0); (*renderer).blockcode = Some(block as blockcodefn); (*renderer).header = Some(header as headerfn); - (*(*renderer).opaque).opaque = tests as *mut _ as *mut libc::c_void; + (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque + = tests as *mut _ as *mut libc::c_void; let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); hoedown_document_render(document, ob, doc.as_ptr(), @@ -442,9 +470,60 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> { } } +pub fn plain_summary_line(md: &str) -> String { + extern fn link(_ob: *mut hoedown_buffer, + _link: *const hoedown_buffer, + _title: *const hoedown_buffer, + content: *const hoedown_buffer, + opaque: *mut libc::c_void) -> libc::c_int + { + unsafe { + if !content.is_null() && (*content).size > 0 { + let ob = opaque as *mut hoedown_buffer; + hoedown_buffer_put(ob, (*content).data as *const libc::c_char, + (*content).size); + } + } + 1 + } + + extern fn normal_text(_ob: *mut hoedown_buffer, + text: *const hoedown_buffer, + opaque: *mut libc::c_void) + { + unsafe { + let ob = opaque as *mut hoedown_buffer; + hoedown_buffer_put(ob, (*text).data as *const libc::c_char, + (*text).size); + } + } + + unsafe { + let ob = hoedown_buffer_new(DEF_OUNIT); + let mut plain_renderer: hoedown_renderer = ::std::mem::zeroed(); + let renderer = &mut plain_renderer as *mut hoedown_renderer; + (*renderer).opaque = ob as *mut libc::c_void; + (*renderer).link = Some(link as linkfn); + (*renderer).normal_text = Some(normal_text as normaltextfn); + + let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); + hoedown_document_render(document, ob, md.as_ptr(), + md.len() as libc::size_t); + hoedown_document_free(document); + let plain_slice = slice::from_raw_buf(&(*ob).data, (*ob).size as uint); + let plain = match str::from_utf8(plain_slice) { + Ok(s) => s.to_string(), + Err(_) => "".to_string(), + }; + hoedown_buffer_free(ob); + plain + } +} + #[cfg(test)] mod tests { use super::{LangString, Markdown}; + use super::plain_summary_line; #[test] fn test_lang_string_parse() { @@ -478,4 +557,18 @@ mod tests { let markdown = "# title"; format!("{}", Markdown(markdown.as_slice())); } + + #[test] + fn test_plain_summary_line() { + fn t(input: &str, expect: &str) { + let output = plain_summary_line(input); + assert_eq!(output, expect); + } + + t("hello [Rust](http://rust-lang.org) :)", "hello Rust :)"); + t("code `let x = i32;` ...", "code `let x = i32;` ..."); + t("type `Type<'static>` ...", "type `Type<'static>` ..."); + t("# top header", "top header"); + t("## header", "header"); + } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index cd2ed5f0a97..9a25993d28a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -64,8 +64,13 @@ use html::item_type::ItemType; use html::layout; use html::markdown::Markdown; use html::markdown; +use html::escape::Escape; use stability_summary; +/// A pair of name and its optional document. +#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] +pub struct NameDoc(String, Option); + /// Major driving force in all rustdoc rendering. This contains information /// about where in the tree-like hierarchy rendering is occurring and controls /// how the current page is being rendered. @@ -95,7 +100,7 @@ pub struct Context { /// functions), and the value is the list of containers belonging to this /// header. This map will change depending on the surrounding context of the /// page. - pub sidebar: HashMap>, + pub sidebar: HashMap>, /// This flag indicates whether [src] links should be generated or not. If /// the source files are present in the html rendering, then this will be /// `true`. @@ -1245,7 +1250,7 @@ impl Context { } } - fn build_sidebar(&self, m: &clean::Module) -> HashMap> { + fn build_sidebar(&self, m: &clean::Module) -> HashMap> { let mut map = HashMap::new(); for item in m.items.iter() { if self.ignore_private_item(item) { continue } @@ -1262,7 +1267,7 @@ impl Context { let short = short.to_string(); let v = map.entry(short).get().unwrap_or_else( |vacant_entry| vacant_entry.insert(Vec::with_capacity(1))); - v.push(myname); + v.push(NameDoc(myname, Some(shorter_line(item.doc_value())))); } for (_, items) in map.iter_mut() { @@ -1476,6 +1481,11 @@ fn shorter<'a>(s: Option<&'a str>) -> &'a str { } } +#[inline] +fn shorter_line(s: Option<&str>) -> String { + shorter(s).replace("\n", " ") +} + fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { match item.doc_value() { Some(s) => { @@ -2201,21 +2211,22 @@ impl<'a> fmt::Display for Sidebar<'a> { None => return Ok(()) }; try!(write!(w, "

{}

", short, longty)); - for item in items.iter() { + for &NameDoc(ref name, ref doc) in items.iter() { let curty = shortty(cur).to_static_str(); - let class = if cur.name.as_ref().unwrap() == item && + let class = if cur.name.as_ref().unwrap() == name && short == curty { "current" } else { "" }; - try!(write!(w, "\ - {name}", + try!(write!(w, "{name}", ty = short, class = class, href = if curty == "mod" {"../"} else {""}, path = if short == "mod" { - format!("{}/index.html", item.as_slice()) + format!("{}/index.html", name.as_slice()) } else { - format!("{}.{}.html", short, item.as_slice()) + format!("{}.{}.html", short, name.as_slice()) }, - name = item.as_slice())); + title = Escape(doc.as_ref().unwrap().as_slice()), + name = name.as_slice())); } try!(write!(w, "
")); Ok(()) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 1b0c3b00640..aac3985f0cc 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -668,6 +668,15 @@ search(); } + function plainSummaryLine(markdown) { + var str = markdown.replace(/\n/g, ' ') + str = str.replace(/'/g, "\'") + str = str.replace(/^#+? (.+?)/, "$1") + str = str.replace(/\[(.*?)\]\(.*?\)/g, "$1") + str = str.replace(/\[(.*?)\]\[.*?\]/g, "$1") + return str; + } + index = buildIndex(rawSearchIndex); startSearch(); @@ -688,8 +697,10 @@ if (crates[i] == window.currentCrate) { klass += ' current'; } + var desc = rawSearchIndex[crates[i]].items[0][3]; div.append($('', {'href': '../' + crates[i] + '/index.html', - 'class': klass}).text(crates[i])); + 'title': plainSummaryLine(desc), + 'class': klass}).text(crates[i])); } sidebar.append(div); }