Auto merge of #20221 - liigo:rustdoc-sidebar-tooltips-v3, r=alexcrichton
This pull request add tooltips to most links of sidebar. The tooltips display "summary line" of items' document. Some lengthy/annoying raw markdown code are eliminated, such as links and headers. - `[Rust](http://rust-lang.org)` displays as `Rust` (no URLs) - `# header` displays as `header` (no `#`s) Some inline spans, e.g. ``` `code` ``` and ```*emphasis*```, are kept as they are, for better readable. I've make sure `&` `'` `"` `<` and `>` are properly displayed in tooltips, for example, `&'a Option<T>`. Online preview: http://liigo.com/tmp/tooltips/std/index.html @alexcrichton @steveklabnik since you have reviewed my previous ([v1](https://github.com/rust-lang/rust/pull/13014),[v2](https://github.com/rust-lang/rust/pull/16448)) PRs of this serise, which have been closed for technical reasons. Thank you.
This commit is contained in:
commit
d8d5e4d217
@ -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<blockcodefn>,
|
||||
blockquote: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
|
||||
*mut libc::c_void)>,
|
||||
blockhtml: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
|
||||
*mut libc::c_void)>,
|
||||
header: Option<headerfn>,
|
||||
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<linkfn>,
|
||||
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<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
|
||||
*mut libc::c_void)>,
|
||||
normal_text: Option<normaltextfn>,
|
||||
|
||||
/* header and footer */
|
||||
doc_header: Option<extern "C" fn(*mut hoedown_buffer, *mut libc::c_void)>,
|
||||
doc_footer: Option<extern "C" fn(*mut hoedown_buffer, *mut libc::c_void)>,
|
||||
}
|
||||
|
||||
#[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");
|
||||
}
|
||||
}
|
||||
|
@ -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<String>);
|
||||
|
||||
/// 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<String, Vec<String>>,
|
||||
pub sidebar: HashMap<String, Vec<NameDoc>>,
|
||||
/// 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<String, Vec<String>> {
|
||||
fn build_sidebar(&self, m: &clean::Module) -> HashMap<String, Vec<NameDoc>> {
|
||||
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, "<div class='block {}'><h2>{}</h2>", 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, "<a class='{ty} {class}' href='{href}{path}'>\
|
||||
{name}</a>",
|
||||
try!(write!(w, "<a class='{ty} {class}' href='{href}{path}' \
|
||||
title='{title}'>{name}</a>",
|
||||
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, "</div>"));
|
||||
Ok(())
|
||||
|
@ -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($('<a>', {'href': '../' + crates[i] + '/index.html',
|
||||
'class': klass}).text(crates[i]));
|
||||
'title': plainSummaryLine(desc),
|
||||
'class': klass}).text(crates[i]));
|
||||
}
|
||||
sidebar.append(div);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user