From 58a257bcdf096c53c0ca75ee1ca1024b51481865 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Tue, 23 Dec 2014 09:58:38 +0800 Subject: [PATCH 1/5] rustdoc: add tooltips to sidebar --- src/librustdoc/html/render.rs | 30 ++++++++++++++++++++---------- src/librustdoc/html/static/main.js | 4 +++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ab9700d966a..d1b5618e51e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -66,6 +66,10 @@ use html::markdown::Markdown; use html::markdown; use stability_summary; +/// A pair of name and its optional document. +#[deriving(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 +99,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 +1249,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 +1266,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 +1480,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) => { @@ -2213,21 +2222,22 @@ impl<'a> fmt::String 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 = 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 f27f0cd70f4..be5025936a2 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -689,8 +689,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': desc.replace(/\n/g, ' '), + 'class': klass}).text(crates[i])); } sidebar.append(div); } From 0c06442bcd340a55c24ce30bfe2c43054f232d93 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Tue, 23 Dec 2014 20:22:50 +0800 Subject: [PATCH 2/5] display plain summary line in javascript --- src/librustdoc/html/static/main.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index be5025936a2..7e1e2ae7765 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -669,6 +669,18 @@ search(); } + function plainSummaryLine(markdown) { + var str = markdown.replace(/\n/g, ' ') + str = str.replace(//g, ">") + str = str.replace(/"/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(); @@ -691,7 +703,7 @@ } var desc = rawSearchIndex[crates[i]].items[0][3]; div.append($('', {'href': '../' + crates[i] + '/index.html', - 'title': desc.replace(/\n/g, ' '), + 'title': plainSummaryLine(desc), 'class': klass}).text(crates[i])); } sidebar.append(div); From 52997408ec4265939c8017ef8de24babe4b73b7f Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Thu, 25 Dec 2014 13:39:29 +0800 Subject: [PATCH 3/5] rustdoc: eliminates raw markdown code (links, headers, etc.) from tooltips of sidebar --- src/librustdoc/html/markdown.rs | 96 +++++++++++++++++++++++++++++++-- src/librustdoc/html/render.rs | 17 +++++- 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 0dbd13b4616..7ebb3d4b86a 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -74,14 +74,34 @@ type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, #[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 libc::c_int>, + 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 +154,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 +301,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 +378,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 +466,59 @@ impl<'a> fmt::String for MarkdownWithToc<'a> { } } +pub fn plain_summary_line(md: &str) -> String { + extern "C" 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 { + // FIXME(liigo): I don't know why the parameter `_ob` is + // not the value passed in by `hoedown_document_render`. + // I have to manually pass in `ob` through `opaque` currently. + let ob = opaque as *mut hoedown_buffer; + hoedown_buffer_put(ob, (*content).data as *const libc::c_char, + (*content).size); + } + } + 1 + } + + extern "C" 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); + (*renderer).normal_text = Some(normal_text); + + 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 = String::from_raw_buf_len((*ob).data, (*ob).size as uint); + 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 +552,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 d1b5618e51e..3ec29dab555 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2197,6 +2197,21 @@ fn item_typedef(w: &mut fmt::Formatter, it: &clean::Item, document(w, it) } +fn escape_title(title: &str) -> String { + let title = markdown::plain_summary_line(title); + let mut result = String::with_capacity(title.len()); + for c in title.chars() { + match c { + '<' => result.push_str("<"), + '>' => result.push_str(">"), + '"' => result.push_str("""), + '\'' => result.push_str("'"), + _ => result.push(c), + } + } + result +} + impl<'a> fmt::String for Sidebar<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let cx = self.cx; @@ -2236,7 +2251,7 @@ impl<'a> fmt::String for Sidebar<'a> { } else { format!("{}.{}.html", short, name.as_slice()) }, - title = doc.as_ref().unwrap().as_slice(), + title = escape_title(doc.as_ref().unwrap().as_slice()), name = name.as_slice())); } try!(write!(w, "")); From 17ebb6053edd7b7d6e8ab5f59dd093f53db7ae44 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Thu, 25 Dec 2014 15:01:24 +0800 Subject: [PATCH 4/5] fix fallout --- src/librustdoc/html/markdown.rs | 30 +++++++++++++++++++----------- src/librustdoc/html/render.rs | 2 +- src/librustdoc/html/static/main.js | 5 +---- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 7ebb3d4b86a..45b77ea2ddd 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -72,6 +72,13 @@ 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 libc::c_void, @@ -83,21 +90,18 @@ struct hoedown_renderer { *mut libc::c_void)>, header: Option, - other_block_level_callbacks: [libc::size_t, ..9], + 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 libc::c_int>, - other_span_level_callbacks_2: [libc::size_t, ..5], + 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, + normal_text: Option, /* header and footer */ doc_header: Option, @@ -502,14 +506,18 @@ pub fn plain_summary_line(md: &str) -> String { 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); - (*renderer).normal_text = Some(normal_text); + (*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 = String::from_raw_buf_len((*ob).data, (*ob).size as uint); + 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 } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 3ec29dab555..86c945125f6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -67,7 +67,7 @@ use html::markdown; use stability_summary; /// A pair of name and its optional document. -#[deriving(Clone, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] pub struct NameDoc(String, Option); /// Major driving force in all rustdoc rendering. This contains information diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 7e1e2ae7765..efb442dbe34 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -671,10 +671,7 @@ function plainSummaryLine(markdown) { var str = markdown.replace(/\n/g, ' ') - str = str.replace(//g, ">") - str = str.replace(/"/g, """) - str = str.replace(/'/g, "'") + str = str.replace(/'/g, "\'") str = str.replace(/^#+? (.+?)/, "$1") str = str.replace(/\[(.*?)\]\(.*?\)/g, "$1") str = str.replace(/\[(.*?)\]\[.*?\]/g, "$1") From 2b11a80a60dbae980418b229ab89d2a28dbbc15f Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Fri, 16 Jan 2015 20:56:26 +0800 Subject: [PATCH 5/5] address review comments: reuse Escape etc. --- src/librustdoc/html/markdown.rs | 7 ++----- src/librustdoc/html/render.rs | 18 ++---------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 45b77ea2ddd..31c01e7777a 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -471,7 +471,7 @@ impl<'a> fmt::String for MarkdownWithToc<'a> { } pub fn plain_summary_line(md: &str) -> String { - extern "C" fn link(_ob: *mut hoedown_buffer, + extern fn link(_ob: *mut hoedown_buffer, _link: *const hoedown_buffer, _title: *const hoedown_buffer, content: *const hoedown_buffer, @@ -479,9 +479,6 @@ pub fn plain_summary_line(md: &str) -> String { { unsafe { if !content.is_null() && (*content).size > 0 { - // FIXME(liigo): I don't know why the parameter `_ob` is - // not the value passed in by `hoedown_document_render`. - // I have to manually pass in `ob` through `opaque` currently. let ob = opaque as *mut hoedown_buffer; hoedown_buffer_put(ob, (*content).data as *const libc::c_char, (*content).size); @@ -490,7 +487,7 @@ pub fn plain_summary_line(md: &str) -> String { 1 } - extern "C" fn normal_text(_ob: *mut hoedown_buffer, + extern fn normal_text(_ob: *mut hoedown_buffer, text: *const hoedown_buffer, opaque: *mut libc::c_void) { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 86c945125f6..480c61534e6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -64,6 +64,7 @@ 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. @@ -2197,21 +2198,6 @@ fn item_typedef(w: &mut fmt::Formatter, it: &clean::Item, document(w, it) } -fn escape_title(title: &str) -> String { - let title = markdown::plain_summary_line(title); - let mut result = String::with_capacity(title.len()); - for c in title.chars() { - match c { - '<' => result.push_str("<"), - '>' => result.push_str(">"), - '"' => result.push_str("""), - '\'' => result.push_str("'"), - _ => result.push(c), - } - } - result -} - impl<'a> fmt::String for Sidebar<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let cx = self.cx; @@ -2251,7 +2237,7 @@ impl<'a> fmt::String for Sidebar<'a> { } else { format!("{}.{}.html", short, name.as_slice()) }, - title = escape_title(doc.as_ref().unwrap().as_slice()), + title = Escape(doc.as_ref().unwrap().as_slice()), name = name.as_slice())); } try!(write!(w, ""));