summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/collect_files.rs56
-rw-r--r--src/generate_html.rs24
2 files changed, 53 insertions, 27 deletions
diff --git a/src/collect_files.rs b/src/collect_files.rs
index 64cfc30..9aa4983 100644
--- a/src/collect_files.rs
+++ b/src/collect_files.rs
@@ -273,27 +273,9 @@ impl Website {
if !path.starts_with('/') {
path = format!("{}{path}", from.parent_url());
}
+ let path = make_url_safe(&collapse_path(&path));
- // Iteratively collapse ".." segments.
- let mut segments: Vec<&str> = path.split('/')
- .filter(|s| !s.is_empty() && *s != ".")
- .collect();
- 'outer: loop {
- for i in 0..(segments.len().saturating_sub(1)) {
- if segments[i] == ".." {
- if i == 0 {
- segments.remove(0);
- } else {
- segments.remove(i-1);
- segments.remove(i-1);
- }
- continue 'outer;
- }
- }
- break;
- }
// Find page with this path in website.
- let path = make_url_safe(&segments.join("/"));
for page in &self.pages {
if page.full_url == path {
let root = from.root();
@@ -310,6 +292,21 @@ impl Website {
return None;
}
+ pub fn has_static(&self, from: &impl LinkFrom, path: &str) -> Option<String> {
+ // Attach parent if not an absolute path.
+ let path = match !path.starts_with('/') {
+ true => collapse_path(&format!("{}{path}", make_url_safe(from.parent_url()))),
+ false => collapse_path(path),
+ };
+ for file in &self.static_files {
+ if file.full_url == path {
+ let root = from.root();
+ return Some(format!("{root}{path}"));
+ }
+ }
+ return None;
+ }
+
pub fn has_image(&self, file_name: &str) -> bool {
let image_path = format!("images/thumb/{file_name}");
self.static_files.iter().any(|s| s.full_url == image_path)
@@ -320,3 +317,24 @@ impl Website {
}
}
+
+fn collapse_path(path: &str) -> String {
+ // Iteratively collapse ".." segments.
+ let mut segments: Vec<&str> = path.split('/')
+ .filter(|s| !s.is_empty() && *s != ".")
+ .collect();
+ 'outer: loop {
+ for i in 0..(segments.len().saturating_sub(1)) {
+ if segments[i] == ".." {
+ if i == 0 {
+ segments.remove(0);
+ } else {
+ segments.remove(i-1);
+ segments.remove(i-1);
+ }
+ continue 'outer;
+ }
+ }
+ return segments.join("/");
+ }
+}
diff --git a/src/generate_html.rs b/src/generate_html.rs
index 6220015..9533410 100644
--- a/src/generate_html.rs
+++ b/src/generate_html.rs
@@ -289,21 +289,29 @@ fn line_to_html(line: &Line, page: &Page, website: &Website) -> String {
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();
- // Strip the protocol from the path when using the path as a label.
- if label.is_empty() {
- label = path.to_string();
+
+ if !path.contains("://") {
+ // Check that the linked static file exists.
+ match website.has_static(page, &path) {
+ Some(resolved_path) => path = resolved_path,
+ None => warn!("Page {:?} contains link to nonexistent static file {path:?}", page.name),
+ }
+ // 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(),
+ };
+ }
+ } else if label.is_empty() {
for protocol in ["mailto://", "http://", "https://"] {
if let Some(stripped) = path.strip_prefix(protocol) {
label = stripped.to_string();
}
}
}
- // Support absolute local paths.
- let path = match path.strip_prefix('/') {
- Some(stripped) => format!("{}{stripped}", page.root()),
- None => path.to_string(),
- };
let label = sanitize_text(&label);
html.push_str(&format!("<a href='{path}' class='external'>{label}</a>"));
}