add absolute links support
This commit is contained in:
parent
8cdb8d0367
commit
c1a0af3cf6
|
@ -516,6 +516,8 @@ pub struct HtmlConfig {
|
||||||
pub input_404: Option<String>,
|
pub input_404: Option<String>,
|
||||||
/// Absolute url to site, used to emit correct paths for the 404 page, which might be accessed in a deeply nested directory
|
/// Absolute url to site, used to emit correct paths for the 404 page, which might be accessed in a deeply nested directory
|
||||||
pub site_url: Option<String>,
|
pub site_url: Option<String>,
|
||||||
|
/// Prepend the `site_url` in links with absolute path.
|
||||||
|
pub use_site_url_as_root: bool,
|
||||||
/// The DNS subdomain or apex domain at which your book will be hosted. This
|
/// The DNS subdomain or apex domain at which your book will be hosted. This
|
||||||
/// string will be written to a file named CNAME in the root of your site,
|
/// string will be written to a file named CNAME in the root of your site,
|
||||||
/// as required by GitHub Pages (see [*Managing a custom domain for your
|
/// as required by GitHub Pages (see [*Managing a custom domain for your
|
||||||
|
@ -562,6 +564,7 @@ impl Default for HtmlConfig {
|
||||||
edit_url_template: None,
|
edit_url_template: None,
|
||||||
input_404: None,
|
input_404: None,
|
||||||
site_url: None,
|
site_url: None,
|
||||||
|
use_site_url_as_root: false,
|
||||||
cname: None,
|
cname: None,
|
||||||
live_reload_endpoint: None,
|
live_reload_endpoint: None,
|
||||||
redirect: HashMap::new(),
|
redirect: HashMap::new(),
|
||||||
|
|
|
@ -55,10 +55,23 @@ impl HtmlHandlebars {
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = ch.content.clone();
|
let content = ch.content.clone();
|
||||||
let content = utils::render_markdown(&content, ctx.html_config.curly_quotes);
|
let content = if ctx.html_config.use_site_url_as_root {
|
||||||
|
utils::render_markdown_with_path(
|
||||||
|
&content,
|
||||||
|
ctx.html_config.curly_quotes,
|
||||||
|
None,
|
||||||
|
ctx.html_config.site_url.as_ref(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
utils::render_markdown(&content, ctx.html_config.curly_quotes)
|
||||||
|
};
|
||||||
|
|
||||||
let fixed_content =
|
let fixed_content = utils::render_markdown_with_path(
|
||||||
utils::render_markdown_with_path(&ch.content, ctx.html_config.curly_quotes, Some(path));
|
&ch.content,
|
||||||
|
ctx.html_config.curly_quotes,
|
||||||
|
Some(path),
|
||||||
|
None,
|
||||||
|
);
|
||||||
if !ctx.is_index && ctx.html_config.print.page_break {
|
if !ctx.is_index && ctx.html_config.print.page_break {
|
||||||
// Add page break between chapters
|
// Add page break between chapters
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/CSS/break-before and https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-before
|
// See https://developer.mozilla.org/en-US/docs/Web/CSS/break-before and https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-before
|
||||||
|
|
|
@ -96,13 +96,13 @@ pub fn unique_id_from_content(content: &str, id_counter: &mut HashMap<String, us
|
||||||
/// page go to the original location. Normal page rendering sets `path` to
|
/// page go to the original location. Normal page rendering sets `path` to
|
||||||
/// None. Ideally, print page links would link to anchors on the print page,
|
/// None. Ideally, print page links would link to anchors on the print page,
|
||||||
/// but that is very difficult.
|
/// but that is very difficult.
|
||||||
fn adjust_links<'a>(event: Event<'a>, path: Option<&Path>) -> Event<'a> {
|
fn adjust_links<'a>(event: Event<'a>, path: Option<&Path>, abs_url: Option<&String>) -> Event<'a> {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref SCHEME_LINK: Regex = Regex::new(r"^[a-z][a-z0-9+.-]*:").unwrap();
|
static ref SCHEME_LINK: Regex = Regex::new(r"^[a-z][a-z0-9+.-]*:").unwrap();
|
||||||
static ref MD_LINK: Regex = Regex::new(r"(?P<link>.*)\.md(?P<anchor>#.*)?").unwrap();
|
static ref MD_LINK: Regex = Regex::new(r"(?P<link>.*)\.md(?P<anchor>#.*)?").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix<'a>(dest: CowStr<'a>, path: Option<&Path>) -> CowStr<'a> {
|
fn fix<'a>(dest: CowStr<'a>, path: Option<&Path>, abs_url: Option<&String>) -> CowStr<'a> {
|
||||||
if dest.starts_with('#') {
|
if dest.starts_with('#') {
|
||||||
// Fragment-only link.
|
// Fragment-only link.
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
|
@ -139,12 +139,19 @@ fn adjust_links<'a>(event: Event<'a>, path: Option<&Path>) -> Event<'a> {
|
||||||
} else {
|
} else {
|
||||||
fixed_link.push_str(&dest);
|
fixed_link.push_str(&dest);
|
||||||
};
|
};
|
||||||
return CowStr::from(fixed_link);
|
if fixed_link.starts_with('/') {
|
||||||
|
fixed_link = match abs_url {
|
||||||
|
Some(abs_url) => format!("{}{}", abs_url.trim_end_matches('/'), &fixed_link),
|
||||||
|
None => fixed_link,
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
return CowStr::from(format!("{}", fixed_link));
|
||||||
}
|
}
|
||||||
dest
|
dest
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix_html<'a>(html: CowStr<'a>, path: Option<&Path>) -> CowStr<'a> {
|
fn fix_html<'a>(html: CowStr<'a>, path: Option<&Path>, abs_url: Option<&String>) -> CowStr<'a> {
|
||||||
// This is a terrible hack, but should be reasonably reliable. Nobody
|
// This is a terrible hack, but should be reasonably reliable. Nobody
|
||||||
// should ever parse a tag with a regex. However, there isn't anything
|
// should ever parse a tag with a regex. However, there isn't anything
|
||||||
// in Rust that I know of that is suitable for handling partial html
|
// in Rust that I know of that is suitable for handling partial html
|
||||||
|
@ -160,7 +167,7 @@ fn adjust_links<'a>(event: Event<'a>, path: Option<&Path>) -> Event<'a> {
|
||||||
|
|
||||||
HTML_LINK
|
HTML_LINK
|
||||||
.replace_all(&html, |caps: ®ex::Captures<'_>| {
|
.replace_all(&html, |caps: ®ex::Captures<'_>| {
|
||||||
let fixed = fix(caps[2].into(), path);
|
let fixed = fix(caps[2].into(), path, abs_url);
|
||||||
format!("{}{}\"", &caps[1], fixed)
|
format!("{}{}\"", &caps[1], fixed)
|
||||||
})
|
})
|
||||||
.into_owned()
|
.into_owned()
|
||||||
|
@ -169,19 +176,19 @@ fn adjust_links<'a>(event: Event<'a>, path: Option<&Path>) -> Event<'a> {
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::Start(Tag::Link(link_type, dest, title)) => {
|
Event::Start(Tag::Link(link_type, dest, title)) => {
|
||||||
Event::Start(Tag::Link(link_type, fix(dest, path), title))
|
Event::Start(Tag::Link(link_type, fix(dest, path, abs_url), title))
|
||||||
}
|
}
|
||||||
Event::Start(Tag::Image(link_type, dest, title)) => {
|
Event::Start(Tag::Image(link_type, dest, title)) => {
|
||||||
Event::Start(Tag::Image(link_type, fix(dest, path), title))
|
Event::Start(Tag::Image(link_type, fix(dest, path, abs_url), title))
|
||||||
}
|
}
|
||||||
Event::Html(html) => Event::Html(fix_html(html, path)),
|
Event::Html(html) => Event::Html(fix_html(html, path, abs_url)),
|
||||||
_ => event,
|
_ => event,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper around the pulldown-cmark parser for rendering markdown to HTML.
|
/// Wrapper around the pulldown-cmark parser for rendering markdown to HTML.
|
||||||
pub fn render_markdown(text: &str, curly_quotes: bool) -> String {
|
pub fn render_markdown(text: &str, curly_quotes: bool) -> String {
|
||||||
render_markdown_with_path(text, curly_quotes, None)
|
render_markdown_with_path(text, curly_quotes, None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_cmark_parser(text: &str, curly_quotes: bool) -> Parser<'_, '_> {
|
pub fn new_cmark_parser(text: &str, curly_quotes: bool) -> Parser<'_, '_> {
|
||||||
|
@ -196,12 +203,17 @@ pub fn new_cmark_parser(text: &str, curly_quotes: bool) -> Parser<'_, '_> {
|
||||||
Parser::new_ext(text, opts)
|
Parser::new_ext(text, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_markdown_with_path(text: &str, curly_quotes: bool, path: Option<&Path>) -> String {
|
pub fn render_markdown_with_path(
|
||||||
|
text: &str,
|
||||||
|
curly_quotes: bool,
|
||||||
|
path: Option<&Path>,
|
||||||
|
abs_url: Option<&String>,
|
||||||
|
) -> String {
|
||||||
let mut s = String::with_capacity(text.len() * 3 / 2);
|
let mut s = String::with_capacity(text.len() * 3 / 2);
|
||||||
let p = new_cmark_parser(text, curly_quotes);
|
let p = new_cmark_parser(text, curly_quotes);
|
||||||
let events = p
|
let events = p
|
||||||
.map(clean_codeblock_headers)
|
.map(clean_codeblock_headers)
|
||||||
.map(|event| adjust_links(event, path))
|
.map(|event| adjust_links(event, path, abs_url))
|
||||||
.flat_map(|event| {
|
.flat_map(|event| {
|
||||||
let (a, b) = wrap_tables(event);
|
let (a, b) = wrap_tables(event);
|
||||||
a.into_iter().chain(b)
|
a.into_iter().chain(b)
|
||||||
|
|
Loading…
Reference in New Issue