diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs
index f12fd16875..b5ef228d34 100644
--- a/src/renderer/html_handlebars/hbs_renderer.rs
+++ b/src/renderer/html_handlebars/hbs_renderer.rs
@@ -33,7 +33,11 @@ impl HtmlHandlebars {
if let BookItem::Chapter(ref ch) = *item {
let content = ch.content.clone();
let content = utils::render_markdown(&content, ctx.html_config.curly_quotes);
- print_content.push_str(&content);
+
+ let string_path = ch.path.parent().unwrap().display().to_string();
+
+ let fixed_content = utils::render_markdown_with_base(&ch.content, ctx.html_config.curly_quotes, &string_path);
+ print_content.push_str(&fixed_content);
// Update the context with data for this file
let path = ch
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 31abe98cae..df997d5eb3 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -66,15 +66,21 @@ pub fn id_from_content(content: &str) -> String {
normalize_id(trimmed)
}
-fn adjust_links(event: Event) -> Event {
+fn adjust_links<'a>(event: Event<'a>, with_base: &str) -> Event<'a> {
lazy_static! {
static ref HTTP_LINK: Regex = Regex::new("^https?://").unwrap();
- static ref MD_LINK: Regex = Regex::new("(?P.*).md(?P#.*)?").unwrap();
+ static ref MD_LINK: Regex = Regex::new(r"(?P.*)\.md(?P#.*)?").unwrap();
}
match event {
Event::Start(Tag::Link(dest, title)) => {
if !HTTP_LINK.is_match(&dest) {
+ let dest = if !with_base.is_empty() {
+ format!("{}/{}", with_base, dest)
+ } else {
+ dest.clone().into_owned()
+ };
+
if let Some(caps) = MD_LINK.captures(&dest) {
let mut html_link = [&caps["link"], ".html"].concat();
@@ -94,6 +100,10 @@ fn adjust_links(event: Event) -> Event {
/// Wrapper around the pulldown-cmark parser for rendering markdown to HTML.
pub fn render_markdown(text: &str, curly_quotes: bool) -> String {
+ render_markdown_with_base(text, curly_quotes, "")
+}
+
+pub fn render_markdown_with_base(text: &str, curly_quotes: bool, base: &str) -> String {
let mut s = String::with_capacity(text.len() * 3 / 2);
let mut opts = Options::empty();
@@ -104,7 +114,7 @@ pub fn render_markdown(text: &str, curly_quotes: bool) -> String {
let mut converter = EventQuoteConverter::new(curly_quotes);
let events = p
.map(clean_codeblock_headers)
- .map(adjust_links)
+ .map(|event| adjust_links(event, base))
.map(|event| converter.convert(event));
html::push_html(&mut s, events);
@@ -220,6 +230,12 @@ mod tests {
render_markdown("[example_anchor](example.md#anchor)", false),
"example_anchor
\n"
);
+
+ // this anchor contains 'md' inside of it
+ assert_eq!(
+ render_markdown("[phantom data](foo.html#phantomdata)", false),
+ "phantom data
\n"
+ );
}
#[test]
diff --git a/tests/dummy_book/src/SUMMARY.md b/tests/dummy_book/src/SUMMARY.md
index 0536e5c297..ee2426e4a8 100644
--- a/tests/dummy_book/src/SUMMARY.md
+++ b/tests/dummy_book/src/SUMMARY.md
@@ -8,6 +8,7 @@
- [Includes](first/includes.md)
- [Recursive](first/recursive.md)
- [Second Chapter](second.md)
+ - [Nested Chapter](second/nested.md)
---
diff --git a/tests/dummy_book/src/second/nested.md b/tests/dummy_book/src/second/nested.md
new file mode 100644
index 0000000000..c3eb3c8fbb
--- /dev/null
+++ b/tests/dummy_book/src/second/nested.md
@@ -0,0 +1,4 @@
+# Testing relative links for the print page
+
+When we link to [the first section](../first/nested.md), it should work on
+both the print page and the non-print page.
\ No newline at end of file
diff --git a/tests/rendered_output.rs b/tests/rendered_output.rs
index 44aed62b0d..b7777ee7c5 100644
--- a/tests/rendered_output.rs
+++ b/tests/rendered_output.rs
@@ -31,7 +31,7 @@ const TOC_TOP_LEVEL: &[&'static str] = &[
"Introduction",
];
const TOC_SECOND_LEVEL: &[&'static str] =
- &["1.1. Nested Chapter", "1.2. Includes", "1.3. Recursive"];
+ &["1.1. Nested Chapter", "1.2. Includes", "2.1. Nested Chapter", "1.3. Recursive"];
/// Make sure you can load the dummy book and build it without panicking.
#[test]
@@ -109,6 +109,20 @@ fn check_correct_cross_links_in_nested_dir() {
);
}
+#[test]
+fn check_correct_relative_links_in_print_page() {
+ let temp = DummyBook::new().build().unwrap();
+ let md = MDBook::load(temp.path()).unwrap();
+ md.build().unwrap();
+
+ let first = temp.path().join("book");
+
+ assert_contains_strings(
+ first.join("print.html"),
+ &[r##"the first section,"##],
+ );
+}
+
#[test]
fn rendered_code_has_playpen_stuff() {
let temp = DummyBook::new().build().unwrap();
@@ -443,7 +457,7 @@ mod search {
assert_eq!(docs[&some_section]["body"], "");
assert_eq!(
docs[&summary]["body"],
- "Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Second Chapter Conclusion"
+ "Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Second Chapter Nested Chapter Conclusion"
);
assert_eq!(docs[&summary]["breadcrumbs"], "First Chapter » Summary");
assert_eq!(docs[&conclusion]["body"], "I put <HTML> in here!");
diff --git a/tests/searchindex_fixture.json b/tests/searchindex_fixture.json
index 330bc648a5..78a3915368 100644
--- a/tests/searchindex_fixture.json
+++ b/tests/searchindex_fixture.json
@@ -9,6 +9,7 @@
"first/includes.html#includes",
"first/includes.html#summary",
"second.html#second-chapter",
+ "second/nested.html#testing-relative-links-for-the-print-page",
"conclusion.html#conclusion"
],
"index": {
@@ -24,6 +25,11 @@
"breadcrumbs": 1,
"title": 1
},
+ "10": {
+ "body": 3,
+ "breadcrumbs": 1,
+ "title": 1
+ },
"2": {
"body": 2,
"breadcrumbs": 2,
@@ -50,7 +56,7 @@
"title": 1
},
"7": {
- "body": 12,
+ "body": 14,
"breadcrumbs": 3,
"title": 1
},
@@ -60,9 +66,9 @@
"title": 2
},
"9": {
- "body": 3,
- "breadcrumbs": 1,
- "title": 1
+ "body": 10,
+ "breadcrumbs": 7,
+ "title": 5
}
},
"docs": {
@@ -78,6 +84,12 @@
"id": "1",
"title": "Introduction"
},
+ "10": {
+ "body": "I put <HTML> in here!",
+ "breadcrumbs": "Conclusion",
+ "id": "10",
+ "title": "Conclusion"
+ },
"2": {
"body": "more text.",
"breadcrumbs": "First Chapter",
@@ -109,7 +121,7 @@
"title": "Includes"
},
"7": {
- "body": "Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Second Chapter Conclusion",
+ "body": "Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Second Chapter Nested Chapter Conclusion",
"breadcrumbs": "First Chapter » Summary",
"id": "7",
"title": "Summary"
@@ -121,13 +133,13 @@
"title": "Second Chapter"
},
"9": {
- "body": "I put <HTML> in here!",
- "breadcrumbs": "Conclusion",
+ "body": "When we link to the first section , it should work on both the print page and the non-print page.",
+ "breadcrumbs": "Second Chapter » Testing relative links for the print page",
"id": "9",
- "title": "Conclusion"
+ "title": "Testing relative links for the print page"
}
},
- "length": 10,
+ "length": 11,
"save": true
},
"fields": [
@@ -206,6 +218,18 @@
}
}
}
+ },
+ "t": {
+ "df": 0,
+ "docs": {},
+ "h": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
}
}
},
@@ -251,7 +275,7 @@
"tf": 1.0
},
"7": {
- "tf": 1.7320508075688773
+ "tf": 2.0
},
"8": {
"tf": 1.0
@@ -296,10 +320,10 @@
"s": {
"df": 2,
"docs": {
- "7": {
+ "10": {
"tf": 1.0
},
- "9": {
+ "7": {
"tf": 1.0
}
}
@@ -420,13 +444,16 @@
"df": 0,
"docs": {},
"t": {
- "df": 2,
+ "df": 3,
"docs": {
"2": {
"tf": 1.0
},
"7": {
"tf": 1.0
+ },
+ "9": {
+ "tf": 1.0
}
}
}
@@ -485,7 +512,7 @@
"0": {
"tf": 1.0
},
- "9": {
+ "10": {
"tf": 1.0
}
}
@@ -683,6 +710,14 @@
"tf": 1.0
}
}
+ },
+ "k": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.4142135623730951
+ }
+ }
}
}
},
@@ -709,7 +744,7 @@
"t": {
"df": 1,
"docs": {
- "9": {
+ "10": {
"tf": 1.0
}
}
@@ -791,14 +826,42 @@
"tf": 1.0
},
"7": {
- "tf": 1.0
+ "tf": 1.4142135623730951
}
}
}
}
+ },
+ "o": {
+ "df": 0,
+ "docs": {},
+ "n": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
}
},
"p": {
+ "a": {
+ "df": 0,
+ "docs": {},
+ "g": {
+ "df": 0,
+ "docs": {},
+ "e": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.7320508075688772
+ }
+ }
+ }
+ }
+ },
"df": 0,
"docs": {},
"r": {
@@ -871,8 +934,12 @@
"df": 0,
"docs": {},
"t": {
- "df": 0,
- "docs": {},
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.7320508075688772
+ }
+ },
"l": {
"df": 0,
"docs": {},
@@ -935,7 +1002,7 @@
"t": {
"df": 1,
"docs": {
- "9": {
+ "10": {
"tf": 1.0
}
}
@@ -967,7 +1034,15 @@
}
},
"df": 0,
- "docs": {}
+ "docs": {},
+ "l": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
},
"u": {
"df": 0,
@@ -1050,13 +1125,16 @@
"df": 0,
"docs": {},
"n": {
- "df": 2,
+ "df": 3,
"docs": {
"3": {
"tf": 1.0
},
"5": {
"tf": 1.0
+ },
+ "9": {
+ "tf": 1.0
}
}
}
@@ -1170,8 +1248,12 @@
"df": 0,
"docs": {}
},
- "df": 0,
- "docs": {}
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
}
},
"x": {
@@ -1200,6 +1282,14 @@
"r": {
"df": 0,
"docs": {},
+ "k": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ },
"l": {
"d": {
"df": 1,
@@ -1280,13 +1370,25 @@
"df": 2,
"docs": {
"0": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
},
"7": {
"tf": 1.0
}
}
}
+ },
+ "t": {
+ "df": 0,
+ "docs": {},
+ "h": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
}
}
},
@@ -1323,13 +1425,13 @@
"df": 0,
"docs": {},
"r": {
- "df": 6,
+ "df": 7,
"docs": {
"2": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
},
"4": {
- "tf": 1.7320508075688773
+ "tf": 1.7320508075688772
},
"5": {
"tf": 1.0
@@ -1338,10 +1440,13 @@
"tf": 1.0
},
"7": {
- "tf": 2.0
+ "tf": 2.23606797749979
},
"8": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
+ },
+ "9": {
+ "tf": 1.0
}
}
}
@@ -1383,11 +1488,11 @@
"s": {
"df": 2,
"docs": {
+ "10": {
+ "tf": 1.4142135623730951
+ },
"7": {
"tf": 1.0
- },
- "9": {
- "tf": 1.4142135623730952
}
}
}
@@ -1419,7 +1524,7 @@
"df": 2,
"docs": {
"0": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
},
"7": {
"tf": 1.0
@@ -1507,10 +1612,10 @@
"df": 0,
"docs": {},
"t": {
- "df": 5,
+ "df": 6,
"docs": {
"2": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
},
"4": {
"tf": 1.0
@@ -1522,7 +1627,10 @@
"tf": 1.0
},
"7": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
+ },
+ "9": {
+ "tf": 1.0
}
}
}
@@ -1581,7 +1689,7 @@
"0": {
"tf": 1.0
},
- "9": {
+ "10": {
"tf": 1.0
}
}
@@ -1636,7 +1744,7 @@
"df": 2,
"docs": {
"6": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
},
"7": {
"tf": 1.0
@@ -1728,7 +1836,7 @@
"df": 2,
"docs": {
"1": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
},
"7": {
"tf": 1.0
@@ -1779,6 +1887,14 @@
"tf": 1.0
}
}
+ },
+ "k": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.7320508075688772
+ }
+ }
}
}
},
@@ -1805,7 +1921,7 @@
"t": {
"df": 1,
"docs": {
- "9": {
+ "10": {
"tf": 1.0
}
}
@@ -1884,17 +2000,45 @@
"df": 2,
"docs": {
"4": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
},
"7": {
- "tf": 1.0
+ "tf": 1.4142135623730951
}
}
}
}
+ },
+ "o": {
+ "df": 0,
+ "docs": {},
+ "n": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
}
},
"p": {
+ "a": {
+ "df": 0,
+ "docs": {},
+ "g": {
+ "df": 0,
+ "docs": {},
+ "e": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 2.0
+ }
+ }
+ }
+ }
+ },
"df": 0,
"docs": {},
"r": {
@@ -1967,8 +2111,12 @@
"df": 0,
"docs": {},
"t": {
- "df": 0,
- "docs": {},
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 2.0
+ }
+ },
"l": {
"df": 0,
"docs": {},
@@ -2031,7 +2179,7 @@
"t": {
"df": 1,
"docs": {
- "9": {
+ "10": {
"tf": 1.0
}
}
@@ -2063,7 +2211,15 @@
}
},
"df": 0,
- "docs": {}
+ "docs": {},
+ "l": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.4142135623730951
+ }
+ }
+ }
},
"u": {
"df": 0,
@@ -2122,13 +2278,16 @@
"docs": {},
"n": {
"d": {
- "df": 2,
+ "df": 3,
"docs": {
"7": {
"tf": 1.0
},
"8": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
+ },
+ "9": {
+ "tf": 1.0
}
}
},
@@ -2146,13 +2305,16 @@
"df": 0,
"docs": {},
"n": {
- "df": 2,
+ "df": 3,
"docs": {
"3": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
},
"5": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
+ },
+ "9": {
+ "tf": 1.0
}
}
}
@@ -2216,7 +2378,7 @@
"df": 1,
"docs": {
"7": {
- "tf": 1.4142135623730952
+ "tf": 1.4142135623730951
}
}
}
@@ -2266,8 +2428,12 @@
"df": 0,
"docs": {}
},
- "df": 0,
- "docs": {}
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.4142135623730951
+ }
+ }
}
},
"x": {
@@ -2296,6 +2462,14 @@
"r": {
"df": 0,
"docs": {},
+ "k": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ },
"l": {
"d": {
"df": 1,
@@ -2388,7 +2562,7 @@
"s": {
"df": 1,
"docs": {
- "9": {
+ "10": {
"tf": 1.0
}
}
@@ -2511,6 +2685,26 @@
}
}
},
+ "l": {
+ "df": 0,
+ "docs": {},
+ "i": {
+ "df": 0,
+ "docs": {},
+ "n": {
+ "df": 0,
+ "docs": {},
+ "k": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
+ }
+ }
+ },
"n": {
"df": 0,
"docs": {},
@@ -2531,6 +2725,62 @@
}
}
},
+ "p": {
+ "a": {
+ "df": 0,
+ "docs": {},
+ "g": {
+ "df": 0,
+ "docs": {},
+ "e": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
+ }
+ },
+ "df": 0,
+ "docs": {},
+ "r": {
+ "df": 0,
+ "docs": {},
+ "i": {
+ "df": 0,
+ "docs": {},
+ "n": {
+ "df": 0,
+ "docs": {},
+ "t": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r": {
+ "df": 0,
+ "docs": {},
+ "e": {
+ "df": 0,
+ "docs": {},
+ "l": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
+ }
+ },
"s": {
"df": 0,
"docs": {},
@@ -2609,6 +2859,26 @@
}
}
}
+ },
+ "t": {
+ "df": 0,
+ "docs": {},
+ "e": {
+ "df": 0,
+ "docs": {},
+ "s": {
+ "df": 0,
+ "docs": {},
+ "t": {
+ "df": 1,
+ "docs": {
+ "9": {
+ "tf": 1.0
+ }
+ }
+ }
+ }
+ }
}
}
}