diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index afc434eb2df..49f6107869e 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -72,6 +72,9 @@
type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
libc::c_int, *mut libc::c_void);
+type codespanfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
+ *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;
@@ -89,11 +92,12 @@ struct hoedown_renderer {
blockhtml: Option,
header: Option,
-
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],
+ autolink: libc::size_t, // unused
+ codespan: Option,
+ other_span_level_callbacks_1: [libc::size_t; 7],
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.
@@ -185,6 +189,16 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
}
}
+/// Returns a new string with all consecutive whitespace collapsed into
+/// single spaces.
+///
+/// Any leading or trailing whitespace will be trimmed.
+fn collapse_whitespace(s: &str) -> String {
+ s.split(|c: char| c.is_whitespace()).filter(|s| {
+ !s.is_empty()
+ }).collect::>().connect(" ")
+}
+
thread_local!(static USED_HEADER_MAP: RefCell> = {
RefCell::new(HashMap::new())
});
@@ -299,6 +313,20 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
reset_headers();
+ extern fn codespan(ob: *mut hoedown_buffer, text: *const hoedown_buffer, _: *mut libc::c_void) {
+ let content = if text.is_null() {
+ "".to_string()
+ } else {
+ let bytes = unsafe { (*text).as_bytes() };
+ let s = str::from_utf8(bytes).unwrap();
+ collapse_whitespace(s)
+ };
+
+ let content = format!("{}
", Escape(&content));
+ let element = CString::new(content).unwrap();
+ unsafe { hoedown_buffer_puts(ob, element.as_ptr()); }
+ }
+
unsafe {
let ob = hoedown_buffer_new(DEF_OUNIT);
let renderer = hoedown_html_renderer_new(0, 0);
@@ -310,6 +338,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
= &mut opaque as *mut _ as *mut libc::c_void;
(*renderer).blockcode = Some(block);
(*renderer).header = Some(header);
+ (*renderer).codespan = Some(codespan);
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
hoedown_document_render(document, ob, s.as_ptr(),
@@ -523,7 +552,7 @@ pub fn plain_summary_line(md: &str) -> String {
#[cfg(test)]
mod tests {
use super::{LangString, Markdown};
- use super::plain_summary_line;
+ use super::{collapse_whitespace, plain_summary_line};
#[test]
fn test_lang_string_parse() {
@@ -571,4 +600,18 @@ fn t(input: &str, expect: &str) {
t("# top header", "top header");
t("## header", "header");
}
+
+ #[test]
+ fn test_collapse_whitespace() {
+ fn t(input: &str, expected: &str) {
+ let actual = collapse_whitespace(input);
+ assert_eq!(actual, expected);
+ }
+
+ t("foo", "foo");
+ t("foo bar baz", "foo bar baz");
+ t(" foo bar", "foo bar");
+ t("\tfoo bar\nbaz", "foo bar baz");
+ t("foo bar \n baz\t\tqux\n", "foo bar baz qux");
+ }
}