summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/generate_html.rs122
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.