From c3718dbd1449986dea0e9bfc7e427ce2b4444c97 Mon Sep 17 00:00:00 2001 From: Hollow Man Date: Mon, 14 Nov 2022 19:55:05 +0200 Subject: [PATCH] Refactor adjust_links Signed-off-by: Hollow Man --- src/utils/mod.rs | 170 ++++++++++++++++++++++++++--------------------- 1 file changed, 94 insertions(+), 76 deletions(-) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 22d02ddd27..b122e506b8 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -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, + ) -> 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; @@ -177,6 +246,7 @@ 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>, @@ -184,25 +254,28 @@ fn adjust_links<'a>( ) -> 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); @@ -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) @@ -305,7 +323,7 @@ fn adjust_links<'a>( let temp_html = IMG_LINK .replace_all(&html, |caps: ®ex::Captures<'_>| { - let fixed = fix(caps[2].into(), path); + let fixed = fix_resource_links(caps[2].into(), path); format!("{}{}\"", &caps[1], fixed) }) .into_owned(); @@ -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,