diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/generate_html.rs | 122 |
1 files changed, 69 insertions, 53 deletions
diff --git a/src/generate_html.rs b/src/generate_html.rs index 8490379..f63614b 100644 --- a/src/generate_html.rs +++ b/src/generate_html.rs @@ -265,7 +265,6 @@ pub fn document_to_html(document: &MarkdownDocument, page: &Page, website: &Webs fn line_to_html(line: &Line, page: &Page, website: &Website) -> String { - let from = &page.name; let mut html = String::new(); for line_element in &line.tokens { match line_element { @@ -280,61 +279,12 @@ fn line_to_html(line: &Line, page: &Page, website: &Website) -> String { Token::Math(text) => { let text = &sanitize_text(text, false); html.push_str(&format!("<span class='math'>{text}</span>")) } Token::InternalLink(name) => { - let (class, label, path) = match name.split_once('#') { - Some(("", heading)) => ("heading", heading, format!("#{}", strip_appendix(heading))), - Some((page, heading)) => ("page", heading, format!("{page}.html#{}", strip_appendix(heading))), - _ => ("page", name.as_str(), format!("{name}.html")), - }; - let mut path = make_url_safe(&path); - let label = match label.rsplit_once('/') { - Some((_, label)) => sanitize_text(label.trim(), true), - None => sanitize_text(label.trim(), true), - }; - // Check that the linked internal page exists. - if class == "page" { - match website.has_page(page, &path, "html") { - Some(resolved) => path = resolved, - None => warn!("Page {from:?} contains link to nonexistent page {path:?}"), - } - } - // Check that the heading exists. - if class == "heading" { - let heading = path.strip_prefix('#').unwrap(); - if !page.headings.iter().any(|h| h.url == heading) { - warn!("Page {from:?} contains link to nonexistent internal heading {heading:?}"); - } - } + let ParsedLink { path, class, label } = parse_internal_link(name, page, website); html.push_str(&format!("<a href='{path}' class='{class}'>{label}</a>")) } Token::ExternalLink { label, path } => { - let mut path = path.to_owned(); - let mut label = label.to_string(); - let mut is_internal = true; - for protocol in ["mailto:", "http://", "https://"] { - if let Some(stripped) = path.strip_prefix(protocol) { - is_internal = false; - if label.is_empty() { - label = stripped.to_string(); - } - break; - } - } - if is_internal { - // Check that the linked static file exists. - match website.has_static(page, &path) { - Some(resolved) => path = resolved, - None => warn!("Page {from:?} contains link to nonexistent static file {path:?}"), - } - // Take the file name as the label if the link is unlabeled. - if label.is_empty() { - label = match path.rsplit_once('/') { - Some((_, file)) => file.to_string(), - None => path.clone(), - }; - } - } - let label = sanitize_text(&label, true); - html.push_str(&format!("<a href='{path}' class='external'>{label}</a>")); + let ParsedLink { path, class, label } = parse_external_link(label, path, page, website); + html.push_str(&format!("<a href='{path}' class='{class}'>{label}</a>")); } } } @@ -343,6 +293,72 @@ fn line_to_html(line: &Line, page: &Page, website: &Website) -> String { +struct ParsedLink { + pub path: String, + pub label: String, + pub class: &'static str, +} + +fn parse_internal_link(name: &str, page: &Page, website: &Website) -> ParsedLink { + let from = &page.name; + let (class, label, path) = match name.split_once('#') { + Some(("", heading)) => ("heading", heading, format!("#{}", strip_appendix(heading))), + Some((page, heading)) => ("page", heading, format!("{page}.html#{}", strip_appendix(heading))), + _ => ("page", name, format!("{name}.html")), + }; + let mut path = make_url_safe(&path); + let label = match label.rsplit_once('/') { + Some((_, label)) => sanitize_text(label.trim(), true), + None => sanitize_text(label.trim(), true), + }; + // Check that the linked internal page exists. + if class == "page" { + match website.has_page(page, &path, "html") { + Some(resolved) => path = resolved, + None => warn!("Page {from:?} contains link to nonexistent page {path:?}"), + } + } + // Check that the heading exists. + if class == "heading" { + let heading = path.strip_prefix('#').unwrap(); + if !page.headings.iter().any(|h| h.url == heading) { + warn!("Page {from:?} contains link to nonexistent internal heading {heading:?}"); + } + } + ParsedLink { path, class, label } +} + +fn parse_external_link(label: &str, path: &str, page: &Page, website: &Website) -> ParsedLink { + let from = &page.name; + let mut path = path.to_owned(); + let mut label = label.to_string(); + let mut is_internal = true; + for protocol in ["mailto:", "http://", "https://"] { + if let Some(stripped) = path.strip_prefix(protocol) { + is_internal = false; + if label.is_empty() { + label = stripped.to_string(); + } + break; + } + } + if is_internal { + // Check that the linked static file exists. + match website.has_static(page, &path) { + Some(resolved) => path = resolved, + None => warn!("Page {from:?} contains link to nonexistent static file {path:?}"), + } + // Take the file name as the label if the link is unlabeled. + if label.is_empty() { + label = match path.rsplit_once('/') { + Some((_, file)) => file.to_string(), + None => path.clone(), + }; + } + } + let label = sanitize_text(&label, true); + ParsedLink { path, class: "external", label } +} /// Replace each HTML-reserved character with an HTML-escaped character. |