Skip to content

Commit

Permalink
Added mod-relative link support
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnHeitmann committed Jun 27, 2016
1 parent eff0fdc commit 3c44331
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 41 deletions.
6 changes: 3 additions & 3 deletions src/libcollections/btree/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ use Bound;
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
///
/// [`BTreeMap`]: struct.BTreeMap.html
/// [`Ord`]: /std/cmp/trait.Ord.html
/// [`Cell`]: /std/cell/struct.Cell.html
/// [`RefCell`]: /std/cell/struct.RefCell.html
/// [`Ord`]: ::/std/cmp/trait.Ord.html
/// [`Cell`]: ::/std/cell/struct.Cell.html
/// [`RefCell`]: ::/std/cell/struct.RefCell.html
///
/// # Examples
///
Expand Down
32 changes: 16 additions & 16 deletions src/libcollections/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

//! Unicode string slices.
//!
//! *[See also the `str` primitive type](../../std/primitive.str.html).*
//! *[See also the `str` primitive type](::/std/primitive.str.html).*


#![stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -715,7 +715,7 @@ impl str {
/// a character matches.
///
/// [`char`]: primitive.char.html
/// [`None`]: /std/option/enum.Option.html#variant.None
/// [`None`]: ::/std/option/enum.Option.html#variant.None
///
/// # Examples
///
Expand Down Expand Up @@ -760,7 +760,7 @@ impl str {
/// a character matches.
///
/// [`char`]: primitive.char.html
/// [`None`]: /std/option/enum.Option.html#variant.None
/// [`None`]: ::/std/option/enum.Option.html#variant.None
///
/// # Examples
///
Expand Down Expand Up @@ -809,7 +809,7 @@ impl str {
/// allows a reverse search and forward/reverse search yields the same
/// elements. This is true for, eg, [`char`] but not for `&str`.
///
/// [`DoubleEndedIterator`]: /std/iter/trait.DoubleEndedIterator.html
/// [`DoubleEndedIterator`]: ::/std/iter/trait.DoubleEndedIterator.html
///
/// If the pattern allows a reverse search but its results might differ
/// from a forward search, the [`rsplit()`] method can be used.
Expand Down Expand Up @@ -922,7 +922,7 @@ impl str {
/// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
/// search yields the same elements.
///
/// [`DoubleEndedIterator`]: /std/iter/trait.DoubleEndedIterator.html
/// [`DoubleEndedIterator`]: ::/std/iter/trait.DoubleEndedIterator.html
///
/// For iterating from the front, the [`split()`] method can be used.
///
Expand Down Expand Up @@ -979,7 +979,7 @@ impl str {
/// allows a reverse search and forward/reverse search yields the same
/// elements. This is true for, eg, [`char`] but not for `&str`.
///
/// [`DoubleEndedIterator`]: /std/iter/trait.DoubleEndedIterator.html
/// [`DoubleEndedIterator`]: ::/std/iter/trait.DoubleEndedIterator.html
/// [`char`]: primitive.char.html
///
/// If the pattern allows a reverse search but its results might differ
Expand Down Expand Up @@ -1161,7 +1161,7 @@ impl str {
/// allows a reverse search and forward/reverse search yields the same
/// elements. This is true for, eg, [`char`] but not for `&str`.
///
/// [`DoubleEndedIterator`]: /std/iter/trait.DoubleEndedIterator.html
/// [`DoubleEndedIterator`]: ::/std/iter/trait.DoubleEndedIterator.html
/// [`char`]: primitive.char.html
///
/// If the pattern allows a reverse search but its results might differ
Expand Down Expand Up @@ -1199,7 +1199,7 @@ impl str {
/// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
/// search yields the same elements.
///
/// [`DoubleEndedIterator`]: /std/iter/trait.DoubleEndedIterator.html
/// [`DoubleEndedIterator`]: ::/std/iter/trait.DoubleEndedIterator.html
///
/// For iterating from the front, the [`matches()`] method can be used.
///
Expand Down Expand Up @@ -1240,7 +1240,7 @@ impl str {
/// allows a reverse search and forward/reverse search yields the same
/// elements. This is true for, eg, [`char`] but not for `&str`.
///
/// [`DoubleEndedIterator`]: /std/iter/trait.DoubleEndedIterator.html
/// [`DoubleEndedIterator`]: ::/std/iter/trait.DoubleEndedIterator.html
///
/// If the pattern allows a reverse search but its results might differ
/// from a forward search, the [`rmatch_indices()`] method can be used.
Expand Down Expand Up @@ -1283,7 +1283,7 @@ impl str {
/// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
/// search yields the same elements.
///
/// [`DoubleEndedIterator`]: /std/iter/trait.DoubleEndedIterator.html
/// [`DoubleEndedIterator`]: ::/std/iter/trait.DoubleEndedIterator.html
///
/// For iterating from the front, the [`match_indices()`] method can be used.
///
Expand Down Expand Up @@ -1513,14 +1513,14 @@ impl str {
///
/// `parse()` can parse any type that implements the [`FromStr`] trait.
///
/// [`FromStr`]: /std/str/trait.FromStr.html
/// [`FromStr`]: ::/std/str/trait.FromStr.html
///
/// # Errors
///
/// Will return [`Err`] if it's not possible to parse this string slice into
/// the desired type.
///
/// [`Err`]: /std/str/trait.FromStr.html#associatedtype.Err
/// [`Err`]: ::/std/str/trait.FromStr.html#associatedtype.Err
///
/// # Example
///
Expand Down Expand Up @@ -1559,7 +1559,7 @@ impl str {
/// While doing so, it attempts to find matches of a pattern. If it finds any, it
/// replaces them with the replacement string slice.
///
/// [`String`]: /std/string/struct.String.html
/// [`String`]: ::/std/string/struct.String.html
///
/// # Examples
///
Expand Down Expand Up @@ -1595,7 +1595,7 @@ impl str {
/// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property
/// `Lowercase`.
///
/// [`String`]: /std/string/struct.String.html
/// [`String`]: ::/std/string/struct.String.html
///
/// # Examples
///
Expand Down Expand Up @@ -1671,7 +1671,7 @@ impl str {
/// 'Uppercase' is defined according to the terms of the Unicode Derived Core Property
/// `Uppercase`.
///
/// [`String`]: /std/string/struct.String.html
/// [`String`]: ::/std/string/struct.String.html
///
/// # Examples
///
Expand Down Expand Up @@ -1715,7 +1715,7 @@ impl str {

/// Converts a `Box<str>` into a [`String`] without copying or allocating.
///
/// [`String`]: /std/string/struct.String.html
/// [`String`]: ::/std/string/struct.String.html
///
/// # Examples
///
Expand Down
84 changes: 77 additions & 7 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ use test;
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
pub struct Markdown<'a>(pub &'a str);
/// A unit struct like `Markdown`, that renders the markdown with a
/// A unit struct like `Markdown`, that can expand '::/...' links
/// using the root prefix provided in the second string.
pub struct MarkdownRelative<'a>(pub &'a str, pub &'a str);
/// A unit struct like `MarkdownRelative`, that renders the markdown with a
/// table of contents.
pub struct MarkdownWithToc<'a>(pub &'a str);
pub struct MarkdownWithToc<'a>(pub &'a str, pub &'a str);

const DEF_OUNIT: libc::size_t = 64;
const HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 11;
Expand Down Expand Up @@ -143,9 +146,13 @@ struct html_toc_data {
nesting_level: libc::c_int,
}

struct MyOpaque {
struct MyOpaque<'a> {
dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
*const hoedown_buffer, *const hoedown_renderer_data),
dfltlink: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
*const hoedown_buffer, *const hoedown_buffer,
*const hoedown_renderer_data) -> libc::c_int,
root_path: &'a str,
toc_builder: Option<TocBuilder>,
}

Expand Down Expand Up @@ -219,7 +226,7 @@ thread_local!(pub static PLAYGROUND_KRATE: RefCell<Option<Option<String>>> = {
RefCell::new(None)
});

pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, root_path: &str) -> fmt::Result {
extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer,
lang: *const hoedown_buffer, data: *const hoedown_renderer_data) {
unsafe {
Expand Down Expand Up @@ -349,18 +356,58 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
1
}

// Intercept the default link logic to process mod-relative links starting with '::/'
extern fn link(
ob: *mut hoedown_buffer,
content: *const hoedown_buffer,
link: *const hoedown_buffer,
title: *const hoedown_buffer,
data: *const hoedown_renderer_data,
) -> libc::c_int {

let my_opaque : &MyOpaque = unsafe {
let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
&*((*opaque).opaque as *const MyOpaque)
};

if link.is_null() {
return (my_opaque.dfltlink)(ob, content, link, title, data);
}

let bytes = unsafe { (*link).as_bytes() };
let link_str = str::from_utf8(bytes).unwrap().to_owned();

if !link_str.starts_with("::/") {
return (my_opaque.dfltlink)(ob, content, link, title, data);
}

let new_link = my_opaque.root_path.to_owned() + &link_str[3..];
let new_link = CString::new(new_link).unwrap();

unsafe {
let link_buffer = hoedown_buffer_new(DEF_OUNIT);
hoedown_buffer_puts(link_buffer, new_link.as_ptr());
let result = (my_opaque.dfltlink)(ob, content, link_buffer, title, data);
hoedown_buffer_free(link_buffer);
result
}
}

unsafe {
let ob = hoedown_buffer_new(DEF_OUNIT);
let renderer = hoedown_html_renderer_new(0, 0);
let mut opaque = MyOpaque {
dfltblk: (*renderer).blockcode.unwrap(),
dfltlink: (*renderer).link.unwrap(),
root_path: root_path,
toc_builder: if print_toc {Some(TocBuilder::new())} else {None}
};
(*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
= &mut opaque as *mut _ as *mut libc::c_void;
(*renderer).blockcode = Some(block);
(*renderer).header = Some(header);
(*renderer).codespan = Some(codespan);
(*renderer).link = Some(link);

let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
hoedown_document_render(document, ob, s.as_ptr(),
Expand Down Expand Up @@ -524,14 +571,23 @@ impl<'a> fmt::Display for Markdown<'a> {
let Markdown(md) = *self;
// This is actually common enough to special-case
if md.is_empty() { return Ok(()) }
render(fmt, md, false)
render(fmt, md, false, "")
}
}

impl<'a> fmt::Display for MarkdownRelative<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let MarkdownRelative(md, root_path) = *self;
// This is actually common enough to special-case
if md.is_empty() { return Ok(()) }
render(fmt, md, false, root_path)
}
}

impl<'a> fmt::Display for MarkdownWithToc<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let MarkdownWithToc(md) = *self;
render(fmt, md, true)
let MarkdownWithToc(md, root_path) = *self;
render(fmt, md, true, root_path)
}
}

Expand Down Expand Up @@ -690,4 +746,18 @@ mod tests {
t("# top header", "top header");
t("## header", "header");
}

#[test]
fn test_root_relative_links() {
fn t(input: &str, root: &str, expect: &str) {
let output = format!("{}", MarkdownRelative(input, root));
assert_eq!(output, format!("<p><a href=\"{}\">Link</a></p>\n", expect));
}

t("[Link](::/path/file.html)", "", "path/file.html");
t("[Link](::/path/file.html)", "../", "../path/file.html");
t("[Link](::/path/file.html)", "../../", "../../path/file.html");
t("[Link]\n[Link]: ::/path/file.html", "../", "../path/file.html");
}

}
Loading

0 comments on commit 3c44331

Please sign in to comment.