From a98c87cdfca4ba228ccf8ebbe460a95f5869e972 Mon Sep 17 00:00:00 2001 From: jutty Date: Mon, 5 Jan 2026 23:12:10 -0300 Subject: [PATCH] Implement spaced anchor redirection --- docs/development/roadmap.md | 4 ++-- src/router/handlers/graph.rs | 9 +++++---- src/types.rs | 19 ++++++++++++------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/development/roadmap.md b/docs/development/roadmap.md index f77d178..d5e1711 100644 --- a/docs/development/roadmap.md +++ b/docs/development/roadmap.md @@ -1,6 +1,6 @@ # Roadmap -- [x] Add tests +- [x] Setup tests - [ ] Improve content syntax parser coverage - [x] Redirects - [ ] Strip/render some syntax in Tree text preview @@ -28,7 +28,7 @@ - [x] Ignore trailing punctuation - [ ] Conjugation anchors (|will|ed -> will) - [ ] Configurable suffixes - - [ ] Spaced node anchor (|red fox| -> redfox -> RedFox) + - [x] Spaced node anchor (|red fox| -> redfox -> RedFox) - [ ] Automatic connections from anchors - [ ] `#` syntax for header ID anchors - [ ] Connection kinds diff --git a/src/router/handlers/graph.rs b/src/router/handlers/graph.rs index 0fadfa2..39ae2a8 100644 --- a/src/router/handlers/graph.rs +++ b/src/router/handlers/graph.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use axum::response::IntoResponse as _; use axum::{body::Body, extract::Path, http::Response, response::Redirect}; @@ -8,7 +9,8 @@ use crate::{syntax::serial::populate_graph, router::handlers, types::Node}; pub async fn node(Path(id): Path) -> Response { let graph = populate_graph(); let empty_node = Node::new(Some(format!("Could not find node ID {id}."))); - let node = graph.find_node(&id).unwrap_or(empty_node.clone()); + let (node_match, exact) = graph.find_node(&id); + let node = node_match.unwrap_or(empty_node.clone()); if !node.redirect.is_empty() { return Redirect::permanent( @@ -17,9 +19,8 @@ pub async fn node(Path(id): Path) -> Response { .into_response(); } - if !graph.nodes.contains_key(&id) - && graph.lowercase_keymap.contains_key(&id) - { + if !exact { + log!("Redirecting non-exact match to {}", node.id); return Redirect::permanent(format!("/node/{}", node.id).as_str()) .into_response(); } diff --git a/src/types.rs b/src/types.rs index 0b55753..20d5d0d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -130,13 +130,18 @@ impl Graph { } } - pub fn find_node(&self, query: &str) -> Option { - self.nodes.get(query).cloned().or_else(|| { - self.lowercase_keymap - .get(query) - .and_then(|lower_key| self.nodes.get(lower_key)) - .cloned() - }) + pub fn find_node(&self, query: &str) -> (Option, bool) { + let collapsed_query = query.trim().replace(" ", ""); + + if let Some(exact_match) = self.nodes.get(query) { + (Some(exact_match.clone()), true) + } else if let Some(lower_key) = + self.lowercase_keymap.get(&collapsed_query) + { + (self.nodes.get(lower_key).cloned(), false) + } else { + (None, false) + } } pub fn get_root(&self) -> Option {