Skip to content

Commit

Permalink
Refactor adjust_links
Browse files Browse the repository at this point in the history
Signed-off-by: Hollow Man <[email protected]>
  • Loading branch information
HollowMan6 committed Sep 30, 2023
1 parent 96c9a4f commit f225602
Showing 1 changed file with 94 additions and 76 deletions.
170 changes: 94 additions & 76 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,76 @@ fn adjust_links<'a>(
fixed_link.to_string()
}

fn fix<'a>(dest: CowStr<'a>, path: Option<&Path>) -> CowStr<'a> {
fn fix_print_page_link<'a>(
mut normalized_path: String,
redirects: &HashMap<String, String>,
) -> CowStr<'a> {
// Fix redirect links
let (path_no_fragment, fragment) = match normalized_path.split_once('#') {
Some((a, b)) => (a, Some(b)),
None => (normalized_path.as_str(), None),
};
for (original, redirect) in redirects {
if !normalize_path(original.trim_start_matches('/'))
.eq_ignore_ascii_case(&normalized_path)
&& !normalize_path(original.trim_start_matches('/'))
.eq_ignore_ascii_case(&path_no_fragment)
{
continue;
}

let mut unnormalized_path = String::new();
if SCHEME_LINK.is_match(&redirect) {
unnormalized_path = redirect.to_string();
} else {
let base = PathBuf::from(path_no_fragment)
.parent()
.expect("path can't be empty")
.to_str()
.expect("utf-8 paths only")
.to_owned();

let normalized_base = normalize_path(base).trim_matches('/').to_owned();
if !normalized_base.is_empty() {
write!(unnormalized_path, "{}/{}", normalized_base, redirect).unwrap();
} else {
unnormalized_path = redirect.to_string().trim_start_matches('/').to_string();
}
}

// original without anchors, need to append link anchors
if !original.contains("#") {
if let Some(fragment) = fragment {
if !unnormalized_path.contains("#") {
unnormalized_path.push('#');
} else {
unnormalized_path.push('-');
}
unnormalized_path.push_str(fragment);
}
}

if SCHEME_LINK.is_match(&redirect) {
return CowStr::from(unnormalized_path);
} else {
normalized_path = normalize_path(unnormalized_path);
}
break;
}

// Check again to make sure anchors are the html links inside the book.
if normalized_path.starts_with("../") || normalized_path.contains("/../") {
return CowStr::from(normalized_path);
}

let mut fixed_anchor_for_print = String::new();
fixed_anchor_for_print.push_str("#");
fixed_anchor_for_print.push_str(&normalize_path_id(normalized_path));
CowStr::from(fixed_anchor_for_print)
}

/// Fix resource links like img to the correct location.
fn fix_resource_links<'a>(dest: CowStr<'a>, path: Option<&Path>) -> CowStr<'a> {
// Don't modify links with schemes like `https`.
if SCHEME_LINK.is_match(&dest) {
return dest;
Expand All @@ -177,32 +246,36 @@ fn adjust_links<'a>(
CowStr::from(fixed_link)
}

/// Adjust markdown file to correct point in the html file.
fn fix_a_links<'a>(
dest: CowStr<'a>,
path: Option<&Path>,
redirects: &HashMap<String, String>,
) -> CowStr<'a> {
if dest.starts_with('#') {
// Fragment-only link.
if let Some(path) = path {
let mut base = path.display().to_string();
if base.ends_with(".md") {
base.truncate(base.len() - 3);
return match path {
Some(path) => {
let mut base = path.display().to_string();
if base.ends_with(".md") {
base.truncate(base.len() - 3);
}
format!(
"#{}{}",
normalize_path_id(normalize_path(base)),
dest.replace("#", "-")
)
.into()
}
return format!(
"#{}{}",
normalize_path_id(normalize_path(base)),
dest.replace("#", "-")
)
.into();
} else {
return dest;
}
None => dest,
};
}

// Don't modify links with schemes like `https`.
if SCHEME_LINK.is_match(&dest) {
return dest;
}

// This is a relative link, adjust it as necessary.
let mut fixed_link = add_base(String::new(), path);

Expand All @@ -216,70 +289,15 @@ fn adjust_links<'a>(
fixed_link.push_str(&dest);
};

let mut normalized_path = normalize_path(&fixed_link);
let normalized_path = normalize_path(&fixed_link);

// Judge if the html link is inside the book.
if !normalized_path.starts_with("../") && !normalized_path.contains("/../") {
// In `print.html`, print page links would all link to anchors on the print page.
if let Some(_) = path {
// Fix redirect links
let normalized_path_split: Vec<&str> = normalized_path.split('#').collect();
for (original, redirect) in redirects {
if normalize_path(original.trim_start_matches('/'))
.eq_ignore_ascii_case(&normalized_path)
|| normalize_path(original.trim_start_matches('/'))
.eq_ignore_ascii_case(&normalized_path_split[0])
{
let mut unnormalized_path = String::new();
if SCHEME_LINK.is_match(&redirect) {
unnormalized_path = redirect.to_string();
} else {
let base = PathBuf::from(normalized_path_split[0])
.parent()
.expect("path can't be empty")
.to_str()
.expect("utf-8 paths only")
.to_owned();

let normalized_base = normalize_path(base).trim_matches('/').to_owned();
if !normalized_base.is_empty() {
write!(unnormalized_path, "{}/{}", normalized_base, redirect)
.unwrap();
} else {
unnormalized_path =
redirect.to_string().trim_start_matches('/').to_string();
}
}

// original without anchors, need to append link anchors
if !original.contains("#") {
for i in 1..normalized_path_split.len() {
if !unnormalized_path.contains("#") {
unnormalized_path.push('#');
} else {
unnormalized_path.push('-');
}
unnormalized_path.push_str(normalized_path_split[i]);
}
}

if !SCHEME_LINK.is_match(&redirect) {
normalized_path = normalize_path(unnormalized_path);
} else {
return CowStr::from(unnormalized_path);
}
break;
}
}
// Check again to make sure anchors are the html links inside the book.
if normalized_path.starts_with("../") || normalized_path.contains("/../") {
return CowStr::from(normalized_path);
}
let mut fixed_anchor_for_print = String::new();
fixed_anchor_for_print.push_str("#");
fixed_anchor_for_print.push_str(&normalize_path_id(normalized_path));
return CowStr::from(fixed_anchor_for_print);
}
return match path {
Some(_) => fix_print_page_link(normalized_path, redirects),
None => CowStr::from(fixed_link),
};
}
// In normal page rendering, links to anchors on another page.
CowStr::from(fixed_link)
Expand All @@ -305,7 +323,7 @@ fn adjust_links<'a>(

let temp_html = IMG_LINK
.replace_all(&html, |caps: &regex::Captures<'_>| {
let fixed = fix(caps[2].into(), path);
let fixed = fix_resource_links(caps[2].into(), path);
format!("{}{}\"", &caps[1], fixed)
})
.into_owned();
Expand All @@ -326,7 +344,7 @@ fn adjust_links<'a>(
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_resource_links(dest, path), title))
}
Event::Html(html) => Event::Html(fix_html(html, path, redirects)),
_ => event,
Expand Down

0 comments on commit f225602

Please sign in to comment.